全志T7 csi&isp等驱动

vin驱动入口

vin驱动的入口文件是drivers\media\platform\sunxi-vin\vin.c,入口函数是vin_init():

static int __init vin_init(void)
{
	ret = sunxi_csi_platform_register();
	ret = sunxi_isp_platform_register();
	ret = sunxi_mipi_platform_register();
	ret = sunxi_flash_platform_register();
	ret = sunxi_scaler_platform_register();
	ret = sunxi_vin_core_register_driver();
	ret = sunxi_vin_debug_register_driver();
	ret = platform_driver_register(&vin_driver);
}

在vin_init()中分别注册csi、isp、scaler等驱动,这里简单分析csi、isp、scaler驱动。

CSI驱动

DST中有:
在这里插入图片描述
即系统有4个CSI模块,sunxi_csi_platform_register()调用后,将4次调用csi_probe(),这个函数主要完成以下任务:
分配并初始化csi_dev

  • 解析DST
  • 映射csi寄存器地址
  • 初始化一个csi_list列表
  • 调用__csi_init_subdev()
  • 调用platform_set_drvdata()设置私有数据,方便驱动内部其他函数获得csi_dev

这里关注__csi_init_subdev():

static int __csi_init_subdev(struct csi_dev *csi)
{
	struct v4l2_subdev *sd = &csi->subdev;
	int ret;
	mutex_init(&csi->subdev_lock);
	csi->arrange.row = 1;
	csi->arrange.column = 1;
	csi->bus_info.ch_total_num = 1;
	v4l2_subdev_init(sd, &sunxi_csi_subdev_ops);//初始化csi->subdev
	sd->grp_id = VIN_GRP_ID_CSI;
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	snprintf(sd->name, sizeof(sd->name), "sunxi_csi.%u", csi->id);
	v4l2_set_subdevdata(sd, csi);//绑定csi到sd,即subdev与启动自定义结构体相互绑定

	csi->csi_pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
	csi->csi_pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
	ret = media_entity_init(&sd->entity, CSI_PAD_NUM, csi->csi_pads, 0);//初始化csi->subdev->entity
	if (ret < 0)
		return ret;

	return 0;
}

这个函数首先调用v4l2_subdev_init初始化一个v4l2_subdev设备,它在后续将被添加到vin_mid. vin_csi_info[]里面,参数sunxi_csi_subdev_ops可以参考《nvp6134驱动.docx》中关于v4l2_subdev_ops结构体的说明。调用v4l2_set_subdevdata()实现sd绑定csi,其他地方可以调用v4l2_get_subdevdata()这样就会很方便的从v4l2_subdev找到csi设备数。这个函数最后调用media_entity_init()初始化一个Media Entity(实体):
在这里插入图片描述
调用csi_probe()后几个结构体的关系如下:
在这里插入图片描述
那这个csi的v4l2_subsdev再哪里添加到vin驱动的v4l2_device呢?
vin.c vin_probe()–>vin_md_register_entities()有:
在这里插入图片描述
首先调用sunxi_csi_get_subdev()(如下)获得系统注册的csi模块v4l2_subdev设备,然后调用v4l2框架函数v4l2_device_register_subdev()注册。
在这里插入图片描述
csi_drv_list在sunxi_csi.c中定义:
在这里插入图片描述
宏LIST_HEAD如下:

#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)

#define LIST_HEAD_INIT(name) { &(name), &(name) }

展开后,csi_drv_list的定义相当于:

struct list_head csi_drv_list= {
	&csi_drv_list,
	&csi_drv_list,
}

即定义了一个前向和后向都指向自己的list_head,且这是一个全局的变量,整个系统共享一个变量。而每个csi设备在调用csi_probe函数时都会调用:
在这里插入图片描述
将每个csi_dev查到列表尾部,这样sunxi_csi_get_subdev()就可以获得csi_dev给vin驱动使用了。

ISP驱动

DST中有:
在这里插入图片描述
即系统同样有4个ISP模块,sunxi_isp_platform_register()调用后,将4次调用isp_probe (),该函数与上面csi_probe()类似,但是多了一个v4l2_ctrl_handler的初始化和初始化isp_stat。
在这里插入图片描述

scaler驱动

系统有8个scaler模块,sunxi_isp_platform_register()调用后,将8次调用scaler_probe(),代码与csi_probe()类似,不再介绍。

MIPI驱动

代码:drivers\media\platform\sunxi-vin\vin-mipi
芯片中集成了两个MIPI-CSI接口,DST中配置如下:
在这里插入图片描述
其中设备的id定义为0x0或0x1,根据项目电路图,选择对应的MIPI-CSI接口:
在这里插入图片描述
在这里插入图片描述
因MIPI0只能输出给CSI0,所以配置vin0_csi_sel=0

vin-mipi驱动代码与csi驱动代码类似,不解释。

总结

总的来说,vin驱动的v4l2_subdev有

csi_dev->subdev
isp_dev->subdev
isp_stat-->subdev
scaler_dev-->subdev
vic_core->vid_cap.subdev
cci_driver-->subdev

这刚好对应vin_md结构体内部的几个数组(大部分v4l2驱动都是现实为链表的,这里因为知道subdev最大的数量,所以可以定义为数组形式):

struct vin_md {
	struct vin_csi_info csi[VIN_MAX_CSI];
	struct vin_mipi_info mipi[VIN_MAX_MIPI];
	struct vin_cci_info cci[VIN_MAX_CCI];
	struct vin_isp_info isp[VIN_MAX_ISP];
	struct vin_stat_info stat[VIN_MAX_ISP];
	struct vin_scaler_info scaler[VIN_MAX_SCALER];
	。。。。。。
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值