📄 csi2c1.c
字号:
return; } i2c_csi_client.adapter->inc_use( i2c_csi_client.adapter );}static void I2C_cleanup(void){ i2c_detach_client(&i2c_csi_client ); i2c_del_driver(&i2c_csi_driver);}//-------------------------------//// Port enable for CSI signals////-------------------------------static void port_init_CSI(void){// PA14 : CSI_PIXCLK// PA13 : CSI_HSYNC// PA12 : CSI_VSYNC// PA11 : CSI_D7// PA10 : CSI_D6// PA9 : CSI_D5// PA8 : CSI_D4// PA7 : CSI_D3// PA6 : CSI_D2// PA5 : CSI_D1// PA4 : CSI_D0// PA3 : CSI_MCLK * (U32 *)PTA_DDIR |= 0x00007FF8; * (U32 *)PTA_GIUS &= ~0x00007FF8; return;}//// Offset Calibration Block///*static void offsetCal(void){ I2C_write(0x20, 0x00); I2C_write(0x21, 0x10); I2C_write(0x23, 0x2A);//offset RAM registers// 12 sets of 64 columns (768 total columns) int i, j; for (i=0; i < 12; i++) { // Fixing columns with 1st method. for (j=0; j < 33; j++) { I2C_write(0x22,0x00); } I2C_write(0x22,0x0a); // neg offset (bright col) I2C_write(0x22,0x09); // neg offset (bright col) I2C_write(0x22,0x01); // pos offset (dark col) I2C_write(0x22,0x02); // pos offset (dark col) for (j=0; j < 27; j++) { I2C_write(0x22,0x00); } } //change by tony I2C_write(0x0A,0x80);}*/static void U32 CSI_init(){// U32 mclkdiv;// U32 MCLKDIV;//set port for CSI signals port_init_CSI();//clock divider setting// mclkdiv = systemClock / sensorClock;// if(mclkdiv % 2) //truncate to divider to even nos.// mclkdiv -= 1;// MCLKDIV = (((mclkdiv / 2) - 1) << 12) & 0xF000; //gen register value * (U32 *)CSI_CTRL_REG1 = 0x00000000; //module reset * (U32 *)CSI_CTRL_REG1 = 0x00000001; //module enable * (U32 *)CSI_CTRL_REG1 |= 0x000; //MCLK enable * (U32 *)CSI_CTRL_REG1 |= MCLKDIV; //set clock divider//our sensor has its own clock * (U32 *)CSI_CTRL_REG1 |= 0x00020000; //SOF int disabled, SOF = rising edge * (U32 *)CSI_CTRL_REG1 |= 0x00040000; //RxFIFO full int enb * (U32 *)CSI_CTRL_REG1 |= 0x00000100; //sync clear FIFOs * (U32 *)CSI_CTRL_REG1 |= 0x01000000; //RX FIFO overrun interrupt enable//// Set FIFO full level//// This is a system timing issue, a HIGHER full level would produce// LESS interrupt, which may reduce the overhead of ISR or polling// * (U32 *)CSI_CTRL_REG1 &= ~0x180000; //full = 16 words * (U32 *)CSI_CTRL_REG1 |= 0x100000; //full = 16 words//return the truncated sensor clock// gSensorClock = sensorClock = systemClock / mclkdiv;// changed by tony port_init_SENSOR(); // toggle INIT pin of sensor to hard reset it *(U32 *)PTB_DR |= (0x1 << 18); // RESET asserted *(U32 *)PTB_DR &= ~(0x1 << 18); // RESET released // // do soft reset of sensor// I2C_write(0x0E, 0x03); //sensor reset// I2C_write(0x0E, 0x00); //clear reset// change by tony 2004-4-10 // set global gain, TO control the input mode// I2C_write(0x10, 0); I2C_write(0x01,0x00); I2C_write(0x02,0xC1); // set color gain I2C_write(0x03,0x23); I2C_write(0x04,0x00); I2C_write(0x05,0x00); /*I2C_write(0x00, 0x06); // Green of Green-Red Row I2C_write(0x01, 0x0C); // Red I2C_write(0x02, 0x0E); // Blue I2C_write(0x03, 0x06); // Green of Blue-Green Row *///同步控制 I2C_write(0x06,0xEB); I2C_write(0x07,0xE0); I2C_write(0x08,0x88);//亮度、色度控制 I2C_write(0x09,0x01);// I2C_write(0x0A,0x80); I2C_write(0x0B,0x47); I2C_write(0x0C,0x40); I2C_write(0x0D,0x00); I2C_write(0x0E,0x01); ///////// //output format control YUV CCIR-656 8 bits I2C_write(0x10,0xC0); I2C_write(0x11,0x1C); I2C_write(0x12,0x00); I2C_write(0x13,0x00); I2C_write(0x14,0x00); I2C_write(0x15,0x00); I2C_write(0x16,0x00); I2C_write(0x17,0x00);/* // Power Configuration // I2C_write(0x0C, 0x40); // Color Tile Configuration I2C_write(0x05, 0x05); // Color Tile Configuration I2C_write(0x06, 0x44); // Row 1 Definition I2C_write(0x07, 0xEE); // Row 2 Definition I2C_write(0x08, 0x00); // Row 3 Definition I2C_write(0x09, 0x00); // Row 4 Definition // Set Voltage Reference I2C_write(0x0A, 0x76); // Negative Voltage I2C_write(0x0B, 0x80); // Positive Voltage // Post ADC Control I2C_write(0x30, 0xFE); // While Pixel Threshold I2C_write(0x31, 0x01); // Black Pixel Threshold I2C_write(0x32, 0x00); // Post ADC Control // Timing Control I2C_write(0x54, 0xC0); // SOF control I2C_write(0x55, 0x90); // VCLK control I2C_write(0x63, 0x08); // Factory Use Only Register, // but you have to set it like this I2C_write(0x60, 0x00); // Internal Timing*/ // Offset Calibration // offsetCal();/* // capture mode setting I2C_write(0x40, 0x35); // Continuous capture, continuous streaming // set WOI I2C_write(0x4B, 0x02); // WOI width (640) I2C_write(0x4C, 0x7F); I2C_write(0x47, 0x01); // WOI Depth (480) I2C_write(0x48, 0xDF); I2C_write(0x49, 0x00); // WOI column pointer (48) I2C_write(0x4A, 48); I2C_write(0x45, 0x00); // WOI row pointer (20) I2C_write(0x46, 20); *//* I2C_write(0x50, 0x02); // WOI width (640+11) I2C_write(0x51, 0x8B); */ return ;}//---------------------------//// SENSOR Register Write////---------------------------//#define DEBUG_I2CWR#ifdef DEBUG_I2CWR#define dprinti2cwr(str...) printk("<"__FUNCTION__"> "str)#else#define dprinti2cwr(str...) // nothing#endifstatic void I2C_write(U32 reg, U32 data){ struct i2c_msg msg; char buf[2]; /* * store the register value to the first address of the buffer * the adapter/algorithm driver will regard the first byte * as the register value */ buf[0] = (char)reg; buf[1] = (char)data; msg.addr = i2c_csi_client.addr; msg.flags = I2C_M_WRITE;// msg.len = count; msg.len = 2; msg.buf = buf; /* * initialize the message structure */ i2c_transfer( i2c_csi_client.adapter, &msg, 1 );}//---------------------------//// SENSOR Register Read////---------------------------static void I2C_read(U32 reg, U32 * _data){ struct i2c_msg msg[2]; char buf; char command; /* * store the register value to the first address of the buffer * the adapter/algorithm driver will regard the first byte * as the register value */ buf = 0; command = (char)reg; /* * initialize the message structure */ msg[0].addr = i2c_csi_client.addr; msg[0].flags = 0x00;// msg.len = count; msg[0].len = 1; msg[0].buf = &command; msg[1].addr = i2c_csi_client.addr; msg[1].flags = I2C_M_READ;// msg.len = count; msg[1].len = 1; msg[1].buf = &buf; i2c_transfer( i2c_csi_client.adapter, msg, 2 ); *_data = (U32)buf;}void setPortSYNC(U32 level){ if(level) * (U32 *)PTA_DR |= 0x00800000; else * (U32 *)PTA_DR &= ~0x00800000; return;}//-------------------------------//// Port enable for SENSOR signals////-------------------------------static void port_init_SENSOR(void){//PA23 = SYNC (~CS5)//config PA23 for SYNC * (U32 *)PTA_DR &= ~0x00800000; * (U32 *)PTA_GIUS |= 0x00800000; * (U32 *)PTA_OCR2 |= 0x0000C000; * (U32 *)PTA_DDIR |= 0x00800000; * (U32 *)PTA_GPR |= 0x00800000;// * (U32 *)PTA_DR |= 0x00800000;//default set port to low// * (U32 *)PTA_DR &= ~0x00800000;}//------------------------------------//// Capture image data with DMA//// Unified function for all // supported image size capture//// Return TRUE if success// Return FALSE if FIFO is overrun////------------------------------------static U32 SFCM_capture_DMA(U32 nPixel){ dma_data_size = nPixel; readSeqNum = capSeqNum = SOFseqNum = 0; stopCapture = 0; * (U32 *)CSI_STS_REG = 0x10000; //clear last SOF irq * (U32 *)CSI_CTRL_REG1 |= 0x60; //prepare for sync clear FIFOs *(U32 *)CSI_CTRL_REG1 |= 0x10000; //enable SOF intr return TRUE;}static void dma_complete_handler(){ *((U32 *)(DMA_CCR0+dma_channel*0x40)) = 0x800; // disable DMA channel *((U32 *)DMA_ISR) = (1<<dma_channel); // clear DMA complete interrupt flag if (stopCapture) { dmaStopped = 1; wake_up_interruptible(&stop_capture_wait); return; } if (*(U32 *)CSI_STS_REG & 1) { // printk("!!! Data in FIFO !!!\n"); return; } capSeqNum++;// if (!stopCapture)// { *((U32 *)(DMA_DAR0+dma_channel*0x40)) = dma_buf_phy_addr; // destination *((U32 *)(DMA_CNTR0+dma_channel*0x40)) = dma_data_size; // count *((U32 *)(DMA_CCR0+dma_channel*0x40)) = 0x809; // enable DMAchannel badFrame = 0; // mark a good frame wake_up_interruptible(&dma_wait);// }}static void dma_error_handler(int error_type){ printk("*** CSI DMA error, type = 0x%08x ! ***\n", error_type);}static void csi_intr_handler(int irq, void *dev_id, struct pt_regs *regs){ if (*(U32 *)CSI_STS_REG & 0x10000) // SOF intr ? { *(U32 *)CSI_STS_REG = 0x10000; // clear SOF intr if (stopCapture) { *(U32 *)CSI_CTRL_REG1 &= ~0x10000; //disable SOF intr SOFintrStopped = 1; wake_up_interruptible(&stop_capture_wait); return; } else { if (SOFseqNum==0) // first SOF interrupt ? { *((U32 *)(DMA_DAR0+dma_channel*0x40)) = dma_buf_phy_addr; // destination *((U32 *)(DMA_CNTR0+dma_channel*0x40)) = dma_data_size; // count *((U32 *)(DMA_CCR0+dma_channel*0x40)) = 0x809; // enable DMAchannel } else // subsequent SOF interrupt (for data lost checking) { if (capSeqNum < SOFseqNum) // i.e. DMA NOT completed on-time { // re-sync data capSeqNum++; *((U32 *)(DMA_CCR0+dma_channel*0x40)) = 0x800; // disable DMA channel // Notify read routine that there has been a bad frame badFrame = 1; wake_up_interruptible(&dma_wait); *((U32 *)(DMA_DAR0+dma_channel*0x40)) = dma_buf_phy_addr; // destination *((U32 *)(DMA_CNTR0+dma_channel*0x40)) = dma_data_size; // count *((U32 *)(DMA_CCR0+dma_channel*0x40)) = 0x809; // enable DMAchannel } } readSeqNum = SOFseqNum; // reading of last frame is not allowed SOFseqNum++; } return; } printk("*** unknown interrupt ***\n"); *(U32 *)CSI_STS_REG = *(U32 *)CSI_STS_REG; // clear all remaining interrupt flags}static devfs_handle_t devfs_handle;int init_module(){ int result; printk("CSI driver "__DATE__" / "__TIME__"\n"); /* register our character device */ result = devfs_register_chrdev(0, "csi2c", &csi2c_fops); if ( result < 0 ) { printk("csi2c driver: Unable to register driver\n"); return -ENODEV; } devfs_handle = devfs_register(NULL, "csi2c", DEVFS_FL_DEFAULT, result, 0, S_IFCHR | S_IRUSR | S_IWUSR, &csi2c_fops, NULL); printk("make node for csi2c with 'mknod csi2c c %d 0'\n", result); gMajor = result; //init GPIO (PB19 / SIM_CLK) - used as STDBY by new CMOS sensor *((U32 *)PTB_GIUS) |= 0x1 << 19; *((U32 *)PTB_OCR2) |= 0x3 << (19 * 2 - 32); *((U32 *)PTB_DDIR) |= 0x1 << 19; *((U32 *)PTB_GPR ) |= 0x1 << 19; *((U32 *)PTB_DR ) &= ~(0x1 << 19); // normal mode // init GPIO (PB18) - used as CMOS H/W reset by CMOS sensor *((U32 *)PTB_GIUS) |= 0x1 << 18; *((U32 *)PTB_OCR2) |= 0x3 << (18 * 2 - 32); *((U32 *)PTB_DDIR) |= 0x1 << 18; *((U32 *)PTB_GPR ) |= 0x1 << 18; *((U32 *)PTB_DR ) &= ~(0x1 << 18); // RESET released if (request_irq(CSI_IRQ, csi_intr_handler, SA_INTERRUPT, "CSI", NULL)) printk("*** Cannot register interrupt handler for CSI ! ***\n"); else printk("CSI interrupt handler registered\n"); I2C_init(); malloc_buffer(); return 0;}void cleanup_module(){ if (gMajor > 0){ devfs_unregister_chrdev(gMajor, "csi2c"); devfs_unregister(devfs_handle); } free_irq(CSI_IRQ, 0); I2C_cleanup(); free_buffer(); printk("Say goodbye to csi2c\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -