drivers/media/platform/amd/isp4/isp4.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/amd/isp4/isp4.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/amd/isp4/isp4.c
Extension
.c
Size
6848 bytes
Lines
241
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (intr_status & isp4_irq[i].status_mask) {
			intr_ack |= isp4_irq[i].ack_mask;
			intr_en |= isp4_irq[i].en_mask;
			seen |= BIT(i);
		}
	}

	/*
	 * Disable the ISP_SYS interrupts that fired. Must be done before waking
	 * the response threads, since they re-enable interrupts when finished.
	 * The lock synchronizes RMW of INT0_EN with isp4_enable_interrupt().
	 */
	spin_lock(&isp_subdev->irq_lock);
	intr_en = isp4hw_rreg(isp_subdev->mmio, ISP_SYS_INT0_EN) & ~intr_en;
	isp4hw_wreg(isp_subdev->mmio, ISP_SYS_INT0_EN, intr_en);
	spin_unlock(&isp_subdev->irq_lock);

	/*
	 * Clear the ISP_SYS interrupts. This must be done after the interrupts
	 * are disabled, so that ISP FW won't flag any new interrupts on these
	 * streams, and thus we don't need to clear interrupts again before
	 * re-enabling them in the response thread.
	 */
	isp4hw_wreg(isp_subdev->mmio, ISP_SYS_INT0_ACK, intr_ack);

	/*
	 * The operation `(seen >> i) << i` is logically equivalent to
	 * `seen &= ~BIT(i)`, with fewer instructions after compilation.
	 */
	for (int i; (i = ffs(seen)); seen = (seen >> i) << i)
		isp4_wake_up_resp_thread(isp_subdev, i - 1);

	return IRQ_HANDLED;
}

static int isp4_capture_probe(struct platform_device *pdev)
{
	int irq[ISP4SD_MAX_FW_RESP_STREAM_NUM];
	struct device *dev = &pdev->dev;
	struct isp4_subdev *isp_subdev;
	struct isp4_device *isp_dev;
	int ret;

	isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL);
	if (!isp_dev)
		return -ENOMEM;

	dev->init_name = ISP4_DRV_NAME;

	isp_subdev = &isp_dev->isp_subdev;
	isp_subdev->mmio = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(isp_subdev->mmio))
		return dev_err_probe(dev, PTR_ERR(isp_subdev->mmio),
				     "isp ioremap fail\n");

	for (size_t i = 0; i < ARRAY_SIZE(isp4_irq); i++) {
		irq[i] = platform_get_irq(pdev, isp4_irq[i].rb_int_num);
		if (irq[i] < 0)
			return dev_err_probe(dev, irq[i],
					     "fail to get irq %d\n",
					     isp4_irq[i].rb_int_num);

		ret = devm_request_irq(dev, irq[i], isp4_irq_handler,
				       IRQF_NO_AUTOEN, isp4_irq[i].name,
				       isp_subdev);
		if (ret)
			return dev_err_probe(dev, ret, "fail to req irq %d\n",
					     irq[i]);
	}

	isp_dev->v4l2_dev.mdev = &isp_dev->mdev;

	strscpy(isp_dev->mdev.model, "amd_isp41_mdev",
		sizeof(isp_dev->mdev.model));
	isp_dev->mdev.dev = dev;
	media_device_init(&isp_dev->mdev);

	snprintf(isp_dev->v4l2_dev.name, sizeof(isp_dev->v4l2_dev.name),
		 "AMD-V4L2-ROOT");
	ret = v4l2_device_register(dev, &isp_dev->v4l2_dev);
	if (ret) {
		dev_err_probe(dev, ret, "fail register v4l2 device\n");
		goto err_clean_media;
	}

	pm_runtime_set_suspended(dev);
	pm_runtime_enable(dev);
	spin_lock_init(&isp_subdev->irq_lock);
	ret = isp4sd_init(&isp_dev->isp_subdev, &isp_dev->v4l2_dev, irq);
	if (ret) {

Annotation

Implementation Notes