包含寄存器地址和PAGE详细信息,以利于供应商核对otp信息kernel\msm-3.18\drivers\media\platform\msm\camera_v2\sensor\eeprom\msm_eeprom.c +msm_eeprom_platform_probe +1728int i,page = 5;*********************以下读取Module info && awb 数据*********************for (j = 0; j < e_ctrl->cal_data.num_data; j++)CDBG("memory_data[%d] = address[0x%x] = 0x%X\n", j, (0x0A04+j),e_ctrl->cal_data.mapdata[j]);*********************以下读取 LSC 数据*********************#define START_ADDRESS_OTP 0x0A28#define START_OTP_YUEQIU 0x0A04#define END_OTP_YUEQIU (0x0A43 + 1)//int i,page = 5;i = START_ADDRESS_OTP;for (j = 0; j < e_ctrl->cal_data.num_data; j++, i++){if(END_OTP_YUEQIU == i){i = START_OTP_YUEQIU;printk("PAGE %d\n", page++);}CDBG("memory_data[%d] = address[0x%x] = 0x%X\n", j, i,e_ctrl->cal_data.mapdata[j]);}/*******打印整个群晖摄像头s5k5e8 otp 数据*********/static int dump_memory;int i, page = 5;#define START_ADDRESS_OTP 0x0a04#define START_OTP_YUEQIU 0x0a04#define END_OTP_YUEQIU (0x0a43 + 1)printk("PAGE 4\n");i = START_ADDRESS_OTP;dump_memory++;if(3 == dump_memory){for (j = 0; j < e_ctrl->cal_data.num_data; j++, i++){if(END_OTP_YUEQIU == i){i = START_OTP_YUEQIU;printk("PAGE %d\n", page++);}printk("memory_data[%d] = address[0x%x] = 0x%X\n", j, i,e_ctrl->cal_data.mapdata[j]);}}
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/libs/qunhui_s5k5e8/qunhui_s5k5e8_eeprom.c/*============================================================================Copyright (c) Qualcomm Technologies, Inc. All Rights Reserved.Qualcomm Technologies Proprietary and Confidential.============================================================================*/#include <stdio.h>#include <string.h>#include <utils/Log.h>#include "../eeprom_util/eeprom.h"#include "eeprom_lib.h"#include "eeprom_util.h"#include "debug_lib.h"#include "sensor_lib.h"#include "actuator_driver.h"#undef CDBG#define EEPROM_DEBUG#ifdef EEPROM_DEBUG#define CDBG(fmt, args...) \ALOGE("s5k5e8_eeprom %s:%d "fmt"\n", __func__, __LINE__, ##args)#else#define CDBG(fmt, args...) do{}while(0)#endif#define AWB_REG_SIZE 8 //手册里面此部分寄存器有8个#define OTP_VALID1 #define OTP_INVALID 0#define GAIN_GREEN1_ADDR 0x020E //这部分寄存器的值问供应商提供,或者手册里有#define GAIN_BLUE_ADDR0x0212#define GAIN_RED_ADDR 0x0210#define GAIN_GREEN2_ADDR 0x0214#define RG_TYPICAL_QUNHUI0x8B //经典值,可以从芯片寄存器里读取,因为是固定的,也可以自己指定#define BG_TYPICAL_QUNHUI0x7D#define QUNHUI_MODULE_ID 0x44 #define PRIMAX_S5K5E8_OTP_DEBUG struct otp_struct {uint16_t module_integrator_id; uint16_t production_year;uint16_t production_month;uint16_t production_day;uint16_t lens_id;uint16_t vcm_id;uint16_t R_Gr_ratio;uint16_t B_Gr_ratio;} otp;static uint16_t rg_typical, bg_typical = 0;static uint16_t use_group = 1;static uint16_t lsc_info[360];//数组大小的计算千万小心仔细,很容易算错,这个数组是回写 sensor 寄存器//camera_i2c_reg_array 属于 camera_i2c_reg_setting 元素struct camera_i2c_reg_array g_reg_array[AWB_REG_SIZE + 144*6 + 2 + 1];struct camera_i2c_reg_setting g_reg_setting;/** qunhui_s5k5e8_get_calibration_items:* @e_ctrl: point to sensor_eeprom_data_t of the eeprom device** Get calibration capabilities and mode items.** This function executes in eeprom module context** Return: void.**/static void qunhui_s5k5e8_get_calibration_items(void *e_ctrl){sensor_eeprom_data_t *ectrl = (sensor_eeprom_data_t *)e_ctrl;eeprom_calib_items_t *e_items = &(ectrl->eeprom_data.items);//is_insensor 如果传感器模块本身支持EEPROM配置,则将此标记设置为TRUE。外部EEPROM均不可用e_items->is_insensor = TRUE;//如果支持AF校准,将此标记设置为TRUEe_items->is_afc = FALSE;//摄像头因为没有对焦功能,所以这个标志位无关紧要//如果支持白平衡校准,将此标记设置为TRUEe_items->is_wbc = FALSE;//摄像头本身支持白平衡校准,就设置为 false//如果支持镜头阴影校准,将此标记设置为TRUEe_items->is_lsc = FALSE;//摄像头本身支持LSC校准,就设置为 false}//叫供应商提供以下函数void qunhui_s5k5e8_awb_updata(uint16_t r_gain,uint16_t b_gain){float R_ration=(float)rg_typical/(float)r_gain;float B_ration=(float)bg_typical/(float)b_gain;uint16_t G_gain,R_gain,B_gain;uint16_t gain_default=0x0100;if (R_ration>=1){if (B_ration>=1){G_gain=gain_default ;R_gain=gain_default*R_ration;B_gain=gain_default*B_ration;}else{B_gain=gain_default;G_gain=gain_default/B_ration;R_gain=gain_default*R_ration/B_ration;}}else{if (B_ration>=1){R_gain=gain_default;G_gain=gain_default/R_ration;B_gain=gain_default*B_ration/R_ration;}else if (R_ration>=B_ration){B_gain=gain_default;G_gain=gain_default/B_ration;R_gain=gain_default*R_ration/B_ration;}else{R_gain=gain_default;G_gain=gain_default/R_ration;B_gain=gain_default*B_ration/R_ration;}}g_reg_array[g_reg_setting.size].reg_addr = GAIN_GREEN1_ADDR;g_reg_array[g_reg_setting.size].reg_data = G_gain >> 8;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_GREEN1_ADDR+1;g_reg_array[g_reg_setting.size].reg_data = G_gain & 0x00ff;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_RED_ADDR;g_reg_array[g_reg_setting.size].reg_data = R_gain >> 8;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_RED_ADDR+1;g_reg_array[g_reg_setting.size].reg_data = R_gain & 0x00ff;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_BLUE_ADDR;g_reg_array[g_reg_setting.size].reg_data = B_gain >> 8;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_BLUE_ADDR+1;g_reg_array[g_reg_setting.size].reg_data = B_gain & 0x00ff;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_GREEN2_ADDR;g_reg_array[g_reg_setting.size].reg_data = G_gain >> 8;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = GAIN_GREEN2_ADDR+1;g_reg_array[g_reg_setting.size].reg_data = G_gain & 0x00ff;g_reg_setting.size++;}//供应商提供的解码函数// I2CMODE_MICRON2 (16 Bit Address,8 Bit Data)/************************************************************************//* 解码OTP至SRAM格式 *//************************************************************************/void DePrOTPLSCData_5E8(uint16_t *OTPBuff, uint16_t *SRAMBuff){int i = 0, j=0;for(i = 0; i < 360; i++)ALOGE("OTPBuff[%d]: %d \n", i, OTPBuff[i]);for (i=0; i<360; i=i+5){SRAMBuff[j++] = (OTPBuff[i] & 0xf0) >>4;SRAMBuff[j++] = ((OTPBuff[i] & 0x0f) <<4) | ((OTPBuff[i+1] & 0xf0) >>4);SRAMBuff[j++] = ((OTPBuff[i+1] & 0x0f) <<4) | ((OTPBuff[i+2] & 0xf0) >>4);SRAMBuff[j++] = OTPBuff[i+2] & 0x0f;SRAMBuff[j++] = OTPBuff[i+3];SRAMBuff[j++] = OTPBuff[i+4];}}/************************************************************************//* 加载SRAM到 Sensor *//************************************************************************/void ApplyLSC(void){uint16_t sramBuff[432];int counter = 0x00;int i;DePrOTPLSCData_5E8(lsc_info, sramBuff);/* 起初这个是没有注释掉的,导致摄像头报错:media server died, camera closed应该是和 xxx_lib.h 里面重复掉了 0x0100 是流控制寄存器,写1:stream 写0:software standbyg_reg_array[g_reg_setting.size].reg_addr = 0x0100;g_reg_array[g_reg_setting.size].reg_data = 0x01;g_reg_setting.size++;*//* LSC 自动加载控制寄存器,写00:自动加载 写1:不是自动加载*/g_reg_array[g_reg_setting.size].reg_addr = 0x3400;g_reg_array[g_reg_setting.size].reg_data = 0x00;g_reg_setting.size++;//寄存器[3]: seed date update start enable//寄存器[2]: gain caculate start enable//寄存器[1]:gain caculate auto-start enableg_reg_array[g_reg_setting.size].reg_addr = 0x3457;g_reg_array[g_reg_setting.size].reg_data = 0x04;g_reg_setting.size++;/* //bFX2WriteSensor(nI2C, 0x0100,0x00, I2CMODE_STMICRO);//bFX2WriteSensor(nI2C, 0x3400,0x00, I2CMODE_STMICRO);//Sleep(100);// 这个寄存器三星没有开放,三星建议,不要设置g_reg_array[g_reg_setting.size].reg_addr = 0x3b4c;g_reg_array[g_reg_setting.size].reg_data = 0x00;g_reg_setting.size++;//bFX2WriteSensor(nI2C, 0x3457,0x04, I2CMODE_STMICRO);//bFX2WriteSensor(nI2C, 0x3b4c,0x00, I2CMODE_STMICRO);*/for(i = 0; i < 432; i++)ALOGE("sramBuff[%d]: %d \n", i, sramBuff[i]);for (i=0; i<432; ){/*0x3415 [7:4]Reserved R [3:0] GAS_write_data[19:16]0x3416 [7:0]GAS_write_data[15:8]0x3417 [7:0]GAS_write_data[7:0]0x3418 [7:0]GAS_address0x3419 [7:4]Reserved [3:0]GAS_command 4=write 8=read*/g_reg_array[g_reg_setting.size].reg_addr = 0x3419;g_reg_array[g_reg_setting.size].reg_data = 0x00;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = 0x3415;g_reg_array[g_reg_setting.size].reg_data = sramBuff[i];g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = 0x3416;g_reg_array[g_reg_setting.size].reg_data = sramBuff[i + 1];g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = 0x3417;g_reg_array[g_reg_setting.size].reg_data = sramBuff[i + 2];g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = 0x3418;g_reg_array[g_reg_setting.size].reg_data = counter++;g_reg_setting.size++;g_reg_array[g_reg_setting.size].reg_addr = 0x3419;g_reg_array[g_reg_setting.size].reg_data = 0x04;g_reg_setting.size++;i=i+3;}//bFX2WriteSensor(nI2C, 0x3457,0x0C, I2CMODE_STMICRO);//bFX2WriteSensor(nI2C, 0x0100,0x01, I2CMODE_STMICRO);g_reg_array[g_reg_setting.size].reg_addr = 0x3457;g_reg_array[g_reg_setting.size].reg_data = 0x0c;g_reg_setting.size++;/*g_reg_array[g_reg_setting.size].reg_addr = 0x0100;g_reg_array[g_reg_setting.size].reg_data = 0x00;g_reg_setting.size++;*/}void qunhui_s5k5e8_calib_sensor(sensor_eeprom_data_t *e_ctrl){CDBG("[S5K5E8OTP] Enter %s", __func__);/*****************************注* 先判断Group2 Flag是否为 1 ? {如果为1 即读取Group2 数据}, {不为1则读取Group1数据}*****************************/unsigned int base=0, i;unsigned int awb_base=16;unsigned int lsc_base=16;unsigned int uiInformation_Group = 0;unsigned int uiAWB_Group = 0;unsigned int uiLSC_Group = 0;#define INFORMATION_GROUP_OFFSET 8#define AWB_GROUP_OFFSET 10#define LSC_GROUP_OFFSET 362/************ Information *****************/if (e_ctrl->eeprom_params.buffer[0 + INFORMATION_GROUP_OFFSET] == 0x01) {uiInformation_Group = 2;base = 8;ALOGE("qunhui s5k5e8_eeprom MODULE ID use group 2 \n");}else if (e_ctrl->eeprom_params.buffer[0] == 0x01) {uiInformation_Group = 1;base = 0;ALOGE("qunhui s5k5e8_eeprom MODULE ID use group 1 \n");}else {uiInformation_Group = 0;ALOGE("qunhui s5k5e8_eeprom MODULE ID error: %s:%d \n", __func__, __LINE__);}/************ AWB *****************/if (e_ctrl->eeprom_params.buffer[16 + AWB_GROUP_OFFSET] == 0x01) {uiAWB_Group = 2;awb_base = 8 + 8 + 10 + 1;ALOGE("qunhui s5k5e8_eeprom awb use group 2 \n");}else if (e_ctrl->eeprom_params.buffer[16] == 0x01){uiAWB_Group = 1;awb_base = 16 + 1;ALOGE("qunhui s5k5e8_eeprom awb use group 1 \n");}else {uiAWB_Group = 0;ALOGE("qunhui s5k5e8_eeprom AWB error: %s:%d \n", __func__, __LINE__);}/************ LSC *****************/if (e_ctrl->eeprom_params.buffer[36 + LSC_GROUP_OFFSET] == 0x01) {//****** Page 10 addressuiLSC_Group = 2;lsc_base = 36 + 362 + 1;//计算开始地址要小心,和下面的读取拷贝要一致ALOGE("qunhui s5k5e8_eeprom lsc use group 2 \n");}else if (e_ctrl->eeprom_params.buffer[36] == 0x01) {//****** Page 4 addressuiLSC_Group = 1;lsc_base = 36 + 1;ALOGE("qunhui s5k5e8_eeprom lsc use group 1 \n");}else {uiLSC_Group = 0;ALOGE("qunhui s5k5e8_eeprom LSC error: %s:%d \n", __func__, __LINE__);}//int flg_otp_lsc = 1;//int i=0;CDBG("grop flag = 0x%x otp.module_id= 0x%x\n",e_ctrl->eeprom_params.buffer[base], e_ctrl->eeprom_params.buffer[base+1] & 0x1f);otp.module_integrator_id = e_ctrl->eeprom_params.buffer[base+1] & 0x1f;otp.lens_id = e_ctrl->eeprom_params.buffer[base+2];otp.vcm_id= e_ctrl->eeprom_params.buffer[base+3];otp.production_year = e_ctrl->eeprom_params.buffer[base+4];otp.production_month = e_ctrl->eeprom_params.buffer[base+5];otp.production_day = e_ctrl->eeprom_params.buffer[base+6];otp.R_Gr_ratio = (e_ctrl->eeprom_params.buffer[awb_base]) | (e_ctrl->eeprom_params.buffer[awb_base + 1] << 8);otp.B_Gr_ratio = (e_ctrl->eeprom_params.buffer[awb_base + 2]) | (e_ctrl->eeprom_params.buffer[awb_base + 3] << 8);rg_typical = (e_ctrl->eeprom_params.buffer[awb_base + 4]) | (e_ctrl->eeprom_params.buffer[awb_base + 5] << 8);bg_typical = (e_ctrl->eeprom_params.buffer[awb_base + 6]) | (e_ctrl->eeprom_params.buffer[awb_base + 7] << 8);//flg_otp_lsc = OTP_VALID;CDBG("[S5K5E8OTP] otp.module_integrator_id= 0x%x\n", otp.module_integrator_id);CDBG("[S5K5E8OTP] otp.lens_id= 0x%x\n", otp.vcm_id);CDBG("[S5K5E8OTP] otp.R_Gr_ratio= 0x%x\n", otp.R_Gr_ratio);CDBG("[S5K5E8OTP] otp.B_Gr_ratio= 0x%x\n", otp.B_Gr_ratio);CDBG("[S5K5E8OTP] rg_typical= 0x%x\n", rg_typical);CDBG("[S5K5E8OTP] bg_typical= 0x%x\n", bg_typical);if(otp.R_Gr_ratio == 0 || otp.B_Gr_ratio == 0){CDBG("[S5K5E8OTP] module OTP wb data unvalid !\n");return ;}qunhui_s5k5e8_awb_updata(otp.R_Gr_ratio,otp.B_Gr_ratio);//memcpy 用起来要小心,源数据的数据类型和目的地址的数据类型要千万注意,还有要拷贝的字节数要写正确,不要自己写数字,不然,很容易出现拷贝不全//memcpy(lsc_info, &e_ctrl->eeprom_params.buffer[lsc_base], 360);for(i = 0; i < 360; i++)lsc_info[i] = e_ctrl->eeprom_params.buffer[lsc_base + i];//和前面的开始地址要一致ApplyLSC();//qunhui_s5k5e8_lsc_updata(flg_otp_lsc);}/** qunhui_s5k5e8_format_calibration_data:* @e_ctrl: point to sensor_eeprom_data_t of the eeprom device** Format all the data structure of calibration** This function executes in eeprom module context and generate* all the calibration registers setting of the sensor.** Return: void.**/void qunhui_s5k5e8_format_calibration_data(void *e_ctrl) {CDBG("Enter %s", __func__);sensor_eeprom_data_t *ectrl = (sensor_eeprom_data_t *)e_ctrl;g_reg_setting.addr_type = CAMERA_I2C_WORD_ADDR;g_reg_setting.data_type = CAMERA_I2C_BYTE_DATA;g_reg_setting.reg_setting = &g_reg_array[0];g_reg_setting.size = 0;g_reg_setting.delay = 0;qunhui_s5k5e8_calib_sensor(ectrl);CDBG("Exit %s", __func__);}/** qunhui_s5k5e8_get_raw_data:* @e_ctrl: point to sensor_eeprom_data_t of the eeprom device* @data: point to the destination msm_camera_i2c_reg_setting** Get the all the calibration registers setting of the sensor** This function executes in eeprom module context.** Return: void.**/static int qunhui_s5k5e8_get_raw_data(void *e_ctrl, void *data) {if (e_ctrl && data)memcpy(data, &g_reg_setting, sizeof(g_reg_setting));elseCDBG("failed Null pointer");return 0;}static eeprom_lib_func_t qunhui_s5k5e8_lib_func_ptr = {.get_calibration_items = qunhui_s5k5e8_get_calibration_items,.format_calibration_data = qunhui_s5k5e8_format_calibration_data,.do_af_calibration = NULL,.do_wbc_calibration = NULL,.do_lsc_calibration = NULL,.get_raw_data = qunhui_s5k5e8_get_raw_data,//以下的上下电没有用到,因为在kernel 的dtsi 文件里面已经配置了上下电.eeprom_info ={.power_setting_array ={.power_setting_a ={{.seq_type = CAMERA_POW_SEQ_GPIO,.seq_val = CAMERA_GPIO_RESET,.config_val = GPIO_OUT_LOW,.delay = 1,},{.seq_type = CAMERA_POW_SEQ_GPIO,.seq_val = CAMERA_GPIO_VANA,.config_val = GPIO_OUT_HIGH,.delay = 1,},{.seq_type = CAMERA_POW_SEQ_VREG,.seq_val = CAMERA_VDIG,.config_val = 1,.delay = 1,},{.seq_type = CAMERA_POW_SEQ_VREG,.seq_val = CAMERA_VIO,.config_val = 1,.delay = 0,},/*{.seq_type = CAMERA_POW_SEQ_VREG,.seq_val = CAMERA_VAF,.config_val = 1,.delay = 5,},*/{.seq_type = CAMERA_POW_SEQ_CLK,.seq_val = CAMERA_MCLK,.config_val = 24000000,.delay = 1,},{.seq_type = CAMERA_POW_SEQ_GPIO,.seq_val = CAMERA_GPIO_RESET,.config_val = GPIO_OUT_HIGH,.delay = 11,},},.size = 6,.power_down_setting_a ={{.seq_type = CAMERA_POW_SEQ_CLK,.seq_val = CAMERA_MCLK,.config_val = 0,.delay = 1,},{.seq_type = CAMERA_POW_SEQ_GPIO,.seq_val = CAMERA_GPIO_RESET,.config_val = GPIO_OUT_LOW,.delay = 1,},/*{.seq_type = CAMERA_POW_SEQ_VREG,.seq_val = CAMERA_VAF,.config_val = 1,.delay = 0,},*/{.seq_type = CAMERA_POW_SEQ_VREG,.seq_val = CAMERA_VIO,.config_val = 0,.delay = 0,},{.seq_type = CAMERA_POW_SEQ_VREG,.seq_val = CAMERA_VDIG,.config_val = 0,.delay = 1,},{.seq_type = CAMERA_POW_SEQ_GPIO,.seq_val = CAMERA_GPIO_VANA,.config_val = GPIO_OUT_LOW,.delay = 1,},},.size_down = 5,},.i2c_freq_mode = SENSOR_I2C_MODE_STANDARD,.mem_map_array ={.memory_map ={{.slave_addr = 0x20,.mem_settings ={{ 0x0A04, CAMERA_I2C_WORD_ADDR,64, CAMERA_I2C_BYTE_DATA, CAMERA_I2C_OP_READ, 1 },},.memory_map_size = 1,},},.size_map_array = 1,},},};/** qunhui_s5k5e8_eeprom_open_lib:** Get the funtion pointer of this lib.** This function executes in eeprom module context.** Return: eeprom_lib_func_t point to the function pointer.**/void* qunhui_s5k5e8_eeprom_open_lib(void) {return &qunhui_s5k5e8_lib_func_ptr;}