微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 手机设计讨论 > MTK手机平台交流 > MTK Camera 模块驱动、设备与总线结构:

MTK Camera 模块驱动、设备与总线结构:

时间:10-02 整理:3721RD 点击:
mtk   CAMERA 模块驱动、设备与总线结构:
a)  驱动的注册
在(\custom\common\kernel\imgsensor\src\Kd_sensorlist.c)CAMERA_HW_I2C_init 这个
static int __init CAMERA_HW_i2C_init(void)
{
    struct proc_dir_entry *prEntry;
//i2c_register_board_info(CAMERA_I2C_BUSNUM, &kd_camera_dev, 1);
    i2c_register_board_info(SUPPORT_I2C_BUS_NUM1, &i2c_devs1, 1);
    //i2c_register_board_info(SUPPORT_I2C_BUS_NUM2, &i2c_devs2, 1);

    if(platform_driver_register(&g_stCAMERA_HW_Driver)){
        PK_ERR("failed to register CAMERA_HW driver\n");
        return -ENODEV;
    }
    //if(platform_driver_register(&g_stCAMERA_HW_Driver2)){
    //    PK_ERR("failed to register CAMERA_HW driver\n");
    //    return -ENODEV;
    //}
    //Register proc file for main sensor register debug
    prEntry = create_proc_entry("driver/camsensor", 0, NULL);
    if (prEntry) {
        prEntry->read_proc = CAMERA_HW_DumpReg_To_Proc;
        prEntry->write_proc = CAMERA_HW_Reg_Debug;
    }
    else {
        PK_ERR("add /proc/driver/camsensor entry fail \n");
    }
    //Register proc file for sub sensor register debug
    prEntry = create_proc_entry("driver/camsensor2", 0, NULL);
    if (prEntry) {
        prEntry->read_proc = CAMERA_HW_DumpReg_To_Proc;
        prEntry->write_proc = CAMERA_HW_Reg_Debug2;
    }
    else {
        PK_ERR("add /proc/driver/camsensor2 entry fail \n");
    }
    atoMIC_set(&g_CamHWOpend, 0);
    //atomic_set(&g_CamHWOpend2, 0);
    atomic_set(&g_CamDrvOpenCnt, 0);
    //atomic_set(&g_CamDrvOpenCnt2, 0);
    atomic_set(&g_CamHWOpening, 0);
    return 0;
}
函数里通过 Platform_driver_register(&g_stCAMERA_HW_Driver)把 Camera 模块驱动注册 到 Platform 总线上。
而 g_stCAMERA_HW_Driver 是对结构体 Platform_driver 这个结构体的填充。
/////////////////////////////////      i2c_register_board_info   的解释
//i2c_board_info用于构建信息表来列出存在的I2C设备。这一信息用于增长新型I2C驱动的驱动模型树。对于主板,它使用i2c_register_board_info()来静态创建。对于子板,利用已知的适配器使用i2c_new_device()动态创建。
//I2C 设备创建模板
struct i2c_board_info {
    char type[I2C_NAME_SIZE];  //芯片类型,用于初始化i2c_CLIent.name
    unsigned short flags;  //用于初始化i2c_client.flags
    unsigned short addr;  //存储于i2c_client.addr
    void *platform_data;  //存储于i2c_client.dev.platform_data
    struct dev_archdata *archdata;  //拷贝至i2c_client.dev.archdata
    int irq;  //存储于i2c_client.irq
};
//使用linux I2C驱动栈,系统可以在初始化时宣告板载信息表。这些应该在靠近arch_initcall()时的板子相关的初始化代码或同等情况时,在I2C适配器驱动被注册之前被执行。例如,主板初始化代码可以定义//几个设备,也可以在叠板的每个子板初始化代码中定义。
//I2C设备会在相关的总线适配器被注册后创建。此后,标准驱动模型工具通常绑定新型I2C驱动至I2C设备。对于使用这一函数宣告的设备,在动态分配的情况下总线号是不可用的。
//传递的板子信息可以安全的是__initdata,但是由于不能拷贝,要小心嵌入式指针(如platform_data,functions等)
//静态的宣告I2C设备
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);
@busnum: 指定这些设备属于哪个总线
@info: I2C设备描述符向量
@len: 向量中描述符的数量;为了预留特定的总线号,可以是0。
在你对应的machine配置里会执行“i2c_register_board_info”一个函数,它会将一个i2c_board_info的结构体注册进系统,
可以发现,在目录/sys/bus/i2c/devices下的设备就是这个i2c_board_info结构体里所描述的I2C设备,
而/sys/bus/i2c/devices下的设备名字就是根据i2c_board_info结构体中定义的I2C Address来命名的。
所以添加一个I2C设备时,除了需要编写这个I2C设备的驱动之外,还需要在machine里面加入I2C设备的i2c_board_info内容。
/////////////////////////////////////////////////////////////////////
///////////////////////////////platform_driver_register   的解释
platform_driver_register()
是来注册设备的驱动程序
platform_device_register()
是来注册设备硬件,告诉kernel,当前有什么设备
当某个设备connect后,必须在device和driver的两条线上都有匹配的东西后,才算是匹配上,并且开始使用driver的probe等函数进行硬件初始化工作。
////////////////////////
//   (Kernel\include\linux\Platform_device.h)  
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,
    }
};

struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
static int CAMERA_HW_probe(struct platform_device *pdev)
{
    return i2c_add_driver(&CAMERA_HW_i2c_driver);
}
static int CAMERA_HW_remove(struct platform_device *pdev)
{
    i2c_del_driver(&CAMERA_HW_i2c_driver);
    return 0;
}
static int CAMERA_HW_suspend(struct platform_device *pdev, pm_message_t mesg)
{
    return 0;
}
static int CAMERA_HW_resume(struct platform_device *pdev)
{
    return 0;
}
b)  设备的注册:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
//kernel\arch\sh\boards\mach-ap325rxa\Setup.c
static struct platform_device ap325rxa_camera[] = {
{
.name        = "soc-camera-pdrv",
.id        = 0,
.dev        = {
.platform_data = &ov7725_link,
},
}, {
.name        = "soc-camera-pdrv",
.id        = 1,
.dev        = {
.platform_data = &camera_link,
},
},
};
static struct soc_camera_link camera_link = {
.bus_id        = 0,
.add_device        = ap325rxa_camera_add,
.del_device        = ap325rxa_camera_del,
.module_name        = "soc_camera_platform",
.priv        = &camera_info,
};

static int ap325rxa_camera_add(struct soc_camera_device *icd)
{
int ret = soc_camera_platform_add(icd, &camera_device, &camera_link,
ap325rxa_camera_release, 0);
if (ret < 0)
return ret;
ret = camera_probe();
if (ret < 0)
soc_camera_platform_del(icd, camera_device, &camera_link);
return ret;
}
static void ap325rxa_camera_del(struct soc_camera_device *icd)
{
soc_camera_platform_del(icd, camera_device, &camera_link);
}
static struct soc_camera_platform_info camera_info = {
.format_name = "UYVY",
.format_depth = 16,
.format = {
.code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.field = V4L2_FIELD_NONE,
.width = 640,
.height = 480,
},
.mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_DATA_ACTIVE_HIGH,
.mbus_type = V4L2_MBUS_PARALLEL,
.set_capture = camera_set_capture,
};

c)  总线的匹配:
既 然 是 驱 动  Platform_device  那 对 应 的 设 备 必 然 是 挂 载  Platform  总 线 上 的Platform_device,Platform 总线是 Linux 系统提供的一种机制,不同于 I2C、I2S 等总线,它 是一种虚拟的总线。
Linux 系统为 Platform 总线定义了一个 bus_type 的实例 Platform_bus_type:
//(Kernel\drivers\base\platform.c)
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
error = device_register(&platform_bus);
if (error)
return error;
error =  bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
struct bus_type platform_bus_type = {
.name        = "platform",
.dev_attrs        = platform_dev_attrs,
.match        = platform_match,
.uevent        = platform_uevent,
.pm        = &platform_dev_pm_ops,
};
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
Platform 总线通过 platform_match 这个成员函数来确定 platform_device 与 platform_driver 如何进行匹配:
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device        *pdev = to_platform_device(dev);
int rc;
/* Some devices have extra OF data and an OF-style MODALIAS */
rc = of_device_uevent_modalias(dev,env);
if (rc != -ENODEV)
return rc;
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
pdev->name);
return 0;
}
static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend,
.runtime_resume = pm_generic_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS
};
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
arch_setup_pdev_archdata(pdev);
return platform_device_add(pdev);
}
void platform_device_unregister(struct platform_device *pdev)
{
platform_device_del(pdev);
platform_device_put(pdev);
}

从上图可以清晰的了解到 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。
d)设备驱动
我们都知道,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 模块。
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,
};
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;
}
static int CAMERA_HW_i2c_remove(struct i2c_client *client)
{
    return 0;
}
static const struct i2c_device_id CAMERA_HW_i2c_id[] = {{CAMERA_HW_DRVNAME1,0},{}};
inline static int RegisterCAMERA_HWCharDrv(void)
{
    struct device* sensor_device = NULL;
#if CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO
    if( alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1,CAMERA_HW_DRVNAME1) )
    {
        PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");
        return -EAGAIN;
    }
#else
    if( register_chrdev_region(  g_CAMERA_HWdevno , 1 , CAMERA_HW_DRVNAME1) )
    {
        PK_DBG("[CAMERA SENSOR] Register device no failed\n");
        return -EAGAIN;
    }
#endif
    //Allocate driver
    g_pCAMERA_HW_CharDrv = cdev_alloc();
    if(NULL == g_pCAMERA_HW_CharDrv)
    {
        unregister_chrdev_region(g_CAMERA_HWdevno, 1);
        PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");
        return -ENOMEM;
    }
    //Attatch file operation.
    cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);
    g_pCAMERA_HW_CharDrv->owner = THIS_MODULE;
    //Add to system
    if(cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1))
    {
        PK_DBG("[MT6516_IDP] Attatch file operation failed\n");
        unregister_chrdev_region(g_CAMERA_HWdevno, 1);
        return -EAGAIN;
    }
    sensor_class = class_create(THIS_MODULE, "sensordrv");
    if (IS_ERR(sensor_class)) {
        int ret = PTR_ERR(sensor_class);
        PK_DBG("Unable to create class, err = %d\n", ret);
        return ret;
    }
    sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);
    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 等操作的接口:
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);
            //在 KdSetDriver()中通过判断 name 和 ID 匹配具体型号的 sensor 的驱动,判断它是主摄还 是次摄,并对它进行初始化:
            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 的驱动,判断它是主摄还 是次摄,并对它进行初始化:
if ( MAX_NUM_OF_SUPPORT_SENSOR > drvIdx ) {
            if (NULL == pSensorList[drvIdx].SensorInit) {
           PK_ERR("ERROR:kdSetDriver()\n");
           return -EIO;
       }
            pSensorList[drvIdx].SensorInit(&g_pInvokeSensorFunc);
            if (NULL == g_pInvokeSensorFunc) {
                PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n",i);
            return -EIO;
}

通过 NAME 和 ID 匹配完成后会将 PSENSOR_FUNCTION_STRUCT *pfFunc 这个结构体匹 配到具体型号的驱动代码中:
SENSOR_FUNCTION_STRUCT  SensorFuncOV5648mipi=
{
    OV5648MIPIOpen,
    OV5648MIPIGetInfo,
    OV5648MIPIGetResolution,
    OV5648MIPIFeatureControl,
    OV5648MIPIControl,
    OV5648MIPIClose
};
到这里,整个 Camera  驱动从总线注册到完成具体 sensor  的初始化的流程就完成了,CAMERA_HW_Ioctl()中其他的 ioctl 操作函数最后都会在$sensor$_sensor.c 中实现。
1、 修改系统配置文件 ProjectConfig.mk:
-alps\mediatek\config\$project$\ProjectConfig.mk
2、  检查、配置供电文件:
-alps\mediatek\custom\$project$\Kernel\Camera\Camera\kd_camera_hw.c
其实在 kd_camera_hw.c 中只有一个函数 kdCISModulePowerOn(),在这个 函数中需要注意的是通过 GPIO 口控制 PDN 和 RST 引脚的时候,对于其相关的
定义,由其在切换平台的时候。例如 MT6573 和 MT6575 的定义顺序就不同。

b)OV5647GetInfo
UINT32 OV5647GetInfo(MSDK_SCENARIO_ID_ENUM ScenarioId,
MSDK_SENSOR_INFO_STRUCT *pSensorInfo,
MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData)
第一个参数 ScenarioId 来自于 MSDK_SCENARIO_ID_ENUM 这个数组,在kd_imgsensor_define.h 中是这样定义的:
#define MSDK_SCENARIO_ID_ENUM        ACDK_SCENARIO_ID_ENUM
typedef enum
{
ACDK_SCENARIO_ID_CAMERA_PREVIEW=0,
ACDK_SCENARIO_ID_VIDEO_PREVIEW,
ACDK_SCENARIO_ID_VIDEO_CAPTURE_MPEG4,
ACDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG,
ACDK_SCENARIO_ID_CAMERA_CAPTURE_MEM,
ACDK_SCENARIO_ID_CAMERA_BURST_CAPTURE_JPEG,
ACDK_SCENARIO_ID_VIDEO_DECODE_MPEG4,
ACDK_SCENARIO_ID_VIDEO_DECODE_H263,
ACDK_SCENARIO_ID_VIDEO_DECODE_H264,
ACDK_SCENARIO_ID_VIDEO_DECODE_WMV78,
ACDK_SCENARIO_ID_VIDEO_DECODE_WMV9,
ACDK_SCENARIO_ID_VIDEO_DECODE_MPEG2,
ACDK_SCENARIO_ID_IMAGE_YUV2RGB,
ACDK_SCENARIO_ID_IMAGE_RESIZE,
ACDK_SCENARIO_ID_IMAGE_ROTATE,
ACDK_SCENARIO_ID_IMAGE_POST_PROCESS, ACDK_SCENARIO_ID_JPEG_RESIZE, ACDK_SCENARIO_ID_JPEG_DECODE, ACDK_SCENARIO_ID_JPEG_PARSE, ACDK_SCENARIO_ID_JPEG_ENCODE, ACDK_SCENARIO_ID_JPEG_ENCODE_THUMBNAIL, ACDK_SCENARIO_ID_DRIVER_IO_CONTROL, ACDK_SCENARIO_ID_DO_NOT_CARE, ACDK_SCENARIO_ID_IMAGE_DSPL_BUFFER_ALLOC, ACDK_SCENARIO_ID_TV_OUT, ACDK_SCENARIO_ID_MAX,
ACDK_SCENARIO_ID_VIDOE_ENCODE_WITHOUT_PREVIEW, ACDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG_BACK_PREVIEW, ACDK_SCENARIO_ID_VIDEO_DECODE_RV8, ACDK_SCENARIO_ID_VIDEO_DECODE_RV9, ACDK_SCENARIO_ID_CAMERA_ZSD,
} ACDK_SCENARIO_ID_ENUM;
通过这个数组定义 Camera 的各种模式,并且给他们从 0 开始给一个模拟的 ID,通过这个
ScenarioID 来控制 Camera 的工作模式是在拍照、摄像等等。
想要了解*pSensorInfo 这个指针的内容就得看 MSDK_SENSOR_INFO_STRUCT 的定义
#define MSDK_SENSOR_INFO_STRUCT ACDK_SENSOR_INFO_STRUCT typedef struct
{
MUINT16 SensorPreviewResolutionX;
MUINT16 SensorPreviewResolutionY;
MUINT16 SensorFullResolutionX;
MUINT16 SensorFullResolutionY;
MUINT8 SensorClockFreq;        /* MHz */
MUINT8 SensorCameraPreviewFrameRate;
MUINT8 SensorVideoFrameRate;
MUINT8 SensorStillCaptureFrameRate;
MUINT8 SensorWebCamCaptureFrameRate;
MUINT8        SensorClockPolarity;        /*
SENSOR_CLOCK_POLARITY_HIGH/SENSOR_CLOCK_POLARITY_Low */
MUINT8 SensorClockFallingPolarity;
MUINT8 SensorClockRisingCount;        /* 0..15 */
MUINT8 SensorClockFallingCount;        /* 0..15 */
MUINT8 SensorClockDividCount;        /* 0..15 */
MUINT8 SensorPixelClockCount;        /* 0..15 */
MUINT8 SensorDataLatchCount;        /* 0..15 */
MUINT8 SensorHsyncPolarity;
MUINT8 SensorVsyncPolarity;
MUINT8 SensorInterruptDelayLines;
MINT32        SensorResetActiveHigh;
MUINT32 SensorResetDelayCount;
ACDK_SENSOR_INTERFACE_TYPE_ENUM SensroInterfaceType;
ACDK_SENSOR_OUTPUT_DATA_FORMAT_ENUM SensorOutputDataFormat;
ACDK_SENSOR_MIPI_LANE_NUMBER_ENUM SensorMIPILaneNumber;
CAMERA_ISO_BINNING_INFO_STRUCT   SensorISOBinningInfo;
MUINT32 CaptureDelayFrame;
MUINT32 PreviewDelayFrame;
MUINT32 VideoDelayFrame;
MUINT16 SensorGrabStartX;
MUINT16 SensorGrabStartY;
MUINT16 SensorDrivingCurrent;
MUINT8        SensorMasterClockSwitch;
MUINT8        AEShutDelayFrame;        /* The frame of setting shutter default 0 for TG
int */
MUINT8        AESensorGainDelayFrame;        /* The frame of setting sensor gain */
MUINT8        AEISPGainDelayFrame;
MUINT8        MIPIDataLowPwr2HighSpeedTermDelayCount;
MUINT8        MIPIDataLowPwr2HighSpeedSettleDelayCount;
MUINT8        MIPICLKLowPwr2HighSpeedTermDelayCount;
MUINT8        SensorWidthSampling;
MUINT8        SensorHightSampling;
MUINT8        SensorPacketECCOrder;
MUINT8        SensorDriver3D;
} ACDK_SENSOR_INFO_STRUCT, *PACDK_SENSOR_INFO_STRUCT;
这个结构体列取了 Sensor 的时钟频率、预览时的帧率、行同步/帧同步频率等参数。
第三个参数*pSensorConfigData 同样根据 MSDK_SENSOR_CONFIG_STRUCT 结构体
#define MSDK_SENSOR_CONFIG_STRUCT ACDK_SENSOR_CONFIG_STRUCT typedef struct
{
ACDK_SENSOR_IMAGE_MIRROR_ENUM   SensorImageMirror;
MINT32 EnableShutterTansfer;        /* Capture 时的快门设置 */
MINT32 EnableFlashlightTansfer;        /*有闪光灯的 SensorCapture 时的快门设置*/
ACDK_SENSOR_OPERATION_MODE_ENUMSensorOperationMode;
MUINT16        ImageTargetWidth;        /* Capture 的图像宽度 */
MUINT16        ImageTargetHeight;        /* Capture 的图像高度*/
MUINT16        CaptureShutter;        /* Capture 时的快门设置 */
MUINT16        FlashlightDuty;        /*有闪光灯的 SensorCapture 时的快门设置*/
MUINT16        FlashlightOffset;        /*有闪光灯的 SensorCapture 时的快门设置*/
MUINT16        FlashlightShutFactor;        /*有闪光灯的 SensorCapture 时的快门设置*/
MUINT16        FlashlightMinShutter;        /*有闪光灯的 SensorCapture 时的快门设置*/
ACDK_CAMERA_OPERATION_MODE_ENUMMetaMode;
MUINT32        DefaultPclk;        // Sensor  默认的像素时钟频率(Ex:24000000)
MUINT32        Pixels;
MUINT32        Lines;
MUINT32        Shutter;
MUINT32        FrameLines;
} ACDK_SENSOR_CONFIG_STRUCT;
c)OV5647GetResolution
UINT32 OV5647GetResolution(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *pSensorResolution) 此函数只有一个参数*pSensorResolution,
找到结构体:MSDK_SENSOR_RESOLUTION_INFO_STRUCT
#define MSDK_SENSOR_RESOLUTION_INFO_STRUCT ACDK_SENSOR_RESOLUTION_INFO_STRUCT
typedef struct
{
MUINT16 SensorPreviewWidth; //预览时的图像宽度
MUINT16 SensorPreviewHeight; //预览时的图像高度
MUINT16 SensorFullWidth;
MUINT16 SensorFullHeight;
} ACDK_SENSOR_RESOLUTION_INFO_STRUCT, *PACDK_SENSOR_RESOLUTION_INFO_STRUCT;
到这里可以发现同样是获取 Sensor 的信息,GetInfo 函数获取并设置了 Sensor 所处的模式、设置好需要的各种时钟、快门和拍照获取图像的信息整个流程的参数,
而 GetResolution 函数却是设置图像在预览模式下的参数,实际上是通过对实际捕获的图像缩放来提高预览时图像的解析度。
d)OV5647FeatureControl
UINT32OV5647FeatureControl(MSDK_SENSOR_FEATURE_ENUM FeatureId,
UINT8        *pFeaturePara, UINT32        *pFeatureParaLen)
在 FeatureControl 这个函数中有三个参数:
#define        MSDK_SENSOR_FEATURE_ENUM
ACDK_SENSOR_FEATURE_ENUM typedef enum
{
SENSOR_FEATURE_BEGIN = SENSOR_FEATURE_START,
SENSOR_FEATURE_GET_RESOLUTION,
SENSOR_FEATURE_GET_PERIOD,
SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ,
SENSOR_FEATURE_SET_ESHUTTER,
SENSOR_FEATURE_SET_NIGHTMODE,
SENSOR_FEATURE_SET_GAIN,
SENSOR_FEATURE_SET_FLASHLIGHT,
SENSOR_FEATURE_SET_ISP_MASTER_CLOCK_FREQ,
SENSOR_FEATURE_SET_REGISTER,
SENSOR_FEATURE_GET_REGISTER,
SENSOR_FEATURE_SET_CCT_REGISTER,
SENSOR_FEATURE_GET_CCT_REGISTER,
SENSOR_FEATURE_SET_ENG_REGISTER,
SENSOR_FEATURE_GET_ENG_REGISTER,
SENSOR_FEATURE_GET_REGISTER_DEFAULT,
SENSOR_FEATURE_GET_CONFIG_PARA,
SENSOR_FEATURE_CAMERA_PARA_TO_SENSOR,
SENSOR_FEATURE_SENSOR_TO_CAMERA_PARA, SENSOR_FEATURE_GET_GROUP_COUNT, SENSOR_FEATURE_GET_GROUP_INFO, SENSOR_FEATURE_GET_ITEM_INFO, SENSOR_FEATURE_SET_ITEM_INFO, SENSOR_FEATURE_GET_ENG_INFO, SENSOR_FEATURE_GET_LENS_DRIVER_ID, SENSOR_FEATURE_SET_YUV_CMD, SENSOR_FEATURE_SET_VIDEO_MODE, SENSOR_FEATURE_SET_CALIBRATION_DATA, SENSOR_FEATURE_SET_SENSOR_SYNC, SENSOR_FEATURE_INITIALIZE_AF, SENSOR_FEATURE_CONSTant_AF, SENSOR_FEATURE_MOVE_FOCUS_LENS, SENSOR_FEATURE_GET_AF_STATUS, SENSOR_FEATURE_GET_AF_INF, SENSOR_FEATURE_GET_AF_MACRO, SENSOR_FEATURE_CHECK_SENSOR_ID, SENSOR_FEATURE_SET_AUTO_FLICKER_MODE, SENSOR_FEATURE_SET_TEST_PATTERN, SENSOR_FEATURE_SET_SOFTWARE_PWDN, SENSOR_FEATURE_SINGLE_FOCUS_MODE, SENSOR_FEATURE_CANCEL_AF, SENSOR_FEATURE_SET_AF_WINDOW, SENSOR_FEATURE_GET_EV_AWB_REF, SENSOR_FEATURE_GET_SHUTTER_GAIN_AWB_GAIN, SENSOR_FEATURE_MAX
} ACDK_SENSOR_FEATURE_ENUM;
FeatureId 这个参数提供了低层给上层接口的准备。*pFeaturePara 和*pFeatureParaLen 分别是 FeatureId 的具体值。

请教一下小编,怎么和Linux的v4l2挂上的呢?

TKS for share

_________________NB

NB

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top