所以要了一份 kernel 2.6.24的OV9650 driver,
參考s5k4ba修改ov9650
基本上ov9650 透過 I2C 連到 s3c6410 camera control上
ov9650.c
#include <linux/autoconf.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/i2c-id.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/init.h> #include <linux/delay.h> //#define CAMIF_DEBUG #include "s3c_camif.h" #include "ov9650.h" static const char *sensor_version = "ov9650.c 2010/11/6"; static void delay(int i) { int j; for(j=0;j<i*10;j++); } static struct i2c_driver ov9650_driver; /* This is SXGA(1280x1024) camera but start from VGA(640x480) mode */ static camif_cis_t ov9650_data = { itu_fmt: CAMIF_ITU601, order422: CAMIF_YCBYCR, //YCRYCB camclk: 24000000, /* No effect */ source_x: 640, source_y: 480, win_hor_ofst: 0, win_ver_ofst: 0, win_hor_ofst2: 0, win_ver_ofst2: 0, polarity_pclk: 1, polarity_vsync:1, polarity_href: 0, reset_type:CAMIF_EX_RESET_AL, /* Active Low */ reset_udelay: 20000, }; ov9650_t ov9650_regs_mirror[OV9650_REGS]; extern camif_cis_t* get_initialized_cis(void); camif_cis_t* get_initialized_cis() { printk(KERN_CRIT"[CAM DRV]+get_initialized_cis\n"); if(ov9650_data.init_sensor == 0) return NULL; printk(KERN_CRIT"[CAM DRV]-get_initialized_cis\n"); return &ov9650_data; } //the device slave address are 60 for read 61 for write #define CAM_ID 0x60 static unsigned short ignore[] = { I2C_CLIENT_END }; static unsigned short normal_addr[] = { (CAM_ID >> 1), I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { normal_i2c:normal_addr, probe:ignore, ignore:ignore, }; unsigned char sensor_read(struct i2c_client *client, unsigned char subaddr) { int ret; unsigned char buf[1]; struct i2c_msg msg = { client->addr, 0, 1, buf }; buf[0] = subaddr; printk(KERN_CRIT"[CAM DRV]+sensor_read\n"); ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO; if (ret == -EIO) { printk(" I2C write Error \n"); return -EIO; } msg.flags = I2C_M_RD; ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO; printk(KERN_CRIT"[CAM DRV]-sensor_read\n"); return buf[0]; } static int sensor_write(struct i2c_client *client, unsigned char subaddr, unsigned char val) { unsigned char buf[2]; struct i2c_msg msg = { client->addr, 0, 2, buf }; printk(KERN_CRIT"[CAM DRV]+sensor_write\n"); buf[0] = subaddr; buf[1] = val; printk(KERN_CRIT"[CAM DRV]-sensor_write\n"); return i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO; } void inline sensor_testreg(struct i2c_client *sam_client) { ov9650_t testreg[OV9650_INIT_REGS]; int i; printk(KERN_CRIT"[CAM DRV]+sensor_testreg\n"); for (i = 0; i < OV9650_INIT_REGS; i++) { testreg[i].value = sensor_read(sam_client,ov9650_reg[i].subaddr); printk(KERN_CRIT"ov9650reg value:[0x%02x][0x%02x]\r\n",ov9650_reg[i].subaddr,testreg[i].value); } while(1) { sensor_write(sam_client, 0x35,0x78); delay(20); testreg[1].value = sensor_read(sam_client,10); printk(KERN_CRIT"ov9650reg value:[0x%x]\r\n",testreg[1].value); } printk(KERN_CRIT"[CAM DRV]-sensor_testreg\n"); } void inline sensor_init(struct i2c_client *sam_client) { int i; //i = (sizeof(ov9650_reg)/sizeof(ov9650_reg[0])); printk(KERN_CRIT"[CAM DRV]+sensor_init\n"); for (i = 0; i < OV9650_INIT_REGS; i++) { delay(50); sensor_write(sam_client,ov9650_reg[i].subaddr, ov9650_reg[i].value); #if 0 printk(KERN_ERR "Page:[%03d] Subaddr %02x = 0x%02x\n",i, ov9650_reg[i].subaddr, ov9650_reg[i].value); #endif } #ifdef YOU_WANT_TO_CHECK_IMG_SENSOR for (i = 0; i < OV9650_INIT_REGS; i++) { if (ov9650_reg[i].subaddr == PAGE_ADDRESS) { sensor_write(sam_client, ov9650_reg[i].subaddr, ov9650_reg[i].value); printk(KERN_ERR "Page: Subaddr %02x = 0x%02x\n", ov9650_reg[i].subaddr, ov9650_reg[i].value); } else { ov9650_regs_mirror[i].subaddr = ov9650_reg[i].subaddr; ov9650_regs_mirror[i].value = s5k3aa_read(sam_client, ov9650_reg[i].subaddr); printk(KERN_ERR "Subaddr %02x = 0x%02x\n", ov9650_reg[i].subaddr, ov9650_regs_mirror[i].value); } } #endif printk(KERN_CRIT"[CAM DRV]-sensor_init\n"); } static int ov9650_attach(struct i2c_adapter *adap, int addr, int flags ) { struct i2c_client *c; int ret = 0; //unsigned char a = 0xff; printk(KERN_CRIT"[CAM DRV]+ov9650_attach\n"); c = kmalloc(sizeof(*c), GFP_KERNEL); if (!c) return -ENOMEM; memset(c, 0, sizeof(struct i2c_client)); strcpy(c->name, "ov9650"); c->addr = addr; c->adapter = adap; c->driver = &ov9650_driver; ov9650_data.sensor = c; ret = i2c_attach_client(c); //a = sensor_read(c,10); //printk("0V9650.C:CAMERA ID: 0x%x\r\n",a); printk(KERN_CRIT"[CAM DRV]-ov9650_attach\n"); return ret; } static int sensor_probe(struct i2c_adapter *adap) { printk(KERN_CRIT"[CAM DRV]+sensor_probe\n"); printk(KERN_CRIT"[CAM DRV]-sensor_probe\n"); return i2c_probe(adap, &addr_data, ov9650_attach); } static int sensor_detach(struct i2c_client *client) { printk(KERN_CRIT"[CAM DRV]+sensor_detach\n"); i2c_detach_client(client); printk(KERN_CRIT"[CAM DRV]-sensor_detach\n"); return 0; } static int change_sensor_size(struct i2c_client *client, int size) { int i; printk(KERN_CRIT"[CAM DRV]+change_sensor_size\n"); switch (size) { case SENSOR_VGA: for (i = 0; i < OV9650_VGA_REGS; i++) { delay(50); sensor_write(client, ov9650_reg_vga[i].subaddr, ov9650_reg_vga[i].value); } break; case SENSOR_SXGA: for (i = 0; i < OV9650_SXGA_REGS; i++) { delay(50); sensor_write(client, ov9650_reg_sxga[i].subaddr, ov9650_reg_sxga[i].value); } break; case SENSOR_SVGA: for (i = 0; i < OV9650_INIT_REGS; i++) { delay(50); sensor_write(client, ov9650_reg[i].subaddr, ov9650_reg[i].value); } break; default: panic("ov9650.c: unexpect value \n"); } printk(KERN_CRIT"[CAM DRV]-change_sensor_size\n"); return 0; } static int change_sensor_wb(struct i2c_client *client, int type) { printk(KERN_CRIT"[CAM DRV]+change_sensor_wb\n"); printk("[ *** Page 0, OV9650 Sensor White Balance Mode ***]\n"); sensor_write(client, 0xFC, 0x0); sensor_write(client, 0x30, type); switch(type){ case 0: default: printk(" -> AWB auto mode ]\n"); break; case 1: printk(" -> Indoor 3100 mode ]\n"); break; case 2: printk(" -> Outdoor 5100 mode ]\n"); break; case 3: printk(" -> Indoor 2000 mode ]\n"); break; case 4: printk(" -> AE/AWB halt ]\n"); break; case 5: printk(" -> Cloudy(6000) mode ]\n"); break; case 6: printk(" -> Sunny(8000) mode ]\n"); break; } printk(KERN_CRIT"[CAM DRV]-change_sensor_wb\n"); return 0; } static int sensor_command(struct i2c_client *client, unsigned int cmd, void *arg) { printk(KERN_CRIT"[CAM DRV]+sensor_command\n"); switch (cmd) { case SENSOR_INIT: sensor_init(client); printk("External Camera initialized\n"); break; case USER_ADD: //MOD_INC_USE_COUNT; break; case USER_EXIT: //MOD_DEC_USE_COUNT; //sensor_testreg(client); break; case SENSOR_VGA: printk("change_sensor_size:SENSOR_VGA\n"); change_sensor_size(client, SENSOR_VGA); break; case SENSOR_SVGA: printk("change_sensor_size:SENSOR_SVGA\n"); change_sensor_size(client, SENSOR_SVGA); break; case SENSOR_SXGA: printk("change_sensor_size:SENSOR_SXGA\n"); change_sensor_size(client, SENSOR_SXGA); break; case SENSOR_UXGA: printk("change_sensor_size:SENSOR_UXGA\n"); change_sensor_size(client, SENSOR_UXGA); break; /* Todo case SENSOR_BRIGHTNESS: change_sensor(); break; */ case SENSOR_WB: printk("[ *** OV9650 Sensor White Balance , No mode ***]\n"); change_sensor_wb(client, (int)arg); break; default: panic("ov9650.c : Unexpect Sensor Command \n"); break; } printk(KERN_CRIT"[CAM DRV]-sensor_command\n"); return 0; } static struct i2c_driver ov9650_driver = { .driver = { .name = "ov9650", }, .id = I2C_DRIVERID_OVCAMCHIP, .attach_adapter = sensor_probe, .detach_client = sensor_detach, .command = sensor_command }; static int ov9650_sensor_init(void) { int ret; printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_init\n"); s3c_camif_open_sensor(&ov9650_data); if (ov9650_data.sensor == NULL) if ((ret = i2c_add_driver(&ov9650_driver))) return ret; if (ov9650_data.sensor == NULL) { i2c_del_driver(&ov9650_driver); return -ENODEV; } s3c_camif_register_sensor(&ov9650_data); printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_init\n"); return 0; } static void ov9650_sensor_exit(void) { printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n"); if (ov9650_data.sensor != NULL) s3c_camif_unregister_sensor(&ov9650_data); printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n"); } static struct v4l2_input ov9650_input = { //第幾個camera輸入 .index = 0, //cmos name .name = "Camera Input (OV9650)", //V4L2_INPUT_TYPE_TUNER 1 This input uses a tuner (RF demodulator). //V4L2_INPUT_TYPE_CAMERA 2 Analog baseband input, for example CVBS //Composite Video, S-Video, RGB. .type = V4L2_INPUT_TYPE_CAMERA, //Video inputs combine with zero or more audio inputs. .audioset = 0, //Capture devices can have zero or more tuners .tuner = 0, //Every video input supports one or more different video standards .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, // .status = 0, }; static struct v4l2_input_handler ov9650_input_handler = { ov9650_sensor_init, ov9650_sensor_exit }; static __init int ov9650_sensor_add(void) { printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_add\n"); printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_add\n"); return s3c_camif_add_sensor(&ov9650_input, &ov9650_input_handler); } static __exit void ov9650_sensor_remove(void) { printk(KERN_CRIT"[CAM DRV]+ov9650_sensor_remove\n"); if(ov9650_data.sensor != NULL) { i2c_del_driver(&ov9650_driver); } s3c_camif_remove_sensor(&ov9650_input, &ov9650_input_handler); printk(KERN_CRIT"[CAM DRV]-ov9650_sensor_remove\n"); } module_init(ov9650_sensor_add) module_exit(ov9650_sensor_remove)
沒有留言:
張貼留言