基于RV1126平台imx291分析 --- imx291注册

Linux v4l2架构学习总链接

imx291源码

imx291的dts配置如下

        imx291: imx291@1a {
                compatible = "sony,imx291";
                status = "okay";
                reg = <0x1a>;

                ...

                port {
                        ucam_out2: endpoint {
                                remote-endpoint = <&mipi_in_ucam0>;
                                data-lanes = <1 2 3 4>;
                        };
                };
        };

对于endpoint这里先忽略

下面分析驱动

imx291_probe


struct imx291 {
	struct i2c_client	*client;
	...
	struct v4l2_subdev	subdev;
	struct media_pad	pad;
	...
	bool			streaming;
	bool			power_on;
	...
};

static int imx291_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct device *dev = &client->dev;
	struct device_node *node = dev->of_node;
	struct imx291 *imx291;
	struct v4l2_subdev *sd;
	
	int ret;
	
	imx291 = devm_kzalloc(dev, sizeof(*imx291), GFP_KERNEL);
	if (!imx291)
    		return -ENOMEM;

	...
	imx291->client = client;
        ...


    	sd = &imx291->subdev;

        
        /*
         * v4l2_i2c_subdev_init这里不展开分析
         * 主要记录一下几点
         * sd->ops = &imx291_subdev_ops;
         * sd->v4l2_dev = NULL;
         * sd->flags = V4L2_SUBDEV_FL_IS_I2C
         */

	v4l2_i2c_subdev_init(sd, client, &imx291_subdev_ops);


        /*
         * 对于controls这里先不分析
         * 后面有专题进行分析
         */


	ret = imx291_initialize_controls(imx291);
    	if (ret)
		goto err_probe;


        /*
         * 这个配置开启了
         * 下面这个成员值都先记住就好
         */

#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
	sd->internal_ops = &imx291_internal_ops;
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
#endif


        /*
         * media这里也先不分析
         * 后面专题
         */


#if defined(CONFIG_MEDIA_CONTROLLER)
	imx291->pad.flags = MEDIA_PAD_FL_SOURCE;
	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
	ret = media_entity_pads_init(&sd->entity, 1, &imx291->pad);
	if (ret < 0)
		goto err_power_off;
#endif

        ...
	ret = v4l2_async_register_subdev_sensor_common(sd);
	if (ret) {
		dev_err(dev, "v4l2 async register subdev failed\n");
		goto err_clean_entity;
	}

	return 0;
        ...
}

imx291_probe

-> v4l2_async_register_subdev_sensor_common


int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
{

        /*
         * 这里都是使用的异步的方式
         * 都是A完成了再通知B
         */

	struct v4l2_async_notifier *notifier;
	int ret;

	if (WARN_ON(!sd->dev))
		return -ENODEV;

	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
	if (!notifier)
		return -ENOMEM;

        /*
         * 这里主要解析dts中有没有指定以下3种设备
         * 1. flash-leds  闪光灯
         * 2. lens-focus 聚焦设备
         * 3. ir-cut     红外滤镜
         * 这些imx291都没有,忽略
         */

    	ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
							     notifier);
	if (ret < 0)
		goto out_cleanup;


        /* 主要就是将notifier挂载到链表notifier_list上 */

	ret = v4l2_async_subdev_notifier_register(sd, notifier);
	if (ret < 0)
		goto out_cleanup;

	ret = v4l2_async_register_subdev(sd);
	if (ret < 0)
		goto out_unregister;

        
        /* subdev和notifier你中有我,我中有你 */

	sd->subdev_notifier = notifier;

	return 0;
}

imx291_probe

-> v4l2_async_register_subdev_sensor_common

        -> v4l2_async_subdev_notifier_register


int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
					struct v4l2_async_notifier *notifier)
{
	int ret;

	if (WARN_ON(!sd || notifier->v4l2_dev))
		return -EINVAL;


        /*
         * 记录subdev
         */

	notifier->sd = sd;

        /* 异步通知注册 主要就是操作notifier */

	ret = __v4l2_async_notifier_register(notifier);
	if (ret)
		notifier->sd = NULL;

	return ret;
}

static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
{
	struct device *dev =
		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
	struct v4l2_async_subdev *asd;
	int ret;
	int i;


	INIT_LIST_HEAD(&notifier->waiting);
	INIT_LIST_HEAD(&notifier->done);
        ...

        
        /*
         * num_subdevs值为0,所以这里的for语句分析
         */

	for (i = 0; i < notifier->num_subdevs; i++) {
		...
	}

        
        /* 
         * 条件不满足,暂时不进入分析,不满足原因如下
         * 1. notifier->parent == NULL
         * 2. notifier->v4l2_dev == NULL
         */

	ret = v4l2_async_notifier_try_all_subdevs(notifier);
	if (ret < 0)
		goto err_unbind;


        /* 
         * 条件不满足,暂时不进入分析,不满足原因如下
         * 1. notifier->parent == NULL
         * 2. notifier->v4l2_dev == NULL
         */

        
	ret = v4l2_async_notifier_try_complete(notifier);
	if (ret < 0)
		goto err_unbind;

        /*
         * 以上2个函数可以看出来,v4l2_dev为空时都不会执行
         * 将这个notifer挂载到链表notifier_list上
         */


	/* Keep also completed notifiers on the list */
	list_add(&notifier->list, &notifier_list);

	mutex_unlock(&list_lock);

	return 0;

 

imx291_probe

-> v4l2_async_register_subdev_sensor_common

        -> v4l2_async_subdev_notifier_register

        -> v4l2_async_register_subdev


int v4l2_async_register_subdev(struct v4l2_subdev *sd)
{
	struct v4l2_async_notifier *subdev_notifier;
	struct v4l2_async_notifier *notifier;
	int ret;

	/*
	 * No reference taken. The reference is held by the device
	 * (struct v4l2_subdev.dev), and async sub-device does not
	 * exist independently of the device at any point of time.
	 */
	if (!sd->fwnode && sd->dev)
		sd->fwnode = dev_fwnode(sd->dev);

	mutex_lock(&list_lock);

	INIT_LIST_HEAD(&sd->async_list);


        /*
         * 目前为止notifier_list上只有一个notifer
         * v4l2_dev上面说过为NULL
         * 所以这个循环可以退出了,没有实质性的动作
         */


	list_for_each_entry(notifier, &notifier_list, list) {
		struct v4l2_device *v4l2_dev =
			v4l2_async_notifier_find_v4l2_dev(notifier);
		struct v4l2_async_subdev *asd;

		if (!v4l2_dev)
			continue;
                ...
        }

        /* None matched, wait for hot-plugging */

        
        /*
         * 没有匹配到相关的信息
         * 将subdev挂载到subdev_list上
         */

	list_add(&sd->async_list, &subdev_list);
}

以上就是imx291的注册过程,注意这里的分析认为是按照一定的顺序注册的,就是imx291--> mipi csi phy --> mipi csi --> rkcif_mipi这种注册顺序

总结一下imx291的注册都做了什么

  1. 填充了subdev的相关成员信息
    1. sd->ops = &imx291_subdev_ops;
    2. sd->v4l2_dev = NULL;
    3. sd->flags = V4L2_SUBDEV_FL_IS_I2C
  2. 创建了notifier关联subdev,并将notifier挂载到链表notifier_list上
  3. subdev挂载到subdev_list上

这里并没有想象中的直接去注册v4l-subdev的节点,看来是需要一定的契机才会注册

请看后面分析。。。

 

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值