📄 im8012.c
字号:
/* * MX21 IM8012 driver * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (C) 2004 Motorola Semiconductors Hong Kong. * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/version.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/hfs_sysdep.h>#include <linux/compatmac.h>#include <linux/hdreg.h>#include <linux/vmalloc.h>#include <linux/malloc.h>#include <linux/fs.h>#include <linux/module.h>#include <linux/blkpg.h>#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>#include <linux/i2c-id.h>#include <linux/slab.h>#include <asm/io.h>#include <linux/mm.h>#include <linux/wrapper.h>#include <asm/dma.h>#include <linux/miscdevice.h>#include <linux/proc_fs.h>#include <linux/pm.h>#include <asm/arch/apmc.h>#include "asm/arch/mx2.h"#include "asm/arch/platform.h"#include "linux/i2c.h"#include "linux/i2c-dev.h"#include "im8012.h"/************************************************************************************************* i2c related*************************************************************************************************/#define I2C_DRIVERID_I2CCSI 0xF000#define EMBEDDED_REGISTER 0x01#define I2C_M_READ 0x02#define I2C_M_WT 0x04//im8012 i2c addr#define SENSOR_I2C_ADDR 0x90static int i2c_csi_attach_adapter (struct i2c_adapter * adap);static struct i2c_driver i2c_csi_driver ={ name: "i2c-csi client driver", id: I2C_DRIVERID_I2CCSI, flags: I2C_DF_DUMMY | I2C_DF_NOTIFY, attach_adapter: i2c_csi_attach_adapter, detach_client: NULL, /*i2c_csi_detach_client,*/ command: NULL};static struct i2c_client i2c_csi2c_client ={ name: "i2c-csi client", id: 2, flags: 0, addr: -1, adapter: NULL, driver: &i2c_csi_driver, data: NULL};static int i2c_csi_attach_adapter (struct i2c_adapter * adap){ if (memcmp(adap->name, "DBMX I2C Adapter", 16) != 0 ) return -ENODEV; i2c_csi2c_client.adapter = adap; return 0;}static void i2c_init(void){ /* * set the address of the CMOS sensor to the client */ i2c_csi2c_client.addr = SENSOR_I2C_ADDR; /* * call the i2c_add_driver() to register the driver * to the Linux I2C system */ if (i2c_add_driver( &i2c_csi_driver ) != 0) { printk("I2C addr driver failed\n"); return; } /* * attach the client to the adapter by calling the i2c_attach_client() * function of the Linux I2C system */ if (i2c_attach_client(&i2c_csi2c_client ) != 0) { printk("I2C attach client failed\n"); i2c_del_driver(&i2c_csi_driver); return; } i2c_csi2c_client.adapter->inc_use( i2c_csi2c_client.adapter );}static void i2c_cleanup(void){ i2c_csi2c_client.adapter->dec_use(i2c_csi2c_client.adapter); i2c_detach_client(&i2c_csi2c_client ); i2c_del_driver(&i2c_csi_driver);}static int i2c_write(unsigned int reg, unsigned short data){ struct i2c_msg msg; char buf[3]; int ret; /* * store the register value to the first address of the buffer * the adapter/algorithm driver will regard the first byte * as the register value */ buf[0] = (char)reg; buf[1] = (char)((data&0xFF00) >> 8); buf[2] = (char)(data&0xFF); /* * initialize the message structure */ msg.addr = i2c_csi2c_client.addr; msg.flags = EMBEDDED_REGISTER | I2C_M_WT; msg.len = 3; msg.buf = buf; ret = i2c_transfer( i2c_csi2c_client.adapter, &msg, 1 ); return ret;}static int i2c_read(unsigned int reg, unsigned short *_data){ struct i2c_msg msg; char buf[3]; int ret; /* * store the register value to the first address of the buffer * the adapter/algorithm driver will regard the first byte * as the register value */ buf[0] = (char)reg; /* * initialize the message structure */ msg.addr = i2c_csi2c_client.addr; msg.flags = EMBEDDED_REGISTER | I2C_M_READ; msg.len = 2; msg.buf = buf; ret = i2c_transfer( i2c_csi2c_client.adapter, &msg, 1 ); *_data = ((unsigned short)buf[0] << 8) | (unsigned short)buf[1]; return ret;}/************************************************************************************************* sensor api*************************************************************************************************/#define CSI_CTL0 0x0040#define CSI_CTL1 0x0020#define CSI_CTL2 0x0010//globalstatic IM8012_CFG g_im8012_cfg;//localstatic void ifp_select(void);static void ic_select(void);static void ifp_soft_reset(void);static void ic_soft_reset(void);static void im8012_soft_reset(void);static void im8012_hard_reset(void);static void im8012_hard_standby_control(int enable);static int im8012_i2c_test(void);static void im8012_color_fmt_ctrl(int color_space);static void im8012_decimation_ctrl(unsigned int out_width, unsigned int out_height);static void im8012_lens_correction(void);static void im8012_black_threshold(void);static void im8012_read_mode_ctrl(int vert_mirror, int hori_mirror);static void im8012_blanking_ctrl(void);static void im8012_gamma_correction(int gamma);static void im8012_color_gain(int gain_green1, int gain_blue, int gain_red, int gain_green2, int gain_global);static void im8012_color_processing(int colorsat);static void im8012_sharpening(int sharpening);static void im8012_cal_awb_bound(int nLeft, int nRight, int nTop, int nBottom);static void im8012_test_pattern_enable(int nPattern);static void im8012_frame_rate_control(int fps);static void im8012_flicker_cancellation(int freq);//select ifp register spacestatic void ifp_select(void){ i2c_write(0x01, 0x0001); return;}static void ifp_soft_reset(void){ ifp_select(); i2c_write(0x07, 0x0001); i2c_write(0x07, 0x0000); return;}//select ic register spacestatic void ic_select(void){ i2c_write(0x01, 0x0004); return;}static void ic_soft_reset(void){ ic_select(); i2c_write(0x0D, 0x0001); i2c_write(0x0D, 0x0000); return;}//soft register resetstatic void im8012_soft_reset(void){ ifp_soft_reset(); ic_soft_reset(); return;}//set reset pin levelstatic void im8012_hard_reset(void){ unsigned short data;//assert reset pulse data = _reg_EXP_IO_0; data &= ~CSI_CTL1; _reg_EXP_IO_0 = data; udelay(100); data |= CSI_CTL1; _reg_EXP_IO_0 = data; udelay(300); return;}//set standby pin levelstatic void im8012_hard_standby_control(int enable){ unsigned short data; data =_reg_EXP_IO_0; if(enable) data |= CSI_CTL0; else data &= ~CSI_CTL0; _reg_EXP_IO_0 = data; return;}//i2c channel read/write teststatic int im8012_i2c_test(void){ unsigned int test_reg = 0x04; //bit [8..0] r/w unsigned short test_val; unsigned short temp_val; int error = 0; im8012_hard_reset(); im8012_hard_standby_control(0); i2c_write(0x01, 0x0004); //select IC for(test_val = 0x0; test_val < 0xFF; test_val ++) { i2c_write(test_reg, test_val); i2c_read(test_reg, &temp_val); if(test_val != temp_val) error = 1; } if(error) printk("im8012: i2c test failed\n"); else printk("im8012: i2c test ok\n"); im8012_hard_reset(); return error;}//set output color spacevoid im8012_color_fmt_ctrl(int color_space){ ifp_select(); if(color_space == YUV) { i2c_write(0x08, 0xCD00); } else if(color_space == RGB) { i2c_write(0x08, 0xD800); } return;}/*//arbitrary resize controlvoid im8012_decimation_ctrl(unsigned int out_width, unsigned int out_height){ if(out_width > 640) out_width = 640; if(out_height > 480) out_height = 480; ifp_select(); i2c_write(0xA5, 0x8000); //hori control i2c_write(0xA6, 0x8000 + 640); //take full window i2c_write(0xA7, 0x8000 + out_width); i2c_write(0xA8, 0x8000); //vert control i2c_write(0xA9, 0x8000 + 480); //take full window i2c_write(0xAA, 0x8000 + out_height); i2c_write(0xA5, 0x0000); //enable changesprintk("im8012: dec control\n"); return;}*///arbitrary resize controlvoid im8012_decimation_ctrl(unsigned int out_width, unsigned int out_height){ unsigned short a5_val, a6_val, a7_val, a8_val, a9_val, aa_val; if(out_width > 640) out_width = 640; if(out_height > 480) out_height = 480; a5_val = 0; //hori control a6_val = 640; //take full window a7_val = out_width; a8_val = 0; //vert control a9_val = 480; //take full window aa_val = out_height; ifp_select(); //change & freeze i2c_write(0xA5, 0x8000 | a5_val); //hori control i2c_write(0xA6, 0x8000 | a6_val); //take full window i2c_write(0xA7, 0x8000 | a7_val); i2c_write(0xA8, 0x8000 | a8_val); //vert control i2c_write(0xA9, 0x8000 | a9_val); //take full window i2c_write(0xAA, 0x8000 | aa_val);//unfreeze & synchronize the changes i2c_write(0xA5, a5_val & ~0x8000);//printk("im8012: dec control\n"); return;}//lens geometry correctionstatic void im8012_lens_correction(void){ unsigned short nValue; ifp_select(); i2c_read(0x08, &nValue); i2c_write(0x08, nValue |= 0x0100); //turn on Lens Shading correction //Vertical direction,split into 5 vertical segment i2c_write(0x81, 0xDD0C); //Red pixel in frist vertex i2c_write(0x82, 0x04F4); //Red pixel in second & third vertex i2c_write(0x83, 0x3C11); //Red pixel in fourth & fifth vertex i2c_write(0x84, 0xE20C); //Green pixel in frist vertex i2c_write(0x85, 0x02F6); //Green pixel in second & third vertex i2c_write(0x86, 0x3211); //Green pixel in fourth & fifth vertex i2c_write(0x87, 0xDD0C); //Blue pixel in frist vertex i2c_write(0x88, 0x00F4); //Blue pixel in second & third vertex i2c_write(0x89, 0x3216); //Blue pixel in fourth & fifth vertex //Horizontal diretion, split into 6 horizontal segment i2c_write(0x8A, 0x8832); //Red pixel in frist vertex i2c_write(0x8B, 0xF7DD); //Red pixel in second & third vertex i2c_write(0x8C, 0x3C0C); //Red pixel in fourth & fifth vertex i2c_write(0x8D, 0x007F); //Red pixel in sixth vertex i2c_write(0x8E, 0xBA1E); //Green pixel in frist vertex i2c_write(0x8F, 0xF7EC); //Green pixel in second & third vertex i2c_write(0x90, 0x3708); //Green pixel in fourth & fifth vertex i2c_write(0x91, 0x0064); //Green pixel in sixth vertex i2c_write(0x92, 0xBF1E); //Blue pixel in frist vertex i2c_write(0x93, 0xF7EE); //Blue pixel in second & third vertex i2c_write(0x94, 0x320F); //Blue pixel in fourth & fifth vertex i2c_write(0x95, 0x0064); //Blue pixel in sixth vertex return;}//photodiode black threshold calibrationstatic void im8012_black_threshold(void){ unsigned short nValue; ic_select(); i2c_read(0x62, &nValue); i2c_write(0x62, nValue|=0x0001); //Manual mode i2c_write(0x5F, 0xA31D); //Calibration(Calib) threshold i2c_write(0x60, 0x001C); //Calib Green1 i2c_write(0x61, 0x0024); //Calib Green2 i2c_write(0x63, 0x0023); //Calib Red i2c_write(0x64, 0x0023); //Calib Blue i2c_write(0x62, nValue&=0xFFFE); //Resume normal mode return;}//pixel read mode control//(read pixel in reverse order)static void im8012_read_mode_ctrl(int vert_mirror, int hori_mirror){ //spec is not updated unsigned short val; ic_select(); i2c_read(0x20, &val); if(vert_mirror) val &= ~0x8080; else val |= 0x8080; //reverse col order if(hori_mirror) val &= ~0x4020; else val |= 0x4020; //reverse row order i2c_write(0x20, val); return;}//frame timing v-blank, h-blank controlstatic void im8012_blanking_ctrl(void){ ic_select();//set to minimum blanking time => max frame rate i2c_write(0x05, 0x9); i2c_write(0x06, 0x3); return;}//set digital gamma correction//to be verifiedstatic void im8012_gamma_correction(int gamma){/* //Formula read DataSheet Page 47 unsigned short Y[10] = {0}; double X[10] = {16, 32, 64, 128, 256, 384, 512, 640, 768, 896}; double nGamma; int i, ii; nGamma = (double)gamma / SCALEFAC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -