基于MT6739的Android9.0 Camera驱动(kernel层)

平台 os版本
MT6739 Android9.0

Kernel 层驱动的实现

camera 整个驱动框架分为三个部分: hal层 逻辑调用,kernel层 的通用驱动 sensorlist.c具体IC 的驱动, 比如 gc2385_mipi_raw.ckernel 起来后不会直接去访问 硬件sensor ,而是会注册相关的驱动,之后 Android系统 起来后会启动相关的服务如: camera_service ,在 camera 服务中会直接去访问 hal层 , kernel驱动 ,进而操作 camera 。这里只分析 kernel层中 camera驱动的实现。

Camera 开机流程

Power On 上电开机,然后通过 i2c 地址匹配 i2c 通讯, resetPower Down 上电 (上电代码在 kd_camera_hw.c 中的 kdCISModulePowerOnVCAM 主要给 ISP 供电; VCAM_IO 是数字IO电源,主要给I2C 供电, VCAMA 是模拟供电,主要给 感光区ADC 部分供电, VCAMAF 主要给对焦马达供电;具体使用可以根据 datasheet 添加,有时会影响 cts ),读取 sensor ID (具体 ic 驱动里面的 openget_imgsensor_id 都有读取 id 的操作, sensor id 只要大于 0 、小于 0xffffffff 都是合法的),然后软复位,下载 preview 参数为预览做准备,下载 capture 为拍照做准备,然后执行下电操作。


Camera 驱动的文件结构

参考 MTKmt6739_Sensor_Porting_guide 可以发现,在 kernel-3.18 中的 camera 驱动有 kd_sensorlist.ckd_camera_hw.c 这两个文件,但是在 MT6739 平台的 kernel-4.4 中将这个文件拆分成了多个文件,如下图所示:
camera驱动文件结构体
各个文件功能描述

文件路径:

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_hw.c

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_i2c.c

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_proc.c

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_sensor_list.c

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor_legacy.c

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/mt6739/camera_hw/imgsensor_cfg_table.c

File Decription(英文) Decription(中文)
imgsensor.c Sensor driver adapter and driver entry point sensor 驱动适配器和驱动入口函数的实现
imgsensor_hw.c Sensor power control sensor 电源控制的实现
imgsensor_i2c.c I2C read/write I2C 读写函数的实现
imgsensor_proc.c PROC related part proc文件系统相关部分的实现
imgsensor_sensor_list.c List of all sensors init function 包含所有sensor初始化函数的表单
imgsensor_legacy.c Legacy part of sensor. Mainly I2c related API sensor的旧的接口部分。主要是与I2c相关API
imgsensor_cfg_table.c Sensor Power and I2C configruation table sensor电源和I2C的配置表

Camera 驱动初始化流程

Camera 入口函数 imgsensor_init

文件路径:

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

module_init(imgsensor_init);

/* camera sensor入口函数 */
static int __init imgsensor_init(void)
{
   
	PK_DBG("[camerahw_probe] start\n");

    /* 注册一个平台驱动gimgsensor_platform_driver */
	if (platform_driver_register(&gimgsensor_platform_driver)) {
   
		PK_PR_ERR("failed to register CAMERA_HW driver\n");
		return -ENODEV;
	}
	...
        
	return 0;
}

注册的平台驱动结构体 gimgsensor_platform_driver

#ifdef CONFIG_OF /* 通过设备树进行match */
static const struct of_device_id gimgsensor_of_device_id[] = {
   
	{
    .compatible = "mediatek,camera_hw", },
	{
   }
};
#endif

static struct platform_driver gimgsensor_platform_driver = {
   
	.probe      = imgsensor_probe, /* 匹配成功会调用这个探测函数 */
	.remove     = imgsensor_remove,
	.suspend    = imgsensor_suspend,
	.resume     = imgsensor_resume,
	.driver     = {
   
		.name   = "image_sensor",
		.owner  = THIS_MODULE,
#ifdef CONFIG_OF
		.of_match_table = gimgsensor_of_device_id, /* 保存与设备树compatible进行匹配的字符串 */
#endif
	}
};

platform_devicesplatform_driver 通过 match 函数匹配上后,会调用 imgsensor_probe 函数注册前后摄 camera 驱动。


imgsensor_probe 探测函数的实现

文件路径:

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

/* 平台driver成功与device匹配后调用imgsensor_probe */
static int imgsensor_probe(struct platform_device *pdev)
{
   
	/* 分配设置注册camera驱动的字符设备文件/dev/kd_camera_hw,创建主次设备号 */
	if (imgsensor_driver_register()) {
   
		PK_PR_ERR("[CAMERA_HW] register char device failed!\n");
		return -1;
	}

	gpimgsensor_hw_platform_device = pdev;

    ... /* 省略部分代码 */
    
    /* camera硬件初始化,包含对power引脚的配置 */
	imgsensor_hw_init(&pgimgsensor->hw);
    
    /* 注册前后摄像头驱动 */
	imgsensor_i2c_create();
	imgsensor_proc_init();

	atomic_set(&pgimgsensor->imgsensor_open_cnt, 0);
#ifdef CONFIG_MTK_SMI_EXT
	mmdvfs_register_mmclk_switch_cb(mmsys_clk_change_cb, MMDVFS_CLIENT_ID_ISP);
#endif

	return 0;
}

imgsensor_probe() 函数中一开始先为 camera 驱动分配设置注册了 camera 字符驱动设备,然后通过函数 imgsensor_i2c_create() 注册前后 camera 驱动。


imgsensor_driver_register 注册函数的实现

imgsensor_driver_register 由函数 imgsensor_probe() 调用,在 imgsensor_driver_register() 函数中实现了 camera 驱动的主次设备号创建,注册对应的设备文件操作结构体 gimgsensor_file_operations

文件路径:

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

static inline int imgsensor_driver_register(void)
{
   
	int i, error = 0;
	dev_t dev_no = MKDEV(IMGSENSOR_DEVICE_NNUMBER, 0);

    /* 申请主设备号 */
    /*************************************************************** 
	 * 让内核分配给我们一个尚未使用的主设备号,不是由我们自己指定的
	 *
	 * dev      : alloc_chrdev_region函数向内核申请下来的主设备号
	 * baseminor: 次设备号的起始
	 * count    : 申请次设备号的个数
	 * name     : 执行 cat /proc/devices显示的名称
	 ***************************************************************/
	if (alloc_chrdev_region(&dev_no, 0, 1, IMGSENSOR_DEV_NAME)) {
   
		PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");
		return -EAGAIN;
	}

	/* Allocate driver */
	/* 给 gpimgsensor_cdev 分配内存,会在 cdev_del 中自动释放 */
	gpimgsensor_cdev = cdev_alloc();
	if (gpimgsensor_cdev ==  NULL) {
   
		unregister_chrdev_region(dev_no, 1);
		PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");
		return -ENOMEM;
	}

	/* Attatch file operation. */
	/*************************************************************
	 * cdev_init 与 cdev_add 函数基本一致,但是多出来对 cdev->ops
	 * 的赋值,用来将 gimgsensor_file_operations 加入到系统中,
	 * gimgsensor_file_operations 中包含着实际处理与设备通信的
	 * 函数。
	 *************************************************************/
	cdev_init(gpimgsensor_cdev, &gimgsensor_file_operations);

	gpimgsensor_cdev->owner = THIS_MODULE;

	/* Add to system */
	/*************************************************************
	 * 初始化 cdev 后,需要通过 cdev_add 把它添加到系统中去。
	 * 传入 cdev 结构的指针 gpimgsensor_cdev , 起始设备编号,
	 * 以及设备编号范围。 
	 *
	 * 可以在 /dev/ 目录下找到设备文件 "kd_camera_hw"
	 *************************************************************/
	if (cdev_add(gpimgsensor_cdev, dev_no, 1)) {
   
		PK_DBG("Attatch file operation failed\n");
		unregister_chrdev_region(dev_no, 1);
		return -EAGAIN;
	}

	/*************************************************************
	 * class_create 动态创建设备的逻辑类,并完成部分字段的初始化,
	 * 然后将其添加到内核中。创建的逻辑类位于/sys/class/。 
	 *
	 * owner: 拥有者。一般赋值为THIS_MODULE。
	 * name: 创建的逻辑类的名称。
	 *************************************************************/
	gpimgsensor_class = class_create(THIS_MODULE, "sensordrv");
	if (IS_ERR(gpimgsensor_class)) {
   
		int ret = PTR_ERR(gpimgsensor_class);

		PK_DBG("Unable to create class, err = %d\n", ret);
		return ret;
	}

	/************************************************************
	 * 通过 device_create 在 /sys/class/sensordrv/ 目录下创建一个
	 * 设备文件目录,目录名为 "kd_camera_hw" 
	 ************************************************************/
	gimgsensor_device = device_create(gpimgsensor_class, NULL, dev_no, NULL, IMGSENSOR_DEV_NAME);

	if (!gimgsensor_device) {
   
		pr_err("Failed to create kd_camera_hw device\n");
		return -1;
	}
	
	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
   
		error = device_create_file(gimgsensor_device, &device_attrs[i]);

		if (error) {
   
			PK_DBG("device_attrs[%d] create failed!!!\n", i);
			break;
		}
	}

	return 0;
}

通过 cdev_init 函数将 gimgsensor_file_operations 设备文件操作结构体注册内核,这样就可以让上层应用调用时使用到底层相关的 open、read、write、ioctl 函数。


gimgsensor_file_operations 文件操作结构体的实现

imgsensor_ioctl 函数被赋值给 file_operations 结构体 gimgsensor_file_operations 的成员变量 .unlocked_ioctl

文件路径:

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

static const struct file_operations gimgsensor_file_operations = {
   
	.owner = THIS_MODULE,
	.open = imgsensor_open,
	.release = imgsensor_release,
	.unlocked_ioctl = imgsensor_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = imgsensor_compat_ioctl
#endif
};

gimgsensor_file_operations 中可以发现,camera 控制函数是有 imgsensor_ioctl 实现的。


imgsensor_ioctl 的定义

通过 imgsensor_ioctl 这个函数来提供 camera 硬件驱动的控制接口。

文件路径:

./kernel-4.4/drivers/misc/mediatek/imgsensor/src/common/v1/imgsensor.c

static long imgsensor_ioctl(
	struct file *a_pstFile,
	unsigned int a_u4Command,
	unsigned long a_u4Param)
{
   
	int i4RetValue = 0;
	void *pBuff = NULL;
    ...

	switch (a_u4Command) {
   
	case KDIMGSENSORIOC_X_GET_CONFIG_INFO:
		i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
		break;
	case KDIMGSENSORIOC_X_GETINFO2:
		i4RetValue = adopt_CAMERA_HW_GetInfo2(pBuff);
		break;
	case KDIMGSENSORIOC_X_FEATURECONCTROL:
		i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);
		break;
	case KDIMGSENSORIOC_X_CONTROL:
		i4RetValue = adopt_CAMERA_HW_Control(pBuff);
		break;
	case KDIMGSENSORIOC_X_SET_MCLK_PLL:
		i4RetValue = imgsensor_clk_set(&pgimgsensor->clk, (ACDK_SENSOR_MCLK_STRUCT 
  • 15
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值