1、camera kernel驱动
高通的kernel中,将camera分为两部分:video和camera两部分
1.1、camera video部分
video部分与userspace进行交互,sensor是有camera厂商定义的寄存器配置部分,主要完成相关寄存器参数的配置。
主要文件路径:kernel\msm-4.4\arch\arm\boot\dts\qcom\sdm660-camera.dtsi
kernel\msm-4.4\drivers\media\platform\msm\camera_v2\msm.c
qcom,msm-cam@ca00000 {
compatible = "qcom,msm-cam";
reg = <0xca00000 0x4000>;
reg-names = "msm-cam";
status = "ok";
bus-vectors = "suspend", "svs", "nominal", "turbo";
qcom,bus-votes = <0 150000000 320000000 320000000>;
qcom,gpu-limit = <700000000>;
};
static const struct of_device_id msm_dt_match[] = {
{.compatible = “qcom,msm-cam”},
{}
};
MODULE_DEVICE_TABLE(of, msm_dt_match);static struct platform_driver msm_driver = {
.probe = msm_probe,
.driver = {
.name = “msm”,
.owner = THIS_MODULE,
.of_match_table = msm_dt_match,
},
};static int __init msm_init(void)
{
return platform_driver_register(&msm_driver);
}
如上:这就是一个简单的platform框架的驱动设备文件,主要提供camera平台的电器参数。
在platform_drv中的probe()才是我们重点关注的,大胆猜测一下:不就是注册video设备到内核的video链表中吗?
msm_v4l2_dev该函数就是驱动的重点分析对象:如下,构造一个msm_v4l2_dev数据,并且调用v4l2_device_register()来将的v4l2部分注册进系统的video链表,调用video_register_device()来注册video部分。
static struct v4l2_device *msm_v4l2_dev; // 初始化一个 v4l2_device 类型的结构体
static int msm_probe(struct platform_device *pdev)
{
struct msm_video_device *pvdev = NULL;
static struct dentry *cam_debugfs_root;
// 1. 初始化一个 v4l2_device 类型的结构体,并分配好结构体内存
msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev), GFP_KERNEL);
pvdev = kzalloc(sizeof(struct msm_video_device), GFP_KERNEL);
// 2. 分配 video_device 结构体内存
pvdev->vdev = video_device_alloc();
// ---> kzalloc(sizeof(struct video_device), GFP_KERNEL);
// 3. 分配 media_device 结构体内存
msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device), GFP_KERNEL);
strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME, sizeof(msm_v4l2_dev->mdev->model)); // msm_config
msm_v4l2_dev->mdev->dev = &(pdev->dev);
// 4. 注册 media_device , 使用的 v4l2
rc = media_device_register(msm_v4l2_dev->mdev);
pvdev->vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; // V4L
pvdev->vdev->entity.group_id = QCAMERA_VNODE_GROUP_ID; // #define QCAMERA_VNODE_GROUP_ID 2
msm_v4l2_dev->notify = msm_sd_notify; // 用于发现对应的 subdev
pvdev->vdev->v4l2_dev = msm_v4l2_dev;
// 5. 设置父设备为 pdev->dev (也就是 qcom,msm-cam 的设备信息)
rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev);
// 6. 注册 video_device设备
strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name));
pvdev->vdev->release = video_device_release;
pvdev->vdev->fops = &msm_fops; // 配置 video_device 的字符设备操作函数
pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops; // 配置 v4l2 IOCTRL
pvdev->vdev->minor = -1;
pvdev->vdev->vfl_type = VFL_TYPE_GRABBER;
rc = video_register_device(pvdev->vdev, VFL_TYPE_GRABBER, -1);
// 7. 将当前 msm_video_device 结构体设为私有数据
video_set_drvdata(pvdev->vdev, pvdev);
// 8. 分配 msm_queue_head 结构体内存
msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
msm_init_queue(msm_session_q);
// 9. 创建 camera 调试目录
cam_debugfs_root = debugfs_create_dir(MSM_CAM_LOGSYNC_FILE_BASEDIR, NULL);
rc = cam_ahb_clk_init(pdev);
of_property_read_u32(pdev->dev.of_node,
"qcom,gpu-limit", &gpu_limit);
goto probe_end;
}
1.2、camera sensor部分
根据dts中camera sensor属性可知、节点为 compatible = "qcom,camera";
所以对饮的驱动路径为:kernel\msm-4.4\drivers\media\platform\msm\camera_v2\sensor\msm_sensor_driver.c
static const struct of_device_id msm_sensor_driver_dt_match[] = {
{.compatible = "qcom,camera"},
{}
};
MODULE_DEVICE_TABLE(of, msm_sensor_driver_dt_match);
static struct platform_driver msm_sensor_platform_driver = {
.probe = msm_sensor_driver_platform_probe,
.driver = {
.name = "qcom,camera",
.owner = THIS_MODULE,
.of_match_table = msm_sensor_driver_dt_match,
},
.remove = msm_sensor_platform_remove,
};
static struct i2c_driver msm_sensor_driver_i2c = {
.id_table = i2c_id,
.probe = msm_sensor_driver_i2c_probe,
.remove = msm_sensor_driver_i2c_remove,
.driver = {
.name = SENSOR_DRIVER_I2C,
},
};
static int __init msm_sensor_driver_init(void)
{
rc = platform_driver_register(&msm_sensor_platform_driver);
rc = i2c_add_driver(&msm_sensor_driver_i2c);
return rc;
}
依旧还是一个platform_driver设备类型,重点关注probe函数
代码路径:kernel\msm-4.4\drivers\media\platform\msm\camera_v2\sensor\msm_sensor_driver.c
static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev)
{
int32_t rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = NULL;
// 1. 创建并分配 msm_sensor_ctrl_t 结构体内存。
/* Create sensor control structure */
s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL);
platform_set_drvdata(pdev, s_ctrl);
// 2. 将sensor device type 初始化为 MSM_CAMERA_PLATFORM_DEVICE
/* Initialize sensor device type */
s_ctrl->sensor_device_type = MSM_CAMERA_PLATFORM_DEVICE;
s_ctrl->of_node = pdev->dev.of_node;
/*fill in platform device*/
s_ctrl->pdev = pdev;
// 3. 解析 节点为 compatible = "qcom,camera"; 的 dts 内容
rc = msm_sensor_driver_parse(s_ctrl);
// 4. 解析dts 中配置的camera clk 信息
// 解析 clock-names = "cam_src_clk", "cam_clk";
// 解析 qcom,clock-rates = <24000000 0>;
/* Get clocks information */
rc = msm_camera_get_clk_info(s_ctrl->pdev, &s_ctrl->sensordata->power_info.clk_info,
&s_ctrl->sensordata->power_info.clk_ptr, &s_ctrl->sensordata->power_info.clk_info_size);
/* Fill platform device id*/
pdev->id = s_ctrl->id;
/* Fill device in power info */
s_ctrl->sensordata->power_info.dev = &pdev->dev;
return rc;
}
dts的属性解析:
static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl){
/* Allocate memory for sensor_i2c_client */
s_ctrl->sensor_i2c_client = kzalloc(sizeof(*s_ctrl->sensor_i2c_client), GFP_KERNEL);
/* Parse dt information and store in sensor control structure */
rc = msm_sensor_driver_get_dt_data(s_ctrl); // 解析Camera DTS 节点,详见 Chapter 3.2
/* Initilize v4l2 subdev info */
s_ctrl->sensor_v4l2_subdev_info = msm_sensor_driver_subdev_info;
s_ctrl->sensor_v4l2_subdev_info_size =ARRAY_SIZE(msm_sensor_driver_subdev_info);
/* Initialize default parameters */
rc = msm_sensor_init_