mtk android tv软件架构,MTK 平台Camera 驱动架构

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

b)设备的注册:

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

80ea05a73dcf58b0e4a4f550579ede2c.png

a3c2a7b2fdf472f7c4aba9c9ece6931d.png

4ef2d574716bf5d1628e62a3af08aa59.png

c)总线的匹配:

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

cbc16b4f77aa2b62049bdcde6cd79d8c.png

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

何进行匹配:

14ac941e187ac94853b84ee59f150691.png

Camera驱动工作流程:

78ccca7b9dd88214d85d38ee8e72cb24.png

从上图可以清晰的了解到 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 中实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MTK平台上的camera驱动教学课程旨在教授学员有关MTK平台上如何编写、安装和调试camera驱动程序的知识和技能。在这门课程中,学员将学习如何使用MTK平台提供的相应工具和接口来开发和优化camera驱动,以实现更好的图像质量和性能。 课程的内容包括以下几个方面: 1. 理论知识:学员将了解摄像头驱动的基本原理和工作原理,包括硬件架构、设备驱动接口和底层算法等。 2. 驱动开发环境搭建:学员将学习如何在MTK平台上搭建合适的开发环境,包括操作系统、编译器和调试工具等。 3. 驱动编写:学员将学习如何编写MTK平台上的camera驱动程序,包括设备初始化、图像采集和处理等功能的实现。 4. 驱动安装与调试:学员将学习如何将开发好的驱动程序安装到MTK平台上,并进行调试和优化,以确保驱动的稳定性和性能。 5. 实践项目:学员将完成一个实际的项目,如编写一个简单的camera应用程序或实现某种特定的图像处理算法,以应用所学知识并提升实践能力。 通过这门课程,学员将掌握MTK平台camera驱动开发的基本技能,能够独立完成camera驱动的编写、安装和调试工作,并具备进一步深入研究和优化的能力。这对于从事手机软件开发、图像处理等领域的工程师和研究人员来说,将是一门非常实用和重要的课程。 ### 回答2: MTK平台Camera驱动教学课程是针对使用MTK芯片的开发人员设计的一门课程。该课程旨在教授学员有关MTK平台Camera驱动的基础知识、开发技巧和调试方法。 首先,课程将介绍MTK平台和其特点,帮助学员了解MTK芯片及其应用领域。接下来,课程将重点讲解Camera驱动的原理和工作机制,涵盖Camera传感器的工作原理、图像采集和处理流程等方面的知识。 课程还将介绍Camera驱动的开发环境和工具,如MTK平台上的Camera HAL层和相应的调试工具。学员将学会如何配置和编译Camera驱动,以及如何使用调试工具进行驱动的调试和性能优化。 除了理论知识的讲解,课程还将通过实例演示和实践操作帮助学员掌握Camera驱动的开发技巧。学员将有机会参与实际的Camera驱动开发项目,通过实践来加深对课程知识的理解和应用能力。 总结起来,MTK平台Camera驱动教学课程旨在提供一套系统化的学习资源,帮助学员全面了解和掌握MTK平台上的Camera驱动开发。通过学习这门课程,学员将能够独立进行MTK平台Camera驱动的开发和调试工作,从而为MTK芯片应用的开发和优化提供支持。 ### 回答3: MTK平台CMOS摄像头驱动开发是一门与软硬件结合紧密的技术课程。首先,学习者需要熟悉MTK平台的基本知识,包括芯片结构、嵌入式系统以及Linux操作系统的基本原理。其次,学习者需要了解摄像头工作原理和常用的摄像头传感器类型,例如CMOS和CCD传感器。在掌握这些基础知识后,学习者可以开始学习MTK平台上的摄像头驱动开发。 在开发摄像头驱动时,学习者需要掌握如何通过MTK平台提供的驱动接口与摄像头硬件进行通信。这包括配置摄像头的分辨率、帧率、曝光时间以及白平衡等参数。此外,还需要了解如何处理摄像头的数据传输和处理,例如图像的压缩、旋转、镜像等操作。 在学习过程中,学习者可以通过阅读相关的文档和资料,参考MTK平台提供的示例代码来加深理解。同时,实际动手开发和调试也是非常重要的,可以通过连接MTK平台开发板和摄像头来调试和验证自己的驱动代码。学习者还可以通过与其他开发者交流和分享经验,提升自己的开发能力。 总之,MTK平台摄像头驱动开发是一门需要结合软硬件知识的综合性课程,通过学习掌握相关的理论知识和实践经验,可以帮助学习者深入了解摄像头驱动的工作原理和开发流程,提高自己的技术水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值