📄 ov9650.c
字号:
/*
*
* MX21 OV9650 Driver
*
* cliff.wong@motorola.com
* 16 Jun, 04
*/
#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 "asm/arch/mx2.h"
#include "asm/arch/platform.h"
#include "linux/i2c.h"
#include "linux/i2c-dev.h"
#include "khead.h"
#include "csi.h"
#include "ov9650.h"
/*************************************************************************************************
i2c related
*************************************************************************************************/
static unsigned int error_status = 0;
static unsigned int i2c_init = 0;
void I2C_init()
{
_reg_GPIO_GIUS(GPIOD) &= ~((1<<17)|(1<<18));
_reg_GPIO_GPR(GPIOD) &= ~((1<<17)|(1<<18));
_reg_GPIO_GIUS(GPIOD) |= 0x00100000;
_reg_GPIO_DDIR(GPIOD) |= 0x00100000;
_reg_GPIO_OCR2(GPIOD) |= 0x00000300;
_reg_GPIO_DR(GPIOD) |= 0x00100000;
_reg_GPIO_DR(GPIOD) &= ~0x00100000;
}
static int i2c_write(unsigned char reg, unsigned char data)
{
I2C_init();
//module reset
_reg_I2C_I2CR = 0x0;
//I2C init
_reg_I2C_IFDR = 0x19; //clock select
_reg_I2C_I2CR |= 0x80; //I2C enable
_reg_I2C_I2CR |= 0x08; //ack disable
//grant bus master
_reg_I2C_I2CR |= 0x20; //gen START signal
while (!(_reg_I2C_I2SR & 0x20)); //poll until bus is grant (IBB bit)
//enter transmit mode
_reg_I2C_I2CR |= 0x10; //transmit mode
//transmit device slave calling addr
_reg_I2C_I2DR = 0x60; //initiate transfer
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//check for ACK bit
if (_reg_I2C_I2SR & 0x1)
printk("not Ack4\n");
//transmit register addr
_reg_I2C_I2DR = reg; //initiate transfer
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//check for ACK bit
if (_reg_I2C_I2SR & 0x1)
printk("not Ack5\n");
//transmit data LSB
_reg_I2C_I2DR = data; //initiate transfer
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//check for ACK bit
if (_reg_I2C_I2SR & 0x1)
printk("not Ack6\n");
//generate STOP signal
_reg_I2C_I2CR &= ~0x20; //enter slave mode
while (_reg_I2C_I2SR & 0x20); //poll until bus is release (IBB = 0)
//disable I2C
_reg_I2C_I2CR = 0x0;
return 0;
// return ret;
}
static int i2c_read(unsigned char reg, unsigned char *_data)
{
I2C_init();
//module reset
_reg_I2C_I2CR = 0x0;
//I2C init
_reg_I2C_IFDR = 0x19; //clock select
_reg_I2C_I2CR |= 0x80; //I2C enable
//grant bus master
_reg_I2C_I2CR |= 0x20; //gen START signal
while (!(_reg_I2C_I2SR & 0x20)); //poll until bus is grant (IBB bit)
//enter transmit mode
_reg_I2C_I2CR |= 0x10;
//transmit device addr for WRITE
_reg_I2C_I2DR = 0x60; //initiate transfer
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//check for ACK bit
if (_reg_I2C_I2SR & 0x1)
printk("not Ack1\n");
//transmit register addr
_reg_I2C_I2DR = reg; //initiate transfer
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//check for ACK bit
if (_reg_I2C_I2SR & 0x1)
printk("not Ack2\n");
_reg_I2C_I2CR &= ~0x20; //enter slave mode
while (_reg_I2C_I2SR & 0x20); //poll until bus is release (IBB = 0)
_reg_I2C_I2CR |= 0x20; //gen START signal
while (!(_reg_I2C_I2SR & 0x20)); //poll until bus is grant (IBB bit
//generate repeated START signal
// _reg_I2C_I2CR |= 0x4;
_reg_I2C_I2CR |= 0x10;
//transmit device calling addr for READ
_reg_I2C_I2DR = 0x61; //initiate transfer
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//check for ACK bit
if (_reg_I2C_I2SR & 0x1)
printk("not Ack3\n");
//change to recieve mode
_reg_I2C_I2CR &= ~0x10;
//dummy read to excite clock generation
_reg_I2C_I2CR &= ~0x08; //ack enable
*_data = _reg_I2C_I2DR;
// while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
// _reg_I2C_I2SR &= ~0x02; //must clear IIF bit
//get MSB, and gen clock for reading LSB
_reg_I2C_I2CR |= 0x08; //ack disable
while (!(_reg_I2C_I2SR & 0x02)); //poll IIF bit
_reg_I2C_I2SR &= ~0x02; //must clear IIF bit
// msb = *(U32 *) I2C_I2DR;
// while (!(*(U32 *) I2C_I2SR & 0x02)); //poll IIF bit
// *(U32 *) I2C_I2SR &= ~0x02; //must clear IIF bit
// printk("data = %x\n",_reg_I2C_I2DR);
//generate STOP signal
_reg_I2C_I2CR &= ~0x20; //enter slave mode
while (_reg_I2C_I2SR & 0x20); //poll until bus is release (IBB = 0)
//get LSB
*_data = _reg_I2C_I2DR;
// printk("data = %x\n",*_data);
udelay(100);
//disable I2C
_reg_I2C_I2CR = 0x0;
//concantenate 2 bytes into 16-bit
return 0;
// return ret;
}
/*************************************************************************************************
sensor api
*************************************************************************************************/
#define CSI_CTL0 0x0040
#define CSI_CTL1 0x0020
#define CSI_CTL2 0x0010
static OV9650_CFG g_ov9650_cfg;
void ov9650_config_SENSOR(OV9650_CFG * _cfg)
{
i2c_write(0x12, 0x80); // reset sensor
udelay(50000);
i2c_write(0x09, 0x11);
i2c_write(0x6b, 0x0a);
i2c_write(0x3b, 0x09);
i2c_write(0x13, 0xe0);
i2c_write(0x01, 0x80);
i2c_write(0x02, 0x80);
i2c_write(0x00, 0x00);
i2c_write(0x10, 0x00);
i2c_write(0x13, 0xe5);
i2c_write(0x39, 0x43);
i2c_write(0x38, 0x12);
i2c_write(0x37, 0x00);
i2c_write(0x35, 0x91);
i2c_write(0x1e, 0x04);
i2c_write(0xA8, 0x80);
i2c_write(0x3f, 0xa6);
i2c_write(0x14, 0x2e);
i2c_write(0x15, 0x02);
i2c_write(0x41, 0x02);
i2c_write(0x42, 0x08);
i2c_write(0x1b, 0x00);
i2c_write(0x16, 0x06);
i2c_write(0x33, 0xe2);
i2c_write(0x34, 0xbf);
i2c_write(0x96, 0x04);
i2c_write(0x3a, 0x00);
i2c_write(0x8e, 0x00);
i2c_write(0x3c, 0x77);
i2c_write(0x8B, 0x06);
i2c_write(0x94, 0x88);
i2c_write(0x95, 0x88);
i2c_write(0x40, 0xc1);
i2c_write(0x29, 0x3f);
i2c_write(0x0f, 0x42);
i2c_write(0x3d, 0x92);
i2c_write(0x69, 0x40);
i2c_write(0x5C, 0xb9);
i2c_write(0x5D, 0x96);
i2c_write(0x5E, 0x10);
i2c_write(0x59, 0xc0);
i2c_write(0x5A, 0xaf);
i2c_write(0x5B, 0x55);
i2c_write(0x43, 0xf0);
i2c_write(0x44, 0x10);
i2c_write(0x45, 0x68);
i2c_write(0x46, 0x96);
i2c_write(0x47, 0x60);
i2c_write(0x48, 0x80);
i2c_write(0x5F, 0xe0);
i2c_write(0x60, 0x8c);
i2c_write(0x61, 0x20);
i2c_write(0xa5, 0xd9);
i2c_write(0xa4, 0x74);
i2c_write(0x8d, 0x02);
i2c_write(0x13, 0xe7);
i2c_write(0x4f, 0x3a);
i2c_write(0x50, 0x3d);
i2c_write(0x51, 0x03);
i2c_write(0x52, 0x12);
i2c_write(0x53, 0x26);
i2c_write(0x54, 0x38);
i2c_write(0x55, 0x40);
i2c_write(0x56, 0x40);
i2c_write(0x57, 0x40);
i2c_write(0x58, 0x0d);
i2c_write(0x8C, 0x23);
i2c_write(0x3E, 0x02);
i2c_write(0xa9, 0xb8);
i2c_write(0xaa, 0x92);
i2c_write(0xab, 0x0a);
i2c_write(0x8f, 0xdf);
i2c_write(0x90, 0x00);
i2c_write(0x91, 0x00);
i2c_write(0x9f, 0x00);
i2c_write(0xa0, 0x00);
i2c_write(0x3A, 0x02);
i2c_write(0x24, 0x70);
i2c_write(0x25, 0x64);
i2c_write(0x26, 0xc3);
i2c_write(0x2a, 0x00);
i2c_write(0x2b, 0x00);
i2c_write(0x6c, 0x40);
i2c_write(0x6d, 0x30);
i2c_write(0x6e, 0x4b);
i2c_write(0x6f, 0x60);
i2c_write(0x70, 0x70);
i2c_write(0x71, 0x70);
i2c_write(0x72, 0x70);
i2c_write(0x73, 0x70);
i2c_write(0x74, 0x60);
i2c_write(0x75, 0x60);
i2c_write(0x76, 0x50);
i2c_write(0x77, 0x48);
i2c_write(0x78, 0x3a);
i2c_write(0x79, 0x2e);
i2c_write(0x7a, 0x28);
i2c_write(0x7b, 0x22);
i2c_write(0x7c, 0x04);
i2c_write(0x7d, 0x07);
i2c_write(0x7e, 0x10);
i2c_write(0x7f, 0x28);
i2c_write(0x80, 0x36);
i2c_write(0x81, 0x44);
i2c_write(0x82, 0x52);
i2c_write(0x83, 0x60);
i2c_write(0x84, 0x6c);
i2c_write(0x85, 0x78);
i2c_write(0x86, 0x8c);
i2c_write(0x87, 0x9e);
i2c_write(0x88, 0xbb);
i2c_write(0x89, 0xd2);
i2c_write(0x8a, 0xe6);
i2c_write(0x15, 0x10);
i2c_write(0x3a, 0x08);
return;
}
void ov9650_config_SXGA(OV9650_CFG * _cfg)
{
i2c_write(0x6a, 0x27);
i2c_write(0x0e, 0xa0);
i2c_write(0x04, 0x00);
i2c_write(0x0c, 0x00);
i2c_write(0x0d, 0x00);
i2c_write(0x11, 0x80);
i2c_write(0x12, 0x00);
i2c_write(0x40, 0xc1);
i2c_write(0x2a, 0x10);
i2c_write(0x2b, 0x34);
i2c_write(0x18, 0xbd);
i2c_write(0x17, 0x1d);
i2c_write(0x32, 0xa4);
i2c_write(0x03, 0x12);
i2c_write(0x1a, 0x81);
i2c_write(0x19, 0x01);
i2c_write(0x09, 0x01);
return;
}
void ov9650_config_VGA(OV9650_CFG * _cfg)
{
i2c_write(0x6a, 0x13);
i2c_write(0x0e, 0x20);
i2c_write(0x04, 0x00);
i2c_write(0x0c, 0x04);
i2c_write(0x0d, 0x80);
i2c_write(0x11, 0x81);
i2c_write(0x12, 0x40);
i2c_write(0x40, 0xc1);
i2c_write(0x2a, 0x10);
i2c_write(0x2b, 0x40);
i2c_write(0x18, 0xc6);
i2c_write(0x17, 0x26);
i2c_write(0x32, 0xad);
i2c_write(0x03, 0x36);
i2c_write(0x1a, 0x3c);
i2c_write(0x19, 0x00);
i2c_write(0x09, 0x01);
return;
}
void ov9650_config_QVGA(OV9650_CFG * _cfg)
{
i2c_write(0x6a, 0x25);
i2c_write(0x0e, 0xa0);
i2c_write(0x04, 0x00);
i2c_write(0x0c, 0x04);
i2c_write(0x0d, 0x80);
i2c_write(0x11, 0x83);
i2c_write(0x12, 0x10);
i2c_write(0x40, 0xc1);
i2c_write(0x2a, 0x00);
i2c_write(0x2b, 0x00);
i2c_write(0x18, 0xc6);
i2c_write(0x17, 0x26);
i2c_write(0x32, 0xa4);
i2c_write(0x03, 0x36);
i2c_write(0x1a, 0x1e);
i2c_write(0x19, 0x00);
i2c_write(0x09, 0x01);
return;
}
void ov9650_config_V_Q(OV9650_CFG * _cfg)
{
i2c_write(0x6a, 0x13);
i2c_write(0x0e, 0x20);
i2c_write(0x04, 0x00);
i2c_write(0x0c, 0x04);
i2c_write(0x0d, 0x80);
i2c_write(0x11, 0x81);
i2c_write(0x12, 0x40);
i2c_write(0x18, 0x9e);//c6
i2c_write(0x17, 0x4e);//26
i2c_write(0x32, 0xad);//ad
i2c_write(0x03, 0x36);//36
i2c_write(0x1a, 0x2d);//3c
i2c_write(0x19, 0x0f);//00
i2c_write(0x40, 0xc1);
i2c_write(0x2a, 0x00);
i2c_write(0x2b, 0x00);
i2c_write(0x09, 0x01);
return;
}
void ov9650_config_S_Q(OV9650_CFG * _cfg)
{
i2c_write(0x6a, 0x27);//41
i2c_write(0x0e, 0xa0);//20
i2c_write(0x04, 0x00);
i2c_write(0x0c, 0x00);
i2c_write(0x0d, 0x00);
i2c_write(0x11, 0x80);
i2c_write(0x12, 0x00);
i2c_write(0x18, 0x82);//bd
i2c_write(0x17, 0x5a);//1d
i2c_write(0x32, 0xa4);//bf
i2c_write(0x03, 0x12);
i2c_write(0x1a, 0x50);
i2c_write(0x19, 0x32);
i2c_write(0x40, 0xc1);
i2c_write(0x2a, 0x00);//10
i2c_write(0x2b, 0x00);//34
i2c_write(0x09, 0x01);
return;
}
void ov9650_cleanup(void)
{
return;
}
void sensor_reset(void)
{
// set powerdown signal low , and give a pluse for reset signal
#if 0
setgpio(RESET, 0);
setgpio(POWERDOWN, 0);
udelay(1000);
setgpio(RESET, 1);
udelay(1000);
setgpio(RESET, 0);
udelay(1000);
#endif
}
void i2c_test(void)
{
U8 pid,ver;
i2c_read(0x0a,&pid);
i2c_read(0x0b,&ver);
printk("Sensor PID 0x%x VER 0x%x\n",pid,ver);
return;
}
/*************************************************************************************************
sensor driver
*************************************************************************************************/
//global static
static devfs_handle_t devfs_handle;
static int gMajor = 0;
//functions and interface
static int ov9650_open(struct inode *inode, struct file *filp);
static int ov9650_release(struct inode *inode, struct file *filp);
static ssize_t ov9650_read(struct file *filp, char *buf, size_t size, loff_t *l);
static ssize_t ov9650_write(struct file *filp, const char *buf, size_t size, loff_t *l);
static int ov9650_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
struct file_operations ov9650_fops =
{
open: ov9650_open,
release: ov9650_release,
read: ov9650_read,
write: ov9650_write,
ioctl: ov9650_ioctl,
};
static int ov9650_open(struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
return 0;
}
static int ov9650_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
static ssize_t ov9650_read(struct file *filp, char *buf, size_t size, loff_t *l)
{
printk("ov9650: read ioctl not implemented\n");
return -1;
}
static ssize_t ov9650_write(struct file *filp, const char *buf, size_t size, loff_t *l)
{
printk("ov9650: write ioctl not implemented\n");
return -1;
}
static int ov9650_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case OV9650_IOC_CONFIG:
{
if(copy_from_user((void *)&g_ov9650_cfg, (void *)arg, sizeof(OV9650_CFG)))
return -EFAULT;
break;
}
case OV9650_IOC_I2C_TEST:
{
break;
}
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -