📄 im8012.c
字号:
for(i = 0; i < 10; i ++) { Y[i] = (unsigned int)(224 * pow(X[i] / 896, nGamma)); } ifp_select(); for(ii = 0; ii < 5; ii ++) { //Write 0x53~0x57 gamma value y1~y10 i2c_write(0x53 + ii, Y[ii * 2]|((Y[ii * 2] + 1) << 8)); }*/ return;}//set analog color gain//floating point is not supported in kernel mode??static void im8012_color_gain(int gain_green1, int gain_blue, int gain_red, int gain_green2, int gain_global){/* //Formula read DataSheet Page 17 unsigned short nValue = 0x20; double step = 0; int add = 0; double nGain[5]; int i; nGain[0] = (double)gain_green1 / SCALEFAC; nGain[1] = (double)gain_blue / SCALEFAC; nGain[2] = (double)gain_red / SCALEFAC; nGain[3] = (double)gain_green2 / SCALEFAC; nGain[4] = (double)gain_global / SCALEFAC; for(i = 0; i < 5; i ++) { if((nGain[i]>=1.0) && (nGain[i]<=1.969)) { step = (1.969-1.0)/0.03125; add= (int)((0x3F-0x20)/step); step = (nGain[i]-1.0)/0.03125; nValue = 0x20+(unsigned short)(step*add); } if((nGain[i]>=2.0) && (nGain[i]<=7.938)) { step = (7.938-2.0)/0.0625; add= (int)((0xFF-0xA0)/step); step = (nGain[i]-2.0)/0.0625; nValue = 0xA0+(unsigned short)(step*add); } if((nGain[i]>=8.0) && (nGain[i]<=15.875)) { step = (15.875-8.0)/0.0125; add= (int)((0x1FF-0x1C0)/step); step = (nGain[i]-8.0)/0.0125; nValue = 0x1C0+(unsigned short)(step*add); } if(i == 4) { //global gain ic_select(); i2c_write(0x35, nValue); } else { //color gain ic_select(); i2c_write(0x2B+i, nValue); } }*/ return;}//frame rate control//0 = disable, i.e. variable frame ratestatic void im8012_frame_rate_control(int fps){ //not implemented //using auto mode by default return;}//color saturation, AWB, defect correctionstatic void im8012_color_processing(int colorsat){ unsigned short nValue; ifp_select(); i2c_read(0x06, &nValue);//color correction i2c_write(0x06, nValue &= 0xFF0F); //turn on //Auto White Balance(AWB) i2c_write(0x06, nValue |= 0x0002); //turn on AWB i2c_write(0x22, 0xD960); //Red channel limit by AWB i2c_write(0x23, 0xD960); //Blue channel limit by AWB//AWB color saturation control i2c_write(0x25, nValue |= 0x4000); //turn on color saturation switch(colorsat) { case 100: i2c_write(0x25, 0x4514); //100% color saturation=>Default break; case 150: i2c_write(0x25, 0x6D14); //150% color saturation break; case 75: i2c_write(0x25, 0x4D14); //75% color saturation break; case 50: i2c_write(0x25, 0x5514); //50% color saturation break; case 37: i2c_write(0x25, 0x5D14); //37.5% color saturation break; case 25: i2c_write(0x25, 0x6514); //25% color saturation break; case -1: i2c_write(0x25, 0x7514); //black and white break; case 0: i2c_write(0x25, nValue & ~0x4000); //turn off color saturation break; default: i2c_write(0x25, 0x4514); //100% color saturation=>Default break; }//Defect Correction i2c_write(0x06, nValue |= 0x2000); //turn on defect correction return;}static void im8012_sharpening(int sharpening){ ifp_select(); i2c_write(0x05, 0x0008); //turn on , no sharpening switch(sharpening) { case 0: i2c_write(0x05, 0x0008); //turn on , no sharpening break; case 25: i2c_write(0x05, 0x0009); //25% sharpening break; case 50: i2c_write(0x05, 0x000A); //50% sharpening break; case 75: i2c_write(0x05, 0x000B); //75% sharpening=>Default break; case 100: i2c_write(0x05, 0x000C); //100% sharpening break; case 125: i2c_write(0x05, 0x000D); //125% sharpening break; case 150: i2c_write(0x05, 0x000E); //150% sharpening break; case 200: i2c_write(0x05, 0x000F); //200% sharpening break; default: i2c_write(0x05, 0x000B); //75% sharpening=>Default break; } return;}//select awb areastatic void im8012_cal_awb_bound(int nLeft, int nRight, int nTop, int nBottom){ unsigned short val;//horizontal direction is divided by 64 nLeft /= 64; nRight /= 64;//vertical direction is divided by 32 nTop /= 32; nBottom /= 32; val = (unsigned short)((nBottom & 0xF) << 12) | ((nTop & 0xF) << 8) | ((nRight & 0xF) << 4) | ((nLeft & 0xF)); ifp_select(); i2c_write(0x2D, val);}//test pattern generation//input -- pattern: 0=turn off, 1=color bar, 2=black, 3=white, 4=graystatic void im8012_test_pattern_enable(int pattern){ ifp_select(); switch(pattern) { case 0: i2c_write(0x48, 0x00); //turn off break; case 1: i2c_write(0x48, 0x07); //Color bar break; case 2: i2c_write(0x48, 0x02); //Black break; case 3: i2c_write(0x48, 0x06); //White break; case 4: i2c_write(0x48, 0x04); //Gray break; default: i2c_write(0x48, 0x07); //Color bar break; } return;}//auto flicker cancellation//note -- still got little flickering//input -- freq: -1=off, 0=auto, 50=50Hz, 60=60Hzstatic void im8012_flicker_cancellation(int freq){ unsigned short data; ifp_select(); switch(freq) { case -1: //disable flicker cancellation i2c_read(0x08, &data); i2c_write(0x08, data & ~0x0800); break; case 0: i2c_read(0x08, &data); i2c_write(0x08, data | 0x0800); //enable flicker cancellation i2c_write(0x5B, 0x00); //auto detect flicker freq break; case 50: i2c_read(0x08, &data); i2c_write(0x08, data | 0x0800); //enable flicker cancellation i2c_write(0x5B, 0x01); //set flicker freq = 50 break; case 60: i2c_read(0x08, &data); i2c_write(0x08, data | 0x0800); //enable flicker cancellation i2c_write(0x5B, 0x03); //set flicker freq = 60 break; } return;}static void im8012_config(IM8012_CFG * _cfg){ im8012_hard_reset(); im8012_hard_standby_control(0); im8012_soft_reset(); //dummy, just for testing im8012_read_mode_ctrl(_cfg->vert_mirror, _cfg->hori_mirror); im8012_blanking_ctrl(); im8012_lens_correction(); im8012_black_threshold(); im8012_cal_awb_bound(_cfg->awb_left, _cfg->awb_right, _cfg->awb_top, _cfg->awb_bottom);// im8012_color_gain(_cfg->gain_green1, _cfg->gain_blue, _cfg->gain_red, _cfg->gain_green2, _cfg->gain_global);// im8012_gamma_correction(_cfg->gamma); im8012_sharpening(_cfg->sharpening); im8012_color_processing(_cfg->colorsat); im8012_decimation_ctrl(_cfg->out_width, _cfg->out_height); im8012_color_fmt_ctrl(_cfg->color_format); if(_cfg->test_pattern_enable) im8012_test_pattern_enable(_cfg->test_pattern_enable);// im8012_frame_rate_control(_cfg->fps); im8012_flicker_cancellation(_cfg->afc_freq); return;}void im8012_cleanup(void){//let sensor enter power saving mode im8012_hard_reset(); im8012_hard_standby_control(1); return; }/************************************************************************************************* sensor driver*************************************************************************************************///global staticstatic devfs_handle_t devfs_handle = NULL;static int gMajor = 0;static int g_im8012_busy = 0;static struct pm_dev *pmdev;static struct apmc_user *g_im8012_apmc;//functions and interfacestatic int im8012_open(struct inode *inode, struct file *filp);static int im8012_release(struct inode *inode, struct file *filp);static ssize_t im8012_read(struct file *filp, char *buf, size_t size, loff_t *l);static ssize_t im8012_write(struct file *filp, const char *buf, size_t size, loff_t *l);static int im8012_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int im8012_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data);struct file_operations im8012_fops = { open: im8012_open, release: im8012_release, read: im8012_read, write: im8012_write, ioctl: im8012_ioctl,};int __init init_module(){ int result; printk("iMagic IM8012 Linux driver ver 0.1\n" " - Copyright (C) 2004 Motorola Inc\n\n"); i2c_init();//register character device result = devfs_register_chrdev(0, "im8012", &im8012_fops); if ( result < 0 ) { printk("im8012 error: Unable to register driver\n"); return -ENODEV; } devfs_handle = devfs_register(NULL, "im8012", DEVFS_FL_DEFAULT, result, 0, S_IFCHR | S_IRUSR | S_IWUSR, &im8012_fops, NULL); if(devfs_handle == NULL) { printk("im8012 error: unable to register driver\n"); return -ENODEV; } gMajor = result; g_im8012_busy = 0;//power management if ((pmdev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, im8012_pm_handler)) == NULL) { printk("im8012 error: failed to register PM... continuing with driver init\n"); } g_im8012_apmc = apmc_register(APMC_LEVEL_HIGHEST); return 0;}void __exit cleanup_module(){ im8012_cleanup(); i2c_cleanup(); apmc_unregister(g_im8012_apmc); pm_unregister(pmdev); if(gMajor > 0) { if(devfs_unregister_chrdev(gMajor, "im8012") < 0) { printk("im8012 error: failed to unregister from devfs\n"); return; } } if(devfs_handle != NULL) devfs_unregister(devfs_handle); else { printk("im8012 error: failed to unregister from devfs, devfs_handle = 0x%08X\n", (int)devfs_handle); return; } printk("IM8012 driver unloaded sucessfully\n"); return;}static int im8012_open(struct inode *inode, struct file *filp){ MOD_INC_USE_COUNT; return 0;}static int im8012_release(struct inode *inode, struct file *filp){ MOD_DEC_USE_COUNT; return 0; }static ssize_t im8012_read(struct file *filp, char *buf, size_t size, loff_t *l){ printk("im8012: read ioctl not implemented\n"); return -1;}static ssize_t im8012_write(struct file *filp, const char *buf, size_t size, loff_t *l){ printk("im8012: write ioctl not implemented\n"); return -1;}static int im8012_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ switch(cmd) { case IM8012_IOC_CONFIG: { g_im8012_busy = 1; if(copy_from_user((void *)&g_im8012_cfg, (void *)arg, sizeof(IM8012_CFG))) return -EFAULT; im8012_config(&g_im8012_cfg); g_im8012_busy = 0; break; } case IM8012_IOC_I2C_TEST: { g_im8012_busy = 1; im8012_i2c_test(); g_im8012_busy = 0; break; } case IM8012_IOC_READ_CONFIG: { if(copy_to_user((void *)arg, (void *)&g_im8012_cfg, sizeof(IM8012_CFG))) return -EFAULT; break; } case IM8012_IOC_SET_CAPTURE_MODE: { //if user does not specify the capture size, //then use the config during im8012_config() if(arg) { if(copy_from_user((void *)&g_im8012_cfg, (void *)arg, sizeof(IM8012_CFG))) return -EFAULT; } //major thing is to change size im8012_decimation_ctrl(g_im8012_cfg.capture_width, g_im8012_cfg.capture_height); break; } case IM8012_IOC_SET_PREVIEW_MODE: { //if user does not specify the preview size, //then use the config during im8012_config() if(arg) { if(copy_from_user((void *)&g_im8012_cfg, (void *)arg, sizeof(IM8012_CFG))) return -EFAULT; } //major thing is to change size im8012_decimation_ctrl(g_im8012_cfg.out_width, g_im8012_cfg.out_height); break; } case IM8012_IOC_STANDBY: { im8012_hard_standby_control(arg); break; } } return 0;}static int im8012_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data){ switch (rqst) { case PM_SUSPEND: { if(g_im8012_busy) { //does not allow suspend when i2c bus is running and configuring the sensor return 1; } else { //put sensor into standby mode by gpio im8012_hard_standby_control(1); printk("im8012 suspend\n"); } break; } case PM_RESUME: { im8012_hard_standby_control(0); printk("im8012 resume\n"); break; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -