Platform_driver 这个结构体包含 Probe()、 Remove()等函数来完成驱动的填充。

b)设备的注册:

对 platform_device 的定义通常在 BSP 的板级文件( kernel\arch\sh\boards\mach-ap325rxa\Setup.c)中实现,在板级文件中,将 platform_device归纳为一个数组,最终通过 platform_add_device()函数统一注册:

c)总线的匹配:

既 然 是 驱 动 Platform_device 那 对 应 的 设 备 必 然 是 挂 载 Platform 总 线 上 的Platform_device, Platform 总线是 Linux 系统提供的一种机制,不同于 I2C、 I2S 等总线,它是一种虚拟的总线。Linux 系统为 Platform 总线定义了一个 bus_type 的实例 Platform_bus_type:( Kernel\drivers\base\platform.c)

Platform 总线通过 platform_match 这个成员函数来确定 platform_device 与 platform_driver 如

何进行匹配:

Camera驱动工作流程:

从上图可以清晰的了解到 Camera 的一个工作流程主要分为这么七步:

1. 打开 Camera Power LDO,让 Camera 有能量保证。

2. 打开 IIC,设置 PDN 引脚,使 Camera 退出出 Standby 模式,按照要求让 Reset 脚做一个复位动作。

3. 读一下 sensor 的版本 ID,这样可以让你确认是否连接上你想要的 sensor。

4. 对 Sensor 进行初始化下载最基本的参数让 Sensor 工作起来,可能包括软复位。

5. 下载 preview 的参数,为预览动作准备。

6. 下载 Capture 的参数,为拍照动作准备。

7. 设置 PDN 引脚,使 Sensor 进入 Standby 模式,或者关掉 LDO 等动作,退出 Camera。

我们都知道, Linux 内核是通过模块的机制来加载设备驱动的,那么接下来我们就从设备模块加载的角度来看下 Camera 工作流程的驱动代码是如何工作的。在-alps\mediatek\custom\common\kernel\imgsensor\src\kd_sensorlist.c 中可以看到:

module_init(CAMERA_HW_i2C_init);

module_exit(CAMERA_HW_i2C_exit);

在这里 Linux 内核加载和卸载 Camera 模块

static struct platform_driver g_stCAMERA_HW_Driver = {

.probe = CAMERA_HW_probe,

.remove = CAMERA_HW_remove,

.suspend = CAMERA_HW_suspend,

.resume = CAMERA_HW_resume,

.driver = {

.name = "image_sensor",

.owner = THIS_MODULE,

}

};Camera 模块初始化开始向总线注册驱动,在 Platform_driver 的成员函数.probe()中, 通过 i2c_add_driver(&CAMERA_HW_i2c_driver)向 I2C 申请,而 CAMERA_HW_i2c_driver 这个结构体里填充的是将 Camera 作为一个字符设备在 I2C 上进行注册:

struct i2c_driver CAMERA_HW_i2c_driver = {

.probe = CAMERA_HW_i2c_probe,

.remove = CAMERA_HW_i2c_remove,

.driver.name = CAMERA_HW_DRVNAME1,

.id_table = CAMERA_HW_i2c_id,

};

/*******************************************************************************

* i2c relative start

********************************************************************************/

/*******************************************************************************

* CAMERA_HW_i2c_probe

********************************************************************************/

static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)

{

int i4RetValue = 0;

PK_DBG("[CAMERA_HW] Attach I2C \n");

//get sensor i2c client

spin_lock(&kdsensor_drv_lock);

g_pstI2Cclient = client;

//set I2C clock rate

g_pstI2Cclient->timing = 300;//200k

spin_unlock(&kdsensor_drv_lock);

//Register char driver

i4RetValue = RegisterCAMERA_HWCharDrv();

if(i4RetValue){

PK_ERR("[CAMERA_HW] register char device failed!\n");

return i4RetValue;

}

//spin_lock_init(&g_CamHWLock);

PK_DBG("[CAMERA_HW] Attached!! \n");

return 0;

}

在 RegisterCAMERA_HWCharDrv() 中

cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);对设备进行初始化,并将g_stCAMERA_HW_fops 这个文件操作函数作为上层对 Camera 设备操作的接口留给上层进行调用:

static const struct file_operations g_stCAMERA_HW_fops =

{

.owner = THIS_MODULE,

.open = CAMERA_HW_Open,

.release = CAMERA_HW_Release,

.unlocked_ioctl = CAMERA_HW_Ioctl

};

其中成员函数 open()只是初始化一个原子变量留给系统调用。 ioctl()才是整个 Camera驱动的入口:CAMERA_HW_Ioctl()是上层文件操作系统操作底层硬件的方法,它先对 Camera 需要的Buffer 做一个初始化,然后建立对 Cameraopen、 getinfo 等操作的接口:

/*******************************************************************************

* CAMERA_HW_Ioctl

********************************************************************************/

static long CAMERA_HW_Ioctl(

struct file * a_pstFile,

unsigned int a_u4Command,

unsigned long a_u4Param

)

{

int i4RetValue = 0;

void * pBuff = NULL;

u32 *pIdx = NULL;

mutex_lock(&kdCam_Mutex);

if(_IOC_NONE == _IOC_DIR(a_u4Command)) {

}

else {

pBuff = kmalloc(_IOC_SIZE(a_u4Command),GFP_KERNEL);

if(NULL == pBuff) {

PK_DBG("[CAMERA SENSOR] ioctl allocate mem failed\n");

i4RetValue = -ENOMEM;

goto CAMERA_HW_Ioctl_EXIT;

}

if(_IOC_WRITE & _IOC_DIR(a_u4Command)){

if(copy_from_user(pBuff , (void *) a_u4Param, _IOC_SIZE(a_u4Command))) {

kfree(pBuff);

PK_DBG("[CAMERA SENSOR] ioctl copy from user failed\n");

i4RetValue =  -EFAULT;

goto CAMERA_HW_Ioctl_EXIT;

}

}

}

pIdx = (u32*)pBuff;

switch(a_u4Command) {

#if 0

case KDIMGSENSORIOC_X_POWER_ON:

i4RetValue = kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM) *pIdx, true, CAMERA_HW_DRVNAME);

break;

case KDIMGSENSORIOC_X_POWER_OFF:

i4RetValue = kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM) *pIdx, false, CAMERA_HW_DRVNAME);

break;

#endif

case KDIMGSENSORIOC_X_SET_DRIVER:

i4RetValue = kdSetDriver((unsigned int*)pBuff);

break;

case KDIMGSENSORIOC_T_OPEN:

i4RetValue = adopt_CAMERA_HW_Open();

break;

case KDIMGSENSORIOC_X_GETINFO:

i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);

break;

case KDIMGSENSORIOC_X_GETRESOLUTION:

i4RetValue = adopt_CAMERA_HW_GetResolution(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_T_CLOSE:

i4RetValue = adopt_CAMERA_HW_Close();

break;

case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:

i4RetValue = adopt_CAMERA_HW_CheckIsAlive();

break;

case KDIMGSENSORIOC_X_GET_SOCKET_POS:

i4RetValue = kdGetSocketPostion((unsigned int*)pBuff);

break;

case KDIMGSENSORIOC_X_SET_I2CBUS:

//i4RetValue = kdSetI2CBusNum(*pIdx);

break;

case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:

//i4RetValue = kdReleaseI2CTriggerLock();

break;

default :

PK_DBG("No such command \n");

i4RetValue = -EPERM;

break;

}

if(_IOC_READ & _IOC_DIR(a_u4Command)) {

if(copy_to_user((void __user *) a_u4Param , pBuff , _IOC_SIZE(a_u4Command))) {

kfree(pBuff);

PK_DBG("[CAMERA SENSOR] ioctl copy to user failed\n");

i4RetValue =  -EFAULT;

goto CAMERA_HW_Ioctl_EXIT;

}

}

kfree(pBuff);

CAMERA_HW_Ioctl_EXIT:

mutex_unlock(&kdCam_Mutex);

return i4RetValue;

}

通过判断 Sensor 状态的逻辑值来进行具体的操作, 对于这个值的定义在:

Mediatek\custom\common\kernel\imgsensor\inc\Kd_imgsensor.h 中

//sensorOpen

//This command will TBD

#define KDIMGSENSORIOC_T_OPEN            _IO(IMGSENSORMAGIC,0)

//sensorGetInfo

//This command will TBD

#define KDIMGSENSORIOC_X_GETINFO            _IOWR(IMGSENSORMAGIC,5,ACDK_SENSOR_GETINFO_STRUCT)

//sensorGetResolution

//This command will TBD

#define KDIMGSENSORIOC_X_GETRESOLUTION      _IOWR(IMGSENSORMAGIC,10,ACDK_SENSOR_RESOLUTION_INFO_STRUCT)

//sensorFeatureControl

//This command will TBD

#define KDIMGSENSORIOC_X_FEATURECONCTROL    _IOWR(IMGSENSORMAGIC,15,ACDK_SENSOR_FEATURECONTROL_STRUCT)

//sensorControl

//This command will TBD

#define KDIMGSENSORIOC_X_CONTROL            _IOWR(IMGSENSORMAGIC,20,ACDK_SENSOR_CONTROL_STRUCT)

//sensorClose

//This command will TBD

#define KDIMGSENSORIOC_T_CLOSE            _IO(IMGSENSORMAGIC,25)

//sensorSearch

#define KDIMGSENSORIOC_T_CHECK_IS_ALIVE     _IO(IMGSENSORMAGIC, 30)

//set sensor driver

#define KDIMGSENSORIOC_X_SET_DRIVER         _IOWR(IMGSENSORMAGIC,35,SENSOR_DRIVER_INDEX_STRUCT)

//get socket postion

#define KDIMGSENSORIOC_X_GET_SOCKET_POS     _IOWR(IMGSENSORMAGIC,40,u32)

//set I2C bus

#define KDIMGSENSORIOC_X_SET_I2CBUS     _IOWR(IMGSENSORMAGIC,45,u32)

//set I2C bus

#define KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK     _IO(IMGSENSORMAGIC,50)

//Set Shutter Gain Wait Done

#define KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE   _IOWR(IMGSENSORMAGIC,55,u32)//HDR

//set mclk

#define KDIMGSENSORIOC_X_SET_MCLK_PLL         _IOWR(IMGSENSORMAGIC,60,ACDK_SENSOR_MCLK_STRUCT)

在 KdSetDriver()中通过判断 name 和 ID 匹配具体型号的 sensor 的驱动,判断它是主摄还

是次摄,并对它进行初始化:

/*******************************************************************************

* kdSetDriver

********************************************************************************/

int kdSetDriver(unsigned int* pDrvIndex)

{

ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;

u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {0,0};

u32 i;

PK_XLOG_INFO("pDrvIndex:0x%08x/0x%08x \n",pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0],pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_1]);

//set driver for MAIN or SUB sensor

if (0 != kdGetSensorInitFuncList(&pSensorList))

{

PK_ERR("ERROR:kdGetSensorInitFuncList()\n");

return -EIO;

}

for ( i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS ; i++ ) {

//

spin_lock(&kdsensor_drv_lock);

g_bEnableDriver[i] = FALSE;

g_invokeSocketIdx[i] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB)>>KDIMGSENSOR_DUAL_SHIFT);

spin_unlock(&kdsensor_drv_lock);

drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB);

//

if ( DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i] ) { continue; }

