基于RV1126 Video分析-----sensor模块所代表的subdev子设备注册

工作:

static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表

				LIST_HEAD(subdev_list)----+					    LIST_HEAD(notifier_list)----+
                                          |                                                 |
		                                  |挂载                                             | 挂载
	                                      |                                                 |
struct techpoint 						  |			   	   +->struct v4l2_async_notifier----+					
	struct v4l2_subdev subdev;	----------+----------------|----->struct v4l2_subdev *sd;
		const struct v4l2_subdev_ops *ops				   |
		struct v4l2_device *v4l2_dev;                      |
		struct v4l2_async_notifier *subdev_notifier; ------+

&i2c1 {                                          
                                             
/delete-node/ ar0230@10;                        
/delete-node/ ov4689@36;                        
/delete-node/ os04a10@36;                       
                                            
tp2855_1: tp2855_1@44 {  
	
	compatible = "techpoint,tp2855";                        
	reg = <0x44>;  //i2c地址                     
	...
	port {                                        
		ucam_out0: endpoint {                       
			remote-endpoint = <&csi_dphy0_input>; //Sensor连接到mipi
			data-lanes = <1 2 3 4>;                   
		};                                          
	};   
}; 

tp2855_2: tp2855_2@45 {
	compatible = "techpoint,tp2855";
	reg = <0x45>; //i2c地址         
	...
	port {
		ucam_out1: endpoint {
			remote-endpoint = <&csi_dphy1_input>; //Sensor连接到mipi    csi_dphy1_input
			data-lanes = <1 2 3 4>; 
		};
	};
};

};

kernel\drivers\media\i2c\techpoint\techpoint_v4l2.c

static const struct v4l2_subdev_pad_ops techpoint_subdev_pad_ops = {
	.enum_mbus_code = techpoint_enum_mbus_code,
	.enum_frame_size = techpoint_enum_frame_sizes,
	.get_fmt = techpoint_get_fmt,
	.set_fmt = techpoint_set_fmt,
};

static const struct v4l2_subdev_video_ops techpoint_video_ops = {
	.s_stream = techpoint_stream,
	.g_mbus_config = techpoint_g_mbus_config,
	.g_frame_interval = techpoint_g_frame_interval,
	.querystd = techpoint_querystd,
};


static const struct v4l2_subdev_core_ops techpoint_core_ops = {
	.s_power = techpoint_power,
	.ioctl = techpoint_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl32 = techpoint_compat_ioctl32,
#endif
};


static const struct v4l2_subdev_ops techpoint_subdev_ops = {
	.core = &techpoint_core_ops,
	.video = &techpoint_video_ops,
	.pad   = &techpoint_subdev_pad_ops,
};



#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static const struct v4l2_subdev_internal_ops techpoint_internal_ops = {
	.open = techpoint_open,
};
#endif


/*
1 填充了subdev的相关成员信息 struct v4l2_subdev *sd;

		sd = &techpoint->subdev; 绑定 techpoint -- v4l2_subdev
		sd->ops = &imx291_subdev_ops;
		sd->v4l2_dev = NULL;
		sd->flags = V4L2_SUBDEV_FL_IS_I2C

2 记录 v4l2_subdev 到 异步通知notifier  notifier->sd = sd
  并将notifier挂载到全局链表notifier_list上
  
3 subdev 挂载到 全局链表subdev_list上
*/
static int techpoint_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	
	struct device *dev = &client->dev;
	struct techpoint *techpoint;
	struct v4l2_subdev *sd;
	
	
	techpoint = devm_kzalloc(dev, sizeof(*techpoint), GFP_KERNEL);
	if (!techpoint)
		return -ENOMEM;

	techpoint->client = client;
	techpoint->supplies = NULL;
...
	
	//注册
	/*
	sd = &techpoint->subdev; 绑定 techpoint -- v4l2_subdev
	sd->ops = &imx291_subdev_ops;
	sd->v4l2_dev = NULL;
	sd->flags = V4L2_SUBDEV_FL_IS_I2C
	*/
	sd = &techpoint->subdev;
	v4l2_i2c_subdev_init(sd, client, &techpoint_subdev_ops);
	
...
	
	/* 
	1 创建了异步通知notifier 关联subdev,并将notifier挂载到全局链表notifier_list上
	2 subdev挂载到 全局链表subdev_list上
	*/
	ret = v4l2_async_register_subdev_sensor_common(sd);

}


static const struct of_device_id techpoint_of_match[] = {
	{ .compatible = "techpoint,tp2855" },
	{ .compatible = "techpoint,tp2815" },
	{ .compatible = "techpoint,tp9930" },
	{},
};

static const struct i2c_device_id techpoint_match_id[] = {
	{ "techpoint", 0 },
	{ },
};

static struct i2c_driver techpoint_i2c_driver = {
	.driver = {
		.name = TECHPOINT_NAME,
		.pm = &techpoint_pm_ops,
		.of_match_table = of_match_ptr(techpoint_of_match),
	},
	.probe		= &techpoint_probe,
	.remove		= &techpoint_remove,
	.id_table	= techpoint_match_id,
};

static int __init sensor_mod_init(void)
{
	return i2c_add_driver(&techpoint_i2c_driver);
}

static void __exit sensor_mod_exit(void)
{
	i2c_del_driver(&techpoint_i2c_driver);
}

kernel\drivers\media\v4l2-core\v4l2-fwnode.c

/*
1 创建了异步通知notifier 关联subdev,并将notifier挂载到全局链表notifier_list上
2 subdev挂载到 全局链表subdev_list上
*/
int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
{
	struct v4l2_async_notifier *notifier;
	int ret;

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

	//初始化为空
	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
	if (!notifier)
		return -ENOMEM;

...

	/* 主要就是将异步通知notifier挂载到 全局notifier_list链表上 
		
		1 记录v4l2_subdev 到 异步通知notifier  notifier->sd = sd
		2 将异步通知notifier挂载到 全局notifier_list链表上 
		
		v4l2_subdev
		v4l2_async_notifier
	*/
	ret = v4l2_async_subdev_notifier_register(sd, notifier);
	if (ret < 0)
		goto out_cleanup;

	//将当前subdev挂载到 全局链表subdev_list上
	ret = v4l2_async_register_subdev(sd);
	if (ret < 0)
		goto out_unregister;

	
	/* subdev和notifier你中有我,我中有你 */
	sd->subdev_notifier = notifier;

	return 0;

out_unregister:
	v4l2_async_notifier_unregister(notifier);

out_cleanup:
	v4l2_async_notifier_cleanup(notifier);
	kfree(notifier);

	return ret;
}

kernel\drivers\media\v4l2-core\v4l2-async.c

static LIST_HEAD(notifier_list); //异步通知链表
static LIST_HEAD(subdev_list);//v4l2_subdev 链表


/*

		参数1 struct mipidphy_priv -> v4l2_subdev
		参数2 struct mipidphy_priv -> v4l2_async_notifier
*/
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;

	/*
	参数 struct mipidphy_priv -> v4l2_async_notifier
	
	异步通知注册 主要就是操作notifier 
	*/
	ret = __v4l2_async_notifier_register(notifier);
	if (ret)
		notifier->sd = NULL;

	return ret;
}


/*
参数 struct mipidphy_priv -> v4l2_async_notifier
*/
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;
	//不满足条件 跳出
	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
		return -EINVAL;
		
	mutex_lock(&list_lock);
	//对于 sensor驱动 无,跳过
	for (i = 0; i < notifier->num_subdevs; i++) {
		...
	}
	/*
该函数只能从V4L2顶层设备:rkcif_mipi设备 开始执行。因为其他三个subdev设备自己刚开始是没有初始化 自己的 父通知器 以及 自己的通知器所管理的 v4l2_device设备的
所以这里 sensor 不执行
*/
	ret = v4l2_async_notifier_try_all_subdevs(notifier);

	 /*  	参数1  当前设备异步通知器				
     * 条件不满足,暂时不进入分析,不满足原因如下
     * 1. notifier->parent == NULL
     * 2. notifier->v4l2_dev == NULL
	 
	 所以其他三个subdev设备 独自初始化时 不满足该函数运行条件
	 只有 rkcif_mipi 能执行该函数
     */

	ret = v4l2_async_notifier_try_complete(notifier);

		  /*
     * 以上2个函数可以看出来,v4l2_dev为空时都不会执行
     * 将这个notifer挂载到链表notifier_list上
     */
	list_add(&notifier->list, &notifier_list);
	
}


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

	if (!sd->fwnode && sd->dev)
		sd->fwnode = dev_fwnode(sd->dev);

	mutex_lock(&list_lock);

	INIT_LIST_HEAD(&sd->async_list);

...

	 /*
         * 没有匹配到相关的信息
         * 将当前subdev挂载到 全局链表subdev_list上
         */
		 
	list_add(&sd->async_list, &subdev_list);
...
	
	return ret;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
TP2915 is a video D/A solution for converting HD digital video signal into the analog domain that is suitable for transmission over single coaxial or twist-pair cable over long reach. The major application is the Automotive interconnect between HD display and HD camera systems or any other applications require robust and low cost transmission of HD video. TP2915 generates the analog video signal complying with HD Transport Video Interface (HD-TVI) format. It is one form of the HD composite video format that is widely adopted in the industry. TP2915 can support a variety of video resolution digital video input standards in 422 or 444 formats over 8, 16 or 24-bit interface with the embedded synchronization (EAV/SAV) header or explicit sync signals. It also accepts 24-bit RGB input with external sync signals. It has the built-in sync extraction logic to obtain the sync information inside the video stream. The video resolutions supported range from SD (NT/PAL) to UHD. TP2915 contains a versatile video timing generator that is programmable for all standards supported and other non-standard video formats. It has programmable clip/shift/scale function to proper condition the input video signal for further processing. It also has an optional 2x over-sampling filters built-in to support higher output sample rate. Over-sampling can relax the external analog filter requirement. TP2915 supports selectable current mode and voltage mode output as well as internal programmable analog reconstruction filter. The built-in data slicer help minimize glue circuits. The signal amplitude of the DAC output can be set by external current setting resistor. It also has built-in color bar test pattern generator for easy testing and adjustment. TP2915 has built-in clock jitter reduction circuit based on local crystal clock to ensure the output signal performance.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Linux老A

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

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

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

打赏作者

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

抵扣说明:

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

余额充值