所以要了一份 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)
沒有留言:
張貼留言