背景知识
OTP 基本概念
Camera Module一般会采取两种方式来记录该Sensor的一些信息,一种是OTP(One Time Programmable),另外一种是EEPROM (Electrically Erasable Programmable Read - Only Memory)。
OTP存储器的类型
- OTP数据烧录在sensor的寄存器中。
- OTP数据烧录在EEPROM中:EEPROM是指带电可擦可编程只读存储器,是一种掉电后数据不丢失的存储芯片。
OTP的作用
保证效果一致性, 模组厂会挑选一部分模组作为golden,然后将其他模组的相应参数校准到和这些golden一样
OTP的数据
OTP烧录的数据类型 一般包括:
AF:自动对焦校准数据
AWB:白平衡校准数据
LSC:镜头阴影校准 (Lens Shading Calibration)
Moudle Info:模组信息,包含模组的生产年月日,模组ID等
兼容的思路
利用OTP中的module info 来区分不同的模组
举例 OTP烧录在sensor寄存器
- sensor 寄存器说明
2. OTP 读写规则
3. OTP读写 参考
进行兼容
利用读出的OTP数据中的module info 进行区分
\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;
uint16_t module_id = -1;
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("LIWANCHAO %s: %s: read id failed\n", __func__, sensor_name);
return rc;
}
pr_err("LIWANCHAO,%s: line = %d,%s,read id: 0x%x expected id 0x%x:\n",
__func__, __LINE__,sensor_name, chipid, slave_info->sensor_id);
//add by liwanchao satrt
if(!strcmp(sensor_name, "ov5675_truly") || !strcmp(sensor_name, "ov5675_back"))
{
pr_err("LIWANCHAO,%s,%d,%s,\n",__func__,__LINE__,sensor_name);
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x0100,
0x01, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x5001,
0x02, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d84,
0xc0, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d88,
0x70, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d89,
0x10, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otP_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d8a,
0x72, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d8b,
0x0e, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d81,
0x01, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
sensor_i2c_client, 0x7011,
&module_id, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0)
{
pr_err("%s: %s: read module_id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x5001,
0x0a, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x0100,
0x00, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
}
/*pr_err("LIWANCHAO module_id = 0x%x\n", module_id );
if( module_id == 0x4)//gz
{
chipid = 0x5675;
pr_err("this is gz,module_id = 0x%x,\n", module_id );
}
else if( module_id == 0x2 )//truly
{
chipid += 1;
pr_err("this is truly,module_id = 0x%x,\n", module_id );
}*/
if(!strcmp(sensor_name, "ov8856_i18") || !strcmp(sensor_name, "ov8856_i18_truly"))
{
pr_err("LIWANCHAO,%s,%d,%s,\n",__func__,__LINE__,sensor_name);
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x0100,
0x01, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x5001,
0x02, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d84,
0xc0, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d88,
0x70, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d89,
0x10, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otP_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d8a,
0x72, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d8b,
0x0a, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x3d81,
0x01, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_read(
sensor_i2c_client, 0x7011,
&module_id, MSM_CAMERA_I2C_BYTE_DATA);//在这里通过读取寄存器0x7011的值,把读取到的值放到module_id里面,通过查看otp map,可以知道这个地址是用来存module_id的。
if (rc < 0)
{
pr_err("%s: %s: read module_id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x5001,
0x0a, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
rc = sensor_i2c_client->i2c_func_tbl->i2c_write(
sensor_i2c_client, 0x0100,
0x00, MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
pr_err("%s: %s: otp_read id failed\n", __func__, sensor_name);
return rc;
}
}
pr_err("LIWANCHAO module_id = 0x%x\n", module_id );
if( module_id == 0x4)//gz
{
if(chipid == 0x885a)//后摄
{
pr_err("this is ov8856 gz,module_id = 0x%x,\n", module_id );
}
else if(chipid == 0x5675 )//前摄
{
pr_err("this is ov5675 gz,module_id = 0x%x,\n", module_id );
}
}
else if( module_id == 0x2 )//truly
{
if(chipid == 0x885a)//后摄
{
chipid += 1;
pr_err("this is ov8856 truly,module_id = 0x%x,\n", module_id );
}
else if(chipid == 0x5675 )//前摄
{
chipid += 1;
pr_err("this is ov5675 truly,module_id = 0x%x,\n", module_id );
}
}
//add by liwanchao end
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;
}
总结
利用OTP兼容 第一个要能够根据读出OTP数据。 第二个是要跟模组厂沟通好 有唯一性的数据来进行区分