【Camera专题】高通-Camera多模组兼容方案

2019-09-18  本文已影响0人  c枫_撸码的日子

一、需求

工作中,经常遇到这样的需求:

这时候,效果的同事需要做针对不同模组厂同一颗sensor进行效果调试。效果参数是2份,即做兼容!

如果你只兼容2个模组厂生产的同一颗sensor,那么直接让2家模组厂区分sensor_id就可以了!
然后驱动代码搞2份,sensor_id和效果文件区别一下就行了!

但是如果有3家甚至更多的模组厂呢,就无法根据sensor_id来区分了,因为sensor_id的地址只能是2个!
(ps:为啥sensor_id只有2个地址:
你看一下sensor规格书就知道了。sensor_id的地址是由硬件上某根线接高或者接地决定的。
以s5k4h7为例子,如果接地了,sensor_id为0x20,接电源,sensor_id为0x5A。)

怎么办呢?

还记得OTP的知识吗?

OTP烧录的数据类型
一般包括:

兼容方案小结

二、兼容方案的实现

我们让模组厂把sensor_id弄成相同,这样方便otp数据读取!
module_id不同,方便进行驱动的兼容!

1.原理分析

kernel/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c

int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
{
    int rc = 0;
    uint16_t chipid = 0;
    struct msm_camera_i2c_client *sensor_i2c_client;
    struct msm_camera_slave_info *slave_info;
    const char *sensor_name;

    if (!s_ctrl) {
        pr_err("%s:%d failed: %pK\n",
            __func__, __LINE__, s_ctrl);
        return -EINVAL;
    }    
    sensor_i2c_client = s_ctrl->sensor_i2c_client;
    slave_info = s_ctrl->sensordata->slave_info;
    sensor_name = s_ctrl->sensordata->sensor_name;

    if (!sensor_i2c_client || !slave_info || !sensor_name) {
        pr_err("%s:%d failed: %pK %pK %pK\n",
            __func__, __LINE__, sensor_i2c_client, slave_info,
            sensor_name);
        return -EINVAL;
    }    

    rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
        sensor_i2c_client, slave_info->sensor_id_reg_addr,
        &chipid, MSM_CAMERA_I2C_WORD_DATA);
    if (rc < 0) { 
        pr_err("%s: %s: read id failed\n", __func__, sensor_name);
        return rc;
    }

    pr_err("%s: read id: 0x%x expected id 0x%x:\n",
            __func__, chipid, slave_info->sensor_id);
    if (msm_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) {
        pr_err("%s chip id %x does not match %x\n",
                __func__, chipid, slave_info->sensor_id);
        return -ENODEV;
    }
    return rc;
}

我们来看msm_sensor_match_id这个函数,逻辑很简单。

思考:
既然这个函数,通过比较sensor_id是否相同,来匹配驱动!
那么我们一样可以在这里比较module_id是否相同,来匹配驱动!

需要注意的地方:
sensor_id的读取,可以直接通过一个i2c_read函数就轻松读到!
module_id的读取,稍微复杂些,要遵守OTP数据的读写规范!

2.具体实现

sensor:s5k4h7
模组厂:丘钛、信利
模组id:丘钛烧录值为0x1、信利烧录值为0x2

2.1 OTP读写规则


2.2 module_id的地址

2.3 函数的封装与实现
static int read_module_id( uint_16 *module_id ,const char *sensor_name ,struct msm_camera_i2c_client *sensor_i2c_client;)
{ 
    int rc = 0;
    //如果sensor是s5k4h7,模组厂是丘钛或者信利
    if(!strcmp(sensor_name, "s5k4h7_qiutai") || !strcmp(sensor_name, "s5k4h7_truly")){
       /*set the page21 of otp*/
        sensor_i2c_client->i2c_func_tbl->i2c_write(sensor_i2c_client, 0x0A02,
        0x15, MSM_CAMERA_I2C_BYTE_DATA);
        if (rc < 0) {
            pr_err("%s: %s: write 0x0A02  failed\n", __func__, sensor_name);
            return rc;
        }
        /*OTP enable and read start*/
        sensor_i2c_client->i2c_func_tbl->i2c_write(sensor_i2c_client, 0x0A00,
        0x0100, MSM_CAMERA_I2C_WORD_DATA);
        if (rc < 0) {
            pr_err("%s: %s: write 0x0A00failed\n", __func__, sensor_name);
            return rc;
        }
        /*读取0x0A05寄存器的值并保持到变量module_id 中*/
        sensor_i2c_client->i2c_func_tbl->i2c_read(sensor_i2c_client, 0x0A05,
                module_id , MSM_CAMERA_I2C_BYTE_DATA);
        if (rc < 0) {
            pr_err("%s: %s: read 0x0A05failed\n", __func__, sensor_name);
            return rc;
        }
    }

    //如果你想兼容其他sensor,可以继续添加

    return rc;
}

