瑞芯微Rockchip开发者社区
直播中

1123127317

8年用户 1006经验值
擅长:制造/封装 接口/总线/驱动
私信 关注
[问答]

怎么去写基于RV1126平台的imx291驱动源码呢

怎么去写基于RV1126平台的imx291驱动源码呢?
如何对基于RV1126平台imx291的dts进行配置呢?

回帖(2)

李戈

2022-3-10 09:21:20
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 failedn");
                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(¬ifier->waiting);
        INIT_LIST_HEAD(¬ifier->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(¬ifier->list, ¬ifier_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, ¬ifier_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的注册都做了什么



  • 填充了subdev的相关成员信息

    • sd->ops = &imx291_subdev_ops;
    • sd->v4l2_dev = NULL;
    • sd->flags = V4L2_SUBDEV_FL_IS_I2C


  • 创建了notifier关联subdev,并将notifier挂载到链表notifier_list上
  • subdev挂载到subdev_list上


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

请看后面分析。。。

举报

李子月

2022-3-10 09:24:38
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 failedn");
                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(¬ifier->waiting);
        INIT_LIST_HEAD(¬ifier->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(¬ifier->list, ¬ifier_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, ¬ifier_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的注册都做了什么


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

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

请看后面分析。。。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分