drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
Extension
.c
Size
23080 bytes
Lines
873
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 (endpoint->bus_type == bus_types[i]) {
				valid = true;
				break;
			}
		}

		if (!valid) {
			dev_err(dev, "unsupported bus type for port %d\n",
				port);
			ret = -EINVAL;
			goto complete;
		}
	}

	bridge_async_subdev =
		v4l2_async_nf_add_fwnode_remote(notifier, handle,
						struct
						sun6i_csi_bridge_async_subdev);
	if (IS_ERR(bridge_async_subdev)) {
		ret = PTR_ERR(bridge_async_subdev);
		goto complete;
	}

	bridge_async_subdev->source = source;

	source->expected = true;

complete:
	fwnode_handle_put(handle);

	return ret;
}

int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
{
	struct device *dev = csi_dev->dev;
	struct sun6i_csi_bridge *bridge = &csi_dev->bridge;
	struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev;
	struct v4l2_subdev *subdev = &bridge->subdev;
	struct v4l2_async_notifier *notifier = &bridge->notifier;
	struct media_pad *pads = bridge->pads;
	enum v4l2_mbus_type parallel_mbus_types[] = {
		V4L2_MBUS_PARALLEL,
		V4L2_MBUS_BT656,
		V4L2_MBUS_INVALID
	};
	int ret;

	mutex_init(&bridge->lock);

	/* V4L2 Subdev */

	v4l2_subdev_init(subdev, &sun6i_csi_bridge_subdev_ops);
	subdev->internal_ops = &sun6i_csi_bridge_internal_ops;
	strscpy(subdev->name, SUN6I_CSI_BRIDGE_NAME, sizeof(subdev->name));
	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	subdev->owner = THIS_MODULE;
	subdev->dev = dev;

	v4l2_set_subdevdata(subdev, csi_dev);

	/* Media Entity */

	subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
	subdev->entity.ops = &sun6i_csi_bridge_entity_ops;

	/* Media Pads */

	pads[SUN6I_CSI_BRIDGE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
	pads[SUN6I_CSI_BRIDGE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
						  MEDIA_PAD_FL_MUST_CONNECT;

	ret = media_entity_pads_init(&subdev->entity,
				     SUN6I_CSI_BRIDGE_PAD_COUNT, pads);
	if (ret < 0)
		return ret;

	/* V4L2 Subdev */

	if (csi_dev->isp_available)
		ret = v4l2_async_register_subdev(subdev);
	else
		ret = v4l2_device_register_subdev(v4l2_dev, subdev);

	if (ret) {
		dev_err(dev, "failed to register v4l2 subdev: %d\n", ret);
		goto error_media_entity;
	}

	/* V4L2 Async */

Annotation

Implementation Notes