2.4 调用read_module_id

kernel/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c

int msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
{
···
++  int module_id = -1;
···
    sensor_i2c_client = s_ctrl->sensor_i2c_client;
    slave_info = s_ctrl->sensordata->slave_info;
    sensor_name = s_ctrl->sensordata->sensor_name;

    if (!sensor_i2c_client || !slave_info || !sensor_name) {
        pr_err("%s:%d failed: %pK %pK %pK\n",
            __func__, __LINE__, sensor_i2c_client, slave_info,
            sensor_name);
        return -EINVAL;
    }    

    rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
        sensor_i2c_client, slave_info->sensor_id_reg_addr,
        &chipid, MSM_CAMERA_I2C_WORD_DATA);
    if (rc < 0) { 
        pr_err("%s: %s: read id failed\n", __func__, sensor_name);
        return rc;
    }

    pr_err("%s: read id: 0x%x expected id 0x%x:\n",
            __func__, chipid, slave_info->sensor_id);
    if (msm_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) {
        pr_err("%s chip id %x does not match %x\n",
                __func__, chipid, slave_info->sensor_id);
        return -ENODEV;
    }

//read id成之后,继续比较module_id
++++++++++++++++++++
    rc = read_module_id(&module_id ,sensor_name ,sensor_i2c_client );
    if (rc < 0) { 
        pr_err("%s: %s: read module_id failed\n", __func__, sensor_name);
        return rc;
    }

    //如果加载到的是 丘钛 的驱动代码
    if(!strcmp(sensor_name, "s5k4h7_qiutai")) {
        if(module_id == 0x1) {//判断module_id 是否为0x1
            //丘钛 sensor 匹配上了丘钛 的驱动代码
            pr_err("%s: %s: module_id = 0x1,it is qiutai sensor\n", __func__, sensor_name);
            return rc;//直接返回成功
        }else {
             pr_err("%s: %s: module_id != 0x1,it not't qiutai sensor\n", __func__, sensor_name);
            return -ENODEV;//模组id不匹配,直接返回失败
      }
    }
    //如果加载到的是 信利 的驱动代码
    if(!strcmp(sensor_name, "s5k4h7_truly")) {
        if(module_id == 0x2) {//判断module_id 是否为0x2
            //信利sensor 匹配上了信利的驱动代码
            pr_err("%s: %s: module_id = 0x1,it is truly sensor\n", __func__, sensor_name);
            return rc;//直接返回成功
        }else {
             pr_err("%s: %s: module_id != 0x1,it not't truly sensor\n", __func__, sensor_name);
            return -ENODEV;//模组id不匹配,直接返回失败
      }
    }
++++++++++++++++++++
    return rc;
}

到这里,我们的兼容就ok了,剩下的就是驱动代码和效果代码提供2份了!

2.5 驱动代码的修改

s5k4h7_qiutai.c


#define SENSOR_MODEL_NO_S5K4H7 "s5k4h7_qiutai"
//区分效果文件
#define S5K4H7_LOAD_CHROMATIX(n) \
  "libchromatix_"SENSOR_MODEL_NO_S5K4H7"_"#n".so"

//这里只有sensor_name 不同,slave_addr 都是0x5A
static struct msm_camera_sensor_slave_info sensor_slave_info = {
  .i2c_freq_mode = I2C_FAST_MODE,
  .sensor_name = "s5k4h7_qiutai",
  /* Camera slot where this camera is mounted */
  .camera_id = CAMERA_0,
  /* sensor slave address */
  .slave_addr = 0x5A, //0x20
···
}

s5k4h7_truly.c


#define SENSOR_MODEL_NO_S5K4H7 "s5k4h7_truly"
//区分效果文件
#define S5K4H7_LOAD_CHROMATIX(n) \
  "libchromatix_"SENSOR_MODEL_NO_S5K4H7"_"#n".so"

//这里只有sensor_name 不同,slave_addr 都是0x5A
static struct msm_camera_sensor_slave_info sensor_slave_info = {
  .i2c_freq_mode = I2C_FAST_MODE,
  .sensor_name = "s5k4h7_truly",
  /* Camera slot where this camera is mounted */
  .camera_id = CAMERA_0,
  /* sensor slave address */
  .slave_addr = 0x5A, //0x20
···
}

3.结语

之前问过高通的工程师,他们居然不知道怎么兼容!!!
其实也不复杂,只能说做的工作不一样吧!
兼容方案虽然简单,贵在思考!

继续当一名咸鱼(* ̄︶ ̄)!

Stay Hungry,Stay Foolish!

上一篇下一篇

猜你喜欢

热点阅读