/*if( DUAL_CAMERA_MAIN_2_SENSOR == g_invokeSocketIdx[i] ) {

spin_lock(&kdsensor_drv_lock);

gI2CBusNum = SUPPORT_I2C_BUS_NUM2;

spin_unlock(&kdsensor_drv_lock);

PK_XLOG_INFO("kdSetDriver: switch I2C BUS2\n");

}

else {

spin_lock(&kdsensor_drv_lock);

gI2CBusNum = SUPPORT_I2C_BUS_NUM1;

spin_unlock(&kdsensor_drv_lock);

PK_XLOG_INFO("kdSetDriver: switch I2C BUS1\n");

}*/

//ToDo: remove print information

PK_XLOG_INFO("[kdSetDriver] i,g_invokeSocketIdx[%d] = %d :\n",i,i,drvIdx[i]);

PK_XLOG_INFO("[kdSetDriver] i,drvIdx[%d] = %d :\n",i,i,drvIdx[i]);

//

if ( MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i] ) {

if (NULL == pSensorList[drvIdx[i]].SensorInit) {

PK_ERR("ERROR:kdSetDriver()\n");

return -EIO;

}

pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);

if (NULL == g_pInvokeSensorFunc[i]) {

PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n",i);

return -EIO;

}

//

spin_lock(&kdsensor_drv_lock);

g_bEnableDriver[i] = TRUE;

g_CurrentInvokeCam = g_invokeSocketIdx[i];

spin_unlock(&kdsensor_drv_lock);

//get sensor name

memcpy((char*)g_invokeSensorNameStr[i],(char*)pSensorList[drvIdx[i]].drvname,sizeof(pSensorList[drvIdx[i]].drvname));

//return sensor ID

//pDrvIndex[0] = (unsigned int)pSensorList[drvIdx].SensorId;

PK_XLOG_INFO("[kdSetDriver] :[%d][%d][%d][%s][%d]\n",i,g_bEnableDriver[i],g_invokeSocketIdx[i],g_invokeSensorNameStr[i],sizeof(pSensorList[drvIdx[i]].drvname));

}

}

return 0;

}

typedef struct

{

MUINT32 SensorId;

MUINT8  drvname[32];

MUINT32 (* SensorInit)(PSENSOR_FUNCTION_STRUCT *pfFunc);

} ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT, *PACDK_KD_SENSOR_INIT_FUNCTION_STRUCT;

通过 NAME 和 ID 匹配完成后会将 PSENSOR_FUNCTION_STRUCT *pfFunc 这个结构体匹配到具体型号的驱动代码中:

SENSOR_FUNCTION_STRUCTSensorFuncGC0329YUV=

{

GC0329Open,

GC0329GetInfo,

GC0329GetResolution,

GC0329FeatureControl,

GC0329Control,

GC0329Close

};

到这里,整个 Camera 驱动从总线注册到完成具体 sensor 的初始化的流程就完成了,CAMERA_HW_Ioctl()中其他的 ioctl 操作函数最后都会在$sensor$_sensor.c 中实现。

