?? csi.c
字號:
unsigned int mclkdiv = 4; //default set to perclk4/4 => 22MHz
_reg_GPIO_GIUS(GPIOD) &= ~0x60000;
_reg_GPIO_GPR(GPIOD) &= ~0x60000;
//disable GPIO PB[21..10]
_reg_GPIO_GIUS(GPIOB) &= ~0x3FFC00;
_reg_GPIO_GIUS(GPIOB) |= 0x4000000;
_reg_GPIO_PUEN(GPIOB) |= 0x4000000;
_reg_GPIO_DDIR(GPIOB) |= 0x4000000;
_reg_GPIO_OCR2(GPIOB) |= 0x300000;
_reg_GPIO_DR(GPIOB) |= 0x4000000;
udelay(5000);
_reg_GPIO_DR(GPIOB) &= ~0x4000000;
//hclk clock enable
_reg_CRM_PCCR0 |= 0x80000000;
//temp solution
//version check should be done in run time
g_csi_ver = 2;
//reset
_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
if(g_csi_ver == 2)
_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
//need to enable hclk before CSICR3 can be access
//enable perclk4
_reg_CRM_PCCR0 |= 0x00400000;
val = _reg_CRM_PCDR1;
val &= ~(0x3F << 24);
val |= (perclk4div - 1) << 24;
_reg_CRM_PCDR1 = val;
_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
//enable default mclk clock
val = CSICR1_RESET_VAL;
val |= ((mclkdiv / 2) - 1) << SHIFT_MCLKDIV;
val |= BIT_MCLKEN;
_reg_CSI_CSICR1 = val;
return;
}
static void csi_cleanup(void)
{
_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
return;
}
//Read a frame by polling
static int csi_poll(unsigned int * _buf, int byte_size)
{
int i, j;
int word_size = byte_size >> 2;
unsigned int *_kbuf;
int korder;
int required_pages;
int extra_pages;
//alloc a tmp buffer in kernel space
required_pages = byte_size >> PAGE_SHIFT;
for (korder = 0 ; required_pages >> korder ; korder++) {;}
extra_pages = (1 << korder) - required_pages;
_kbuf = (unsigned int *)__get_free_pages(GFP_KERNEL, korder);
if(!_kbuf)
{
printk("csi error: buffer alloc failed\n");
return -1;
}
//poll sof
_reg_CSI_CSISR = BIT_SOF_INT;
while(!(_reg_CSI_CSISR & BIT_SOF_INT));
_reg_CSI_CSISR = BIT_SOF_INT;
//clear fifo overflow
if(_reg_CSI_CSISR & BIT_RFF_OR_INT)
_reg_CSI_CSISR = BIT_RFF_OR_INT;
j = 0;
while(1)
{
//overflow check
if(_reg_CSI_CSISR & BIT_RFF_OR_INT)
{
// printk("csi error: overflow\n");
_reg_CSI_CSISR = BIT_RFF_OR_INT;
}
//poll rx fifo full
if(_reg_CSI_CSISR & BIT_RXFF_INT)
{
for(i = 0; i < 8; i ++)
_kbuf[j ++] = _reg_CSI_CSIRXR;
}
if(j >= word_size)
break;
}
copy_to_user(_buf, _kbuf, byte_size);
free_pages((int)_kbuf, korder);
return 0;
}
static void csi_reset_frame_count(void)
{
_reg_CSI_CSICR3 |= BIT_FRMCNT_RST;
return;
}
static int csi_get_frame_count(void)
{
int count;
count = _reg_CSI_CSICR3 >> SHIFT_FRMCNT;
return count;
}
//global static
static devfs_handle_t devfs_handle;
static int gMajor = 0;
//functions and interface
static int csi_open(struct inode *inode, struct file *filp);
static int csi_release(struct inode *inode, struct file *filp);
static ssize_t csi_read(struct file *filp, char *buf, size_t size, loff_t *l);
static ssize_t csi_write(struct file *filp, const char *buf, size_t size, loff_t *l);
static int csi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
struct file_operations csi_fops =
{
open: csi_open,
release: csi_release,
read: csi_read,
write: csi_write,
ioctl: csi_ioctl,
};
static OV9650_CFG g_ov9650_cfg;
//init module does only the basic things
//dma & irq are turned on later according to csi config
int __init init_module()
{
int result;
csi_module_init();
_reg_CRM_PCDR1 &= ~0x3f000000;
_reg_CRM_PCDR1 |= 0x2000000;
_reg_CSI_CSICR1 |= 0x2; //latch on rising edge
_reg_CSI_CSICR1 |= 0x4; // invert the PIXCLK
_reg_CSI_CSICR1 |= 0x40000000;
_reg_CSI_CSICR1 |= 0x40000;
_reg_CSI_CSICR1 |= 0x1000000;
_reg_CSI_CSICR1 |= 0x100000;
_reg_CSI_CSICR1 |= 0x10000000;
_reg_CSI_CSICR1 |= 0x10; //gated clock mode
_reg_CSI_CSICR1 |= 0x800;
_reg_CSI_CSICR1 |= 0x80; //big endian
_reg_CSI_CSICR1 |= 0x100; //sync FIFO clear
_reg_CSI_CSICR1 |= 0x0200; //MCLK = HCLK / 2
_reg_CSI_CSICR1 |= 0x1000; //HHTech add:set clock divider(=4)
_reg_CSI_CSICR1 |= 0x20000; //SOF rising edge
_reg_CSI_CSICR1 &= ~0xF000;
// _reg_CSI_CSICR1 |= 0x1000;
_reg_CSI_CSICR1 &= ~0x18000;
_reg_CSI_CSICR1 |= 0x10000;
_reg_CSI_CSICR1 |= 0x80000000;
_reg_CSI_CSICR1 &= ~0x80;
printk("MX21 CSI driver\n");
printk("h/w version %d\n", g_csi_ver);
printk("s/w version 0.0\n"__DATE__" / "__TIME__"\n");
printk("CSI_CSICR1 0x%8x\n",_reg_CSI_CSICR1);
//register CSI character device
result = devfs_register_chrdev(0, "csi2c", &csi_fops);
if ( result < 0 )
{
printk("csi error: unable to register driver\n");
return -ENODEV;
}
devfs_handle = devfs_register(NULL, "csi2c", DEVFS_FL_DEFAULT,
result, 0,
S_IFCHR | S_IRUSR | S_IWUSR,
&csi_fops, NULL);
gMajor = result;
if (request_irq
(31, csi_intr_handler, SA_INTERRUPT, "CSI", NULL))
printk
("*** Cannot register interrupt handler for CSI ! ***\n");
else
printk("CSI interrupt handler registered\n");
malloc_buffer();
sensor_reset();
i2c_test();
ov9650_config_SENSOR(&g_ov9650_cfg);
// ov9650_config_QVGA(&g_ov9650_cfg);
printk("OV9650 Sensor Init OK!\n");
return 0;
}
void __exit cleanup_module()
{
csi_cleanup();
if(gMajor > 0)
{
devfs_unregister_chrdev(gMajor, "csi");
devfs_unregister(devfs_handle);
}
printk("CSI driver is unloaded sucessfully\n\n");
free_irq(31,0);
free_buffer();
return;
}
// DMA support HHTECH
static int csi_open(struct inode *inode, struct file *filp)
{
dma_request_t csi_dma_req = {0};
MOD_INC_USE_COUNT;
return 0;
}
static int csi_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
static ssize_t csi_read(struct file *filp, char *buf, size_t size, loff_t *l)
{
int i;
while(!PRP_poll_ch1_buf1_complete());
copy_to_user(buf, csi_data_buf, size);
return 0;
}
static ssize_t csi_write(struct file *filp, const char *buf, size_t size, loff_t *l)
{
printk("csi error: write ioctl is not implemented\n");
return -1;
}
static int csi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case IOCTL_CSI_READ_CONFIG:
{
csi_read_cfg(&g_csi_cfg);
if(copy_to_user((void *)arg, (void *)&g_csi_cfg, sizeof(CSI_CFG)))
return -EFAULT;
break;
}
case IOCTL_CSI_CONFIG:
{
if(copy_from_user((void *)&g_csi_cfg, (void *)arg, sizeof(CSI_CFG)))
return -EFAULT;
csi_config(&g_csi_cfg);
break;
}
case IOCTL_I2C_R:
{
unsigned char val,reg;
reg = (unsigned char *) arg;
i2c_read(reg,&val);
return val;
}
case IOCTL_I2C_W:
{
unsigned char val,reg;
reg = (unsigned char *)((arg >> 8) & 0xff);
val = (unsigned char *)(arg & 0xff);
i2c_write(reg, val);
return 0;
}
case IOCTL_CSI_READ_STATUS:
{
csi_read_status(&g_csi_status);
if(copy_to_user((void *)arg, (void *)&g_csi_status, sizeof(CSI_STATUS)))
return -EFAULT;
break;
}
case IOCTL_CSI_GET_FRMCNT:
{
int count;
count = csi_get_frame_count();
if(copy_to_user((void *)arg, (void *)&count, sizeof(int)))
return -EFAULT;
break;
}
case IOCTL_CSI_RST_FRMCNT:
{
csi_reset_frame_count();
break;
}
case IOCTL_DMA_CAPTURE:
{
return SFCM_capture_DMA((U32) arg);
break;
}
case IOCTL_STOP_CAPTURE:
break;
case IOCTL_SET_FMT:
switch(arg)
{
case 0:
PRP_init33(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
ov9650_config_QVGA(&g_ov9650_cfg);
break;
case 1:
PRP_init32(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
ov9650_config_VGA(&g_ov9650_cfg);
break;
case 2:
PRP_init31(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
ov9650_config_SXGA(&g_ov9650_cfg);
break;
case 3:
PRP_init33(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
ov9650_config_V_Q(&g_ov9650_cfg);
break;
case 4:
PRP_init33(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
ov9650_config_S_Q(&g_ov9650_cfg);
break;
}
break;
}
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -