www.pudn.com > s5k3m2_mipi_raw.rar > s5k3m2_otp.c, change:2015-07-15,size:16746b


/************************************************************************************************* 
s5k3m2_otp.c 
--------------------------------------------------------- 
OTP Application file From Truly for s5k3m2 
2013.01.14 
--------------------------------------------------------- 
NOTE: 
The modification is appended to initialization of image sensor.  
After sensor initialization, use the function , and get the id value. 
bool otp_wb_update(BYTE zone) 
and 
bool otp_lenc_update(BYTE zone),  
then the calibration of AWB and LSC will be applied.  
After finishing the OTP written, we will provide you the golden_rg and golden_bg settings. 
**************************************************************************************************/ 
 
#include <linux/videodev2.h> 
#include <linux/i2c.h> 
#include <linux/platform_device.h> 
#include <linux/delay.h>   
#include <linux/cdev.h> 
#include <linux/uaccess.h> 
#include <linux/fs.h> 
#include <asm/atomic.h> 
#include <linux/slab.h> 
 
 
#include "kd_camera_hw.h" 
#include "kd_imgsensor.h" 
#include "kd_imgsensor_define.h" 
#include "kd_imgsensor_errcode.h" 
 
#include "s5k3m2mipi_Sensor.h" 
//#include "s5k3m2mipiraw_Camera_Sensor_para.h" 
//#include "s5k3m2mipiraw_CameraCustomized.h" 
 
extern int iWriteRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u16 i2cId); 
extern int iReadRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u8 * a_pRecvData, u16 a_sizeRecvData, u16 i2cId); 
 
#define USHORT unsigned short 
#define BYTE unsigned char 
#define Sleep(ms) mdelay(ms) 
 
BYTE s5k3m2_byteread_cmos_sensor(kal_uint32 addr) 
{ 
	BYTE get_byte=0; 
	char puSendCmd[2] = {(char)(addr >> 8) , (char)(addr & 0xFF) }; 
	iReadRegI2C(puSendCmd , 2, (u8*)&get_byte,1,0x20); 
	return get_byte; 
} 
//extern  void write_cmos_sensor(u16 addr, u32 para); 
//extern  void write_cmos_sensor_8(u16 addr, u32 para); 
 
 
static void write_cmos_sensor(kal_uint16 addr, kal_uint16 para) 
{ 
    char pusendcmd[4] = {(char)(addr >> 8) , (char)(addr & 0xFF) ,(char)(para >> 8),(char)(para & 0xFF)}; 
    iWriteRegI2C(pusendcmd , 4, 0x20); 
} 
 
static void write_cmos_sensor_8(kal_uint16 addr, kal_uint8 para) 
{ 
    char pusendcmd[4] = {(char)(addr >> 8) , (char)(addr & 0xFF) ,(char)(para & 0xFF)}; 
    iWriteRegI2C(pusendcmd , 3, 0x20); 
} 
 
#define TRULY_ID           0x02 
//#define SUNNY_ID           0x02 
 
 
//#define VALID_OTP          0x00 
#define VALID_OTP        0x40 
 
#define GAIN_DEFAULT       0x0100 
#define GAIN_GREEN1_ADDR   0x020E 
#define GAIN_BLUE_ADDR     0x0212 
#define GAIN_RED_ADDR      0x0210 
#define GAIN_GREEN2_ADDR   0x0214 
 
#define GOLDEN_RGr           0x1FE 
#define GOLDEN_BGr           0x207 
 
USHORT current_RGr; 
USHORT current_BGr; 
USHORT current_GbGr; 
 
static kal_uint32 r_ratio; 
static kal_uint32 b_ratio; 
 
 
//kal_uint32	golden_r = 0, golden_gr = 0, golden_gb = 0, golden_b = 0; 
//kal_uint32	current_r = 0, current_gr = 0, current_gb = 0, current_b = 0; 
/************************************************************************************************* 
* Function    :  start_read_otp 
* Description :  before read otp , set the reading block setting   
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  0, reading block setting err 
                 1, reading block setting ok  
**************************************************************************************************/ 
bool start_read_otp() 
{ 
 
	Sleep(10); 
	write_cmos_sensor(0x0136,0x1800); 
	write_cmos_sensor(0x0304,0x0006); 
	write_cmos_sensor(0x0306,0x006E); 
	write_cmos_sensor(0x030C,0x0004); 
	write_cmos_sensor(0x030E,0x006A); 
	write_cmos_sensor(0x0302,0x0001); 
	write_cmos_sensor(0x0300,0x0004); 
	write_cmos_sensor(0x030A,0x0001); 
	write_cmos_sensor(0x0308,0x0008); 
 	write_cmos_sensor(0x0100, 0x0100);//STREAM ON 
    Sleep(10); 
	write_cmos_sensor_8(0x0A02, 0x1F);   //Select the page to write by writing to 0xD0000A02 0x00~0x0F 
	write_cmos_sensor_8(0x0A00, 0x01);   //Enter read mode by writing 01h to 0xD0000A00 
	Sleep(2); 
 
	return 1; 
} 
 
/************************************************************************************************* 
* Function    :  stop_read_otp 
* Description :  after read otp , stop and reset otp block setting   
**************************************************************************************************/ 
void stop_read_otp() 
{ 
	write_cmos_sensor_8(0x0A00, 0x00);//Disable NVM controller 
} 
 
 
/************************************************************************************************* 
* Function    :  get_otp_AWB_flag 
* Description :  get otp AWB_WRITTEN_FLAG   
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  [BYTE], if 0x00 , this type has valid or empty otp data, otherwise, invalid otp data 
**************************************************************************************************/ 
BYTE get_otp_AWB_flag(BYTE zone) 
{ 
    BYTE flag_AWB ; 
    start_read_otp(); 
    if(zone==0) 
    	{ 
    		flag_AWB = s5k3m2_byteread_cmos_sensor(0x0A04); 
    		printk("S5K3M2_zone0 wgs++: flag_AWB := 0x%02x \n", flag_AWB ); 
  		} 
  	else 
  		{ 
  			flag_AWB = s5k3m2_byteread_cmos_sensor(0x0A14); 
  			printk("S5K3M2_zone1 wgs++: flag_AWB := 0x%02x \n", flag_AWB ); 
  		} 
    stop_read_otp(); 
 
     
	return flag_AWB; 
} 
 
 
/************************************************************************************************* 
* Function    :  get_otp_module_id 
* Description :  get otp MID value  
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  [BYTE] 0 : OTP data fail  
                 other value : module ID data , TRULY ID is 0x0001             
**************************************************************************************************/ 
BYTE get_otp_module_id(BYTE zone) 
{ 
	BYTE module_id = 0; 
 
	start_read_otp(); 
 			if(zone==0) 
    	{ 
				module_id = s5k3m2_byteread_cmos_sensor(0x0A06); 
			} 
			else 
				{ 
					module_id = s5k3m2_byteread_cmos_sensor(0x0A26); 
				} 
 
	stop_read_otp(); 
 
	printk("S5K3M2 wgs++: Module ID = 0x%02x.\n",module_id); 
 
	return module_id; 
} 
 
 
/************************************************************************************************* 
* Function    :  get_otp_date 
* Description :  get otp date value     
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f     
**************************************************************************************************/ 
bool get_otp_date(BYTE zone)  
{ 
	BYTE year  = 0; 
	BYTE month = 0; 
	BYTE day   = 0; 
 
	start_read_otp(); 
	if(zone==0) 
    	{ 
				year  = s5k3m2_byteread_cmos_sensor(0x0A07); 
				month = s5k3m2_byteread_cmos_sensor(0x0A08); 
				day   = s5k3m2_byteread_cmos_sensor(0x0A09); 
			} 
			else 
				{ 
					year  = s5k3m2_byteread_cmos_sensor(0x0A27); 
					month = s5k3m2_byteread_cmos_sensor(0x0A28); 
					day   = s5k3m2_byteread_cmos_sensor(0x0A29); 
				} 
 
	stop_read_otp(); 
 
    printk("S5K3M2 wgs++: date=%02d.%02d.%02d \n", year,month,day); 
 
	return 1; 
} 
 
 
 
/************************************************************************************************* 
* Function    :  get_otp_lens_id 
* Description :  get otp LENS_ID value  
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  [BYTE] 0 : OTP data fail  
                 other value : LENS ID data              
**************************************************************************************************/ 
BYTE get_otp_lens_id(BYTE zone) 
{ 
	BYTE lens_id = 0; 
 
	start_read_otp(); 
		if(zone==0) 
    	{ 
			lens_id = s5k3m2_byteread_cmos_sensor(0x0A0A); 
			} 
			else 
				{ 
					lens_id = s5k3m2_byteread_cmos_sensor(0x0A2A); 
				} 
	stop_read_otp(); 
 
	printk("S5K3M2 wgs++: Lens ID = 0x%02x.\n",lens_id); 
 
	return lens_id; 
} 
 
 
/************************************************************************************************* 
* Function    :  get_otp_vcm_id 
* Description :  get otp VCM_ID value  
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  [BYTE] 0 : OTP data fail  
                 other value : VCM ID data              
**************************************************************************************************/ 
BYTE get_otp_vcm_id(BYTE zone) 
{ 
	BYTE vcm_id = 0; 
 
	start_read_otp(); 
	if(zone==0) 
    { 
			vcm_id = s5k3m2_byteread_cmos_sensor(0x0A0B); 
		} 
		else 
			{ 
				vcm_id = s5k3m2_byteread_cmos_sensor(0x0A2B); 
			} 
 
	stop_read_otp(); 
 
	printk("S5K3M2 wgs++: VCM ID = 0x%02x.\n",vcm_id); 
 
	return vcm_id;	 
} 
 
 
/************************************************************************************************* 
* Function    :  get_otp_driverIC_id 
* Description :  get otp driverIC id value  
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  [BYTE] 0 : OTP data fail  
                 other value : driver ID data              
**************************************************************************************************/ 
BYTE get_otp_driverIC_id(BYTE zone) 
{ 
	BYTE driverIC_id = 0; 
 
	start_read_otp(); 
		if(zone==0) 
    { 
			driverIC_id = s5k3m2_byteread_cmos_sensor(0x0A0C); 
		} 
		else 
			{ 
				driverIC_id = s5k3m2_byteread_cmos_sensor(0x0A2C); 
			} 
 
	stop_read_otp(); 
 
	printk("S5K3M2 wgs++: Driver ID = 0x%02x.\n",driverIC_id); 
 
	return driverIC_id; 
} 
 
/************************************************************************************************* 
* Function    :  otp_lenc_update 
* Description :  Update lens correction  
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f 
* Return      :  [bool] 0 : OTP data fail  
                        1 : otp_lenc update success             
**************************************************************************************************/ 
bool otp_lenc_update() 
{ 
 
        //LSC correct 
        write_cmos_sensor_8(0x0B00,0x01); 
        write_cmos_sensor(0x3058,0x0900); 
        //write_cmos_sensor_8(0x0B00,0x00); 
        printk("S5K3M2 wgs++: LSC update finished!!!!! \n"); 
        //Load 
    return 1; 
} 
 
 
 
/************************************************************************************************* 
* Function    :  wb_gain_set 
* Description :  Set WB ratio to register gain setting  512x 
* Parameters  :  [int] r_ratio : R ratio data compared with golden module R 
                       b_ratio : B ratio data compared with golden module B 
* Return      :  [bool] 0 : set wb fail  
                        1 : WB set success             
**************************************************************************************************/ 
 
bool wb_gain_set() 
{ 
    USHORT R_GAIN; 
    USHORT B_GAIN; 
    USHORT Gr_GAIN; 
    USHORT Gb_GAIN; 
    USHORT G_GAIN; 
 
    if(!r_ratio || !b_ratio) 
    { 
        printk("S5K3M2 wgs++: OTP WB ratio Data Err!\n"); 
        return 0; 
    } 
//s5k3m2_wordwrite_cmos_sensor(GAIN_GREEN1_ADDR, GAIN_DEFAULT); //Green 1 default gain 1x 
//s5k3m2_wordwrite_cmos_sensor(GAIN_GREEN2_ADDR, GAIN_DEFAULT); //Green 2 default gain 1x 
    if(r_ratio >= 512 ) 
    { 
        if(b_ratio>=512)  
        { 
            R_GAIN = (USHORT)(GAIN_DEFAULT * r_ratio / 512);						 
            G_GAIN = GAIN_DEFAULT; 
            B_GAIN = (USHORT)(GAIN_DEFAULT * b_ratio / 512); 
        } 
        else 
        { 
            R_GAIN =  (USHORT)(GAIN_DEFAULT*r_ratio / b_ratio ); 
            G_GAIN = (USHORT)(GAIN_DEFAULT*512 / b_ratio ); 
            B_GAIN = GAIN_DEFAULT;     
        } 
    } 
    else                       
    {		 
        if(b_ratio >= 512) 
        { 
            R_GAIN = GAIN_DEFAULT; 
            G_GAIN = (USHORT)(GAIN_DEFAULT*512 /r_ratio);		 
            B_GAIN =  (USHORT)(GAIN_DEFAULT*b_ratio / r_ratio ); 
        }  
        else  
        { 
            Gr_GAIN = (USHORT)(GAIN_DEFAULT*512/ r_ratio );						 
            Gb_GAIN = (USHORT)(GAIN_DEFAULT*512/b_ratio );						 
            if(Gr_GAIN >= Gb_GAIN)						 
            {						 
                R_GAIN = GAIN_DEFAULT;						 
                G_GAIN = (USHORT)(GAIN_DEFAULT *512/ r_ratio );						 
                B_GAIN =  (USHORT)(GAIN_DEFAULT*b_ratio / r_ratio );						 
            }  
            else 
            {						 
                R_GAIN =  (USHORT)(GAIN_DEFAULT*r_ratio  / b_ratio);						 
                G_GAIN = (USHORT)(GAIN_DEFAULT*512 / b_ratio );						 
                B_GAIN = GAIN_DEFAULT; 
            } 
        }         
    } 
		printk("S5K3M2 wgs++: [R_GAIN=%d],[G_GAIN=%d],[B_GAIN=%d] \n",R_GAIN, G_GAIN, B_GAIN); 
    write_cmos_sensor(GAIN_RED_ADDR, R_GAIN);		 
    write_cmos_sensor(GAIN_BLUE_ADDR, B_GAIN);      
    write_cmos_sensor(GAIN_GREEN1_ADDR, G_GAIN); //Green 1 default gain 1x		 
    write_cmos_sensor(GAIN_GREEN2_ADDR, G_GAIN); //Green 2 default gain 1x 
    write_cmos_sensor_8(0x3056,0x01); 
    printk("S5K3M2 wgs++: OTP WB Update Finished! \n"); 
     
	return 1; 
} 
 
 
 
/************************************************************************************************* 
* Function    :  get_otp_wb 
* Description :  Get WB data     
* Parameters  :  [BYTE] zone : OTP PAGE index , 0x00~0x0f       
**************************************************************************************************/ 
bool get_otp_wb(BYTE zone) 
{ 
	BYTE temph = 0; 
	BYTE templ = 0; 
	current_RGr = 0, current_BGr = 0, current_GbGr = 0; 
	USHORT golden_RGr=GOLDEN_RGr; 
	USHORT golden_BGr=GOLDEN_BGr; 
    start_read_otp(); 
if(zone==0) 
 { 
	temph = s5k3m2_byteread_cmos_sensor(0x0A0E);   
	templ = s5k3m2_byteread_cmos_sensor(0x0A0F);    
	current_RGr  = (USHORT)templ + ((USHORT)temph << 8); 
 
	temph = s5k3m2_byteread_cmos_sensor(0x0A10);   
	templ = s5k3m2_byteread_cmos_sensor(0x0A11);    
	current_BGr  = (USHORT)templ + ((USHORT)temph << 8); 
 
	temph = s5k3m2_byteread_cmos_sensor(0x0A12);   
	templ = s5k3m2_byteread_cmos_sensor(0x0A13);    
	current_GbGr  = (USHORT)templ + ((USHORT)temph << 8); 
 
} 
else 
	{ 
		temph = s5k3m2_byteread_cmos_sensor(0x0A2E);   
	templ = s5k3m2_byteread_cmos_sensor(0x0A2F);    
	current_RGr  = (USHORT)templ + ((USHORT)temph << 8); 
 
	temph = s5k3m2_byteread_cmos_sensor(0x0A30);   
	templ = s5k3m2_byteread_cmos_sensor(0x0A31);    
	current_BGr  = (USHORT)templ + ((USHORT)temph << 8); 
 
	temph = s5k3m2_byteread_cmos_sensor(0x0A32);   
	templ = s5k3m2_byteread_cmos_sensor(0x0A33);    
	current_GbGr  = (USHORT)templ + ((USHORT)temph << 8); 
	} 
	stop_read_otp(); 
	 
    printk("S5K3M2 wgs++: golden_RGr=%d,golden_BGr=%d \n",golden_RGr,golden_BGr); 
    printk("S5K3M2 wgs++: current_RGr=%d,current_BGr=%d,current_GbGr=%d \n",current_RGr,current_BGr,current_GbGr);     
	return 1; 
} 
 
 
/************************************************************************************************* 
* Function    :  otp_wb_update 
* Description :  Update WB correction  
* Return      :  [bool] 0 : OTP data fail  
                        1 : otp_WB update success             
**************************************************************************************************/ 
bool otp_wb_update(BYTE zone) 
{ 
 
	if(!get_otp_wb(zone))  // get wb data from otp 
		return 0; 
 
 
	if(!current_RGr || !current_BGr || !current_GbGr) 
	{ 
		printk("S5K3M2 wgs++: WB update Err !\n"); 
		return 0; 
	} 
 
	r_ratio = 512 * GOLDEN_RGr /current_RGr; 
	b_ratio = 512 * GOLDEN_BGr /current_BGr; 
    printk("S5K3M2 wgs++: r_ratio=%d, b_ratio=%d \n",r_ratio, b_ratio); 
	wb_gain_set(); 
 
	printk("S5K3M2 wgs++: WB update finished! \n"); 
 
	return 1; 
} 
 
/************************************************************************************************* 
* Function    :  otp_update() 
* Description :  update otp data from otp , it otp data is valid,  
                 it include get ID and WB update function   
* Return      :  [bool] 0 : update fail 
                        1 : update success 
**************************************************************************************************/ 
bool otp_update() 
{ 
	BYTE zone = 0;// 
	BYTE FLG = 0x00; 
	BYTE MID = 0x00,LENS_ID= 0x00,VCM_ID= 0x00; 
	int i; 
	 
	for(i=0;i<2;i++) 
	{ 
		FLG = get_otp_AWB_flag(zone); 
		if(FLG != VALID_OTP) 
			zone ++; 
		else 
			break; 
	} 
	if(i==2) 
	{ 
		printk("S5K3M2 wgs++: No OTP Data or OTP data is invalid!!\n"); 
		return 0; 
	} 
		if(FLG == VALID_OTP) 
    { 
    MID = get_otp_module_id(zone); 
    get_otp_date(zone); 
    LENS_ID=	get_otp_lens_id(zone); 
    VCM_ID=	get_otp_vcm_id(zone); 
    get_otp_driverIC_id(zone); 
    	otp_wb_update(zone); 
			otp_lenc_update(); 
			return 1; 
  	} 
     
	if(MID != TRULY_ID) 
	{ 
		printk("S5K3M2 wgs++: Not Truly Module!!!!\n"); 
		return 0; 
	} 
	 
}