drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
Extension
.c
Size
15144 bytes
Lines
592
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

struct mxc_isi_async_subdev {
	struct v4l2_async_connection asd;
	unsigned int port;
};

static inline struct mxc_isi_async_subdev *
asd_to_mxc_isi_async_subdev(struct v4l2_async_connection *asd)
{
	return container_of(asd, struct mxc_isi_async_subdev, asd);
};

static inline struct mxc_isi_dev *
notifier_to_mxc_isi_dev(struct v4l2_async_notifier *n)
{
	return container_of(n, struct mxc_isi_dev, notifier);
};

static int mxc_isi_async_notifier_bound(struct v4l2_async_notifier *notifier,
					struct v4l2_subdev *sd,
					struct v4l2_async_connection *asc)
{
	const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
				      | MEDIA_LNK_FL_ENABLED;
	struct mxc_isi_dev *isi = notifier_to_mxc_isi_dev(notifier);
	struct mxc_isi_async_subdev *masd = asd_to_mxc_isi_async_subdev(asc);
	struct media_pad *pad = &isi->crossbar.pads[masd->port];
	struct device_link *link;

	dev_dbg(isi->dev, "Bound subdev %s to crossbar input %u\n", sd->name,
		masd->port);

	/*
	 * Enforce suspend/resume ordering between the source (supplier) and
	 * the ISI (consumer). The source will be suspended before and resume
	 * after the ISI.
	 */
	link = device_link_add(isi->dev, sd->dev, DL_FLAG_STATELESS);
	if (!link) {
		dev_err(isi->dev,
			"Failed to create device link to source %s\n", sd->name);
		return -EINVAL;
	}

	return v4l2_create_fwnode_links_to_pad(sd, pad, link_flags);
}

static int mxc_isi_async_notifier_complete(struct v4l2_async_notifier *notifier)
{
	struct mxc_isi_dev *isi = notifier_to_mxc_isi_dev(notifier);
	int ret;

	dev_dbg(isi->dev, "All subdevs bound\n");

	ret = v4l2_device_register_subdev_nodes(&isi->v4l2_dev);
	if (ret < 0) {
		dev_err(isi->dev,
			"Failed to register subdev nodes: %d\n", ret);
		return ret;
	}

	return media_device_register(&isi->media_dev);
}

static const struct v4l2_async_notifier_operations mxc_isi_async_notifier_ops = {
	.bound = mxc_isi_async_notifier_bound,
	.complete = mxc_isi_async_notifier_complete,
};

static int mxc_isi_pipe_register(struct mxc_isi_pipe *pipe)
{
	int ret;

	ret = v4l2_device_register_subdev(&pipe->isi->v4l2_dev, &pipe->sd);
	if (ret < 0)
		return ret;

	return mxc_isi_video_register(pipe, &pipe->isi->v4l2_dev);
}

static void mxc_isi_pipe_unregister(struct mxc_isi_pipe *pipe)
{
	mxc_isi_video_unregister(pipe);
}

static int mxc_isi_v4l2_init(struct mxc_isi_dev *isi)
{
	struct fwnode_handle *node = dev_fwnode(isi->dev);
	struct media_device *media_dev = &isi->media_dev;
	struct v4l2_device *v4l2_dev = &isi->v4l2_dev;
	unsigned int i;

Annotation

Implementation Notes