Linux v4l2架构学习总链接
dts代码如下
mipi_csi2: mipi-csi2@ffb10000 {
compatible = "rockchip,rv1126-mipi-csi2";
status = "okay";
ports {
...
port@0 {
reg = <0>;
mipi_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy0_out>;
};
};
port@1 {
reg = <1>;
mipi_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_in>;
};
};
};
};
驱动代码
static int csi2_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device_node *node = pdev->dev.of_node;
struct csi2_dev *csi2 = NULL;
struct resource *res;
int ret;
...
csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
if (!csi2)
return -ENOMEM;
csi2->dev = &pdev->dev;
...
/*
* sd->ops = &csi2_subdev_ops
*/
v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops);
v4l2_set_subdevdata(&csi2->sd, &pdev->dev);
csi2->sd.entity.ops = &csi2_entity_ops;
csi2->sd.dev = &pdev->dev;
csi2->sd.owner = THIS_MODULE;
csi2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
ret = strscpy(csi2->sd.name, DEVICE_NAME, sizeof(csi2->sd.name));
if (ret < 0)
v4l2_err(&csi2->sd, "failed to copy name\n");
platform_set_drvdata(pdev, &csi2->sd);
/*
* csi2_media_init同样是media相关的,不关心
*/
ret = csi2_media_init(&csi2->sd);
if (ret < 0)
goto rmmutex;
/*
* 主要分析 csi2_notifier
*/
ret = csi2_notifier(csi2);
if (ret)
goto rmmutex;
v4l2_info(&csi2->sd, "probe success, v4l2_dev:%s!\n", csi2->sd.v4l2_dev->name);
...
return 0;
}
csi2_probe
-> csi2_notifier
static int csi2_notifier(struct csi2_dev *csi2)
{
struct v4l2_async_notifier *ntf = &csi2->notifier;
int ret;
/*
* 这里还是寻找port@0
* v4l2_async_notifier_parse_fwnode_endpoints_by_port
* 这个函数之前已经分析过了
* 这个操作过后
* notifier->subdevs[0] 会记录之前分析mipi-csi-phy在dts中的节点信息
*/
ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(csi2->dev,
&csi2->notifier,
sizeof(struct v4l2_async_subdev), 0,
csi2_parse_endpoint);
if (ret < 0)
return ret;
if (!ntf->num_subdevs)
return -ENODEV; /* no endpoint */
csi2->sd.subdev_notifier = &csi2->notifier;
csi2->notifier.ops = &csi2_async_ops;
/*
* 具体的看v4l2_async_subdev_notifier_register 分析
* https://blog.csdn.net/ldl617/article/details/115548594
* 这个执行后 mipi csi的notifier->wait上会挂载asd
* 这个asd就是notifier->subdevs[0]
* 也就是mipi csi phy在dts中的节点
* 最后将mipi csi的notifier挂载到notifier_list上
*/
ret = v4l2_async_subdev_notifier_register(&csi2->sd, &csi2->notifier);
if (ret) {
v4l2_err(&csi2->sd,
"failed to register async notifier : %d\n",
ret);
v4l2_async_notifier_cleanup(&csi2->notifier);
return ret;
}
/*
* 这里会有v4l2_dev = NULL不执行
* 只是将subdev挂载到subdev_list
*/
return v4l2_async_register_subdev(&csi2->sd);
}