mtk android tv软件架构,MTK 平台Camera 驱动架构相关推荐

  1. Android高通平台调试Camera驱动全纪录

    项目比较紧,3周内把一个带有外置ISP,MIPI数据通信,800万像素的camera从无驱动到实现客户全部需求. 1日 搭平台,建环境,编译内核,烧写代码. 我是一直在Window下搭个虚拟机登服务器 ...

  2. 请把Camera hold住 - Android高通平台调试Camera驱动全纪录

    项目比较紧,3周内把一个带有外置ISP,MIPI数据通信,800万像素的camera从无驱动到实现客户全部需求. 1日 搭平台,建环境,编译内核,烧写代码. 我是一直在Window下搭个虚拟机登服务器 ...

  3. android camera2 qcom,Qcom平台 Camera的一些知识点 之MCLK

    前言 MCLK 是平台 baseband 提供给 cam sensor的正常工作的频率, Qcom 平台一般未24MHz,由其他时钟源分频而来,实测在23.8MHz左右. 在打开相机的时候,才可以测到 ...

  4. android camera2 qcom,Qcom平台 camera的一些知识点 之RAW图抓取

    前言 介绍camera sensor 输出的 raw 图,用于验证cam显示效果问题. 参考文档 : KBA-161204073328 目录 的 mask bit 定义 参数解释: /** * 参数解 ...

  5. mtk android 编译过程,MTK android 快速编译方法.doc

    . . [FAQ10625] 提升Android编译速度 Platform: MT6572 MT6582 MT6588 MT6589 MT6592 MT6595 MT6571 MT6582/92+MT ...

  6. 全志平台camera驱动开发(4)NVP6134芯片4路模拟视频BT656输入

    前言 1. 调试平台: 全志V5/T7等有BT656或BT1120的并行接口,理论有DVP接口的一般都支持 2. NVP6134可使用多路视频同时输入 硬件连接 模拟camera1 模拟camera2 ...

  7. 全志平台camera驱动开发(5)NVP6134芯片8路模拟视频BT1120输入

    前言 1. 调试平台: 全志V5/T7等有BT1120的并行接口,理论有DVP接口的一般都支持 2. NVP6134可使用多路视频同时输入 硬件连接 模拟camera1 模拟camera2 模拟cam ...

  8. mtk android关机铃声,mtk android power key 长按8s 关机功能实现

    该功能是系统启动后,在任何情况下,长按power key 8s都能做到直接关机.因此在kernel中实现. 所有修改都在keypad driver中,如下文件. mediatek\platform\m ...

  9. android tv闹钟_Android 平台有哪些闹钟应用值得推荐?

    哇真是一篇充满年代感的问题,不知道咋点进来的. 既然点进来,就得留下点什么,这是我的一贯风格(装一下 -_-!) 楼主提到的睡眠周期,我不是特别理解,就按照我的习惯碎碎念一下吧 ----------- ...

最新文章

  1. MySQL触发器的使用规则
  2. DASH直播平台的搭建
  3. 【HDU - 5890】Eighty seven(bitset优化背包)
  4. openssh升级后无法登陆解决方案
  5. 关于obs的录制时黑屏问题
  6. android 接收SDCcard插拔的广播
  7. 取消浏览器的默认样式
  8. Git版本管理工具的使用方法
  9. JAVA 随机数学习
  10. 「一本通 4.5 例 1」树的统计(树链剖分)
  11. 珠宝订货(订单)系统与ERP实现库存信息同步的实现方案分享
  12. dir_recurse是 php函数,dir_recurse是一个函数么?
  13. 火车票查询软件测试自学,火车票订购系统的测试报告.doc
  14. 【机器学习7】决策树
  15. 做戴威式的管理者,还是雷军式的管理者?
  16. java计算移动平均值_多种移动平均计算总结(MA,EMA,SMA,DMA,TMA,WMA)
  17. java se和java_Java SE 9非常适合灵活,可扩展和无服务器的未来
  18. Anaconda使用教程(一)——下载、安装及环境配置
  19. Python实现TOPSIS分析法(优劣解距离法)
  20. 痛心!华为高管丁耘去世,享年 53 岁

热门文章

  1. 中软培训 day01 sublime安装及使用
  2. Geoserver学习笔记-3、服务标准(WFS)
  3. 9月份杂谈-如何戒掉坏习惯
  4. 基于RT-THREAD nano的平衡车--上位机软件
  5. Excel AI - 推出 AI 智能函数,太过强大
  6. Python学习笔记(9)采集图片网址并下载图片——以途牛旅游网为例
  7. Ubuntu 与Windows共享文件夹的操作
  8. 北京信息科技大学计算机科学与技术怎么样,北京信息科技大学怎么样 ,是211的学校吗...
  9. Golang基础——统计字符串中汉字的数量
  10. 使用git pull的时候未能对git remote进行身份验证?