embedded linux ,android

2010年11月11日 星期四

Porting CMOS Sensor OV9650 form 2.6.24 to android kernel 2.6.29 on dma6410xp

由於dma6410xp的camera還不能動,
所以要了一份 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)

沒有留言:

張貼留言