📄 csi.c
字号:
/* * MX21 CSI driver * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (C) 2004 Motorola Semiconductors Hong Kong. * *//***@defgroup CSI CSI driver*//**@{*//** *@file csi.c *@brief CSI driver source file * * linux/drivers/csi/csi.c */#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/pm.h>#include <asm/arch/apmc.h>#include "csi.h"/********************************************************************************---------------------------- HARDWARE SPECIFIC -------------------------------*///tapeout 2 specific#ifndef _reg_CSI_CSICR3#define _reg_CSI_CSICR3 (*((volatile unsigned long *)(CSI_IO_ADDRESS(CSI_BASE_ADDR+0x1C))))#endif//globalstatic int g_csi_ver = 2; //version check //-- should be done by s/w, however in current csi design, there is no way to distinguish // TO1 & 2 by softwarestatic int g_csi_busy = 0;static CSI_CFG g_csi_cfg;static CSI_STATUS g_csi_status; //cache copy of csi status register//localstatic void csihw_read_config(CSI_CFG * _cfg);static void csihw_config(CSI_CFG * _cfg);static int csihw_poll(unsigned int * _buf, int byte_size);static void csihw_reset_frame_count(void);static int csihw_get_frame_count(void);static int csihw_pol_eof(int rxcnt); //blockstatic int csihw_pol_sof(void); //blockstatic void csihw_clock_enable(void);static void csihw_clock_disable(void);static void csihw_reset(void);//reset values#define CSICR1_RESET_VAL 0x40000800#define CSICR2_RESET_VAL 0x0#define CSICR3_RESET_VAL 0x0//csi control reg 1#define BIT_SWAP16_EN (0x1 << 31)#define BIT_EXT_VSYNC (0x1 << 30)#define BIT_EOF_INT_EN (0x1 << 29)#define BIT_PRP_IF_EN (0x1 << 28)#define BIT_CCIR_MODE (0x1 << 27)#define BIT_COF_INT_EN (0x1 << 26)#define BIT_SF_OR_INTEN (0x1 << 25)#define BIT_RF_OR_INTEN (0x1 << 24)#define BIT_STATFF_LEVEL (0x3 << 22)#define BIT_STATFF_INTEN (0x1 << 21)#define BIT_RXFF_LEVEL (0x3 << 19)#define BIT_RXFF_INTEN (0x1 << 18)#define BIT_SOF_POL (0x1 << 17)#define BIT_SOF_INTEN (0x1 << 16)#define BIT_MCLKDIV (0xF << 12)#define BIT_HSYNC_POL (0x1 << 11)#define BIT_CCIR_EN (0x1 << 10)#define BIT_MCLKEN (0x1 << 9)#define BIT_FCC (0x1 << 8)#define BIT_PACK_DIR (0x1 << 7)#define BIT_CLR_STATFIFO (0x1 << 6)#define BIT_CLR_RXFIFO (0x1 << 5)#define BIT_GCLK_MODE (0x1 << 4)#define BIT_INV_DATA (0x1 << 3)#define BIT_INV_PCLK (0x1 << 2)#define BIT_REDGE (0x1 << 1)#define SHIFT_STATFF_LEVEL 22#define SHIFT_RXFF_LEVEL 19#define SHIFT_MCLKDIV 12//control reg 3#define BIT_FRMCNT (0xFFFF << 16)#define BIT_FRMCNT_RST (0x1 << 15)#define BIT_CSI_SUP (0x1 << 3)#define BIT_ZERO_PACK_EN (0x1 << 2)#define BIT_ECC_INT_EN (0x1 << 1)#define BIT_ECC_AUTO_EN (0x1)#define SHIFT_FRMCNT 16//csi status reg#define BIT_SFF_OR_INT (0x1 << 25)#define BIT_RFF_OR_INT (0x1 << 24)#define BIT_STATFF_INT (0x1 << 21)#define BIT_RXFF_INT (0x1 << 18)#define BIT_EOF_INT (0x1 << 17)#define BIT_SOF_INT (0x1 << 16)#define BIT_F2_INT (0x1 << 15)#define BIT_F1_INT (0x1 << 14)#define BIT_COF_INT (0x1 << 13)#define BIT_ECC_INT (0x1 << 1)#define BIT_DRDY (0x1 << 0)static void csihw_read_status(CSI_STATUS * _status){ _status->sff_or_int = (_reg_CSI_CSISR & BIT_SFF_OR_INT) ? 1 : 0; _status->rff_or_int = (_reg_CSI_CSISR & BIT_RFF_OR_INT) ? 1 : 0; _status->statff_int = (_reg_CSI_CSISR & BIT_STATFF_INT) ? 1 : 0; _status->rxff_int = (_reg_CSI_CSISR & BIT_RXFF_INT) ? 1 : 0; _status->eof_int = (_reg_CSI_CSISR & BIT_EOF_INT) ? 1 : 0; _status->sof_int = (_reg_CSI_CSISR & BIT_SOF_INT) ? 1 : 0; _status->f2_int = (_reg_CSI_CSISR & BIT_F2_INT) ? 1 : 0; _status->f1_int = (_reg_CSI_CSISR & BIT_F1_INT) ? 1 : 0; _status->cof_int = (_reg_CSI_CSISR & BIT_COF_INT) ? 1 : 0; _status->ecc_int = (_reg_CSI_CSISR & BIT_ECC_INT) ? 1 : 0; _status->drdy = (_reg_CSI_CSISR & BIT_DRDY) ? 1 : 0; return;}static void csi_irq_handler(int irq, void * data, struct pt_regs * pt){ csihw_read_status(&g_csi_status);//go to individual handlers//leave it untouched if user has not enabled the interrupt if(g_csi_cfg.rf_or_inten) { if(g_csi_status.rff_or_int) { g_csi_status.rff_or_int = 0; printk("csi error: rxff overflow\n"); //flush fifo _reg_CSI_CSICR1 &= ~BIT_FCC; _reg_CSI_CSICR1 |= BIT_CLR_RXFIFO; if(g_csi_cfg.fcc) _reg_CSI_CSICR1 |= BIT_FCC; _reg_CSI_CSISR = BIT_RFF_OR_INT; } } if(g_csi_cfg.sof_inten) { if(g_csi_status.sof_int) { _reg_CSI_CSISR = BIT_SOF_INT; g_csi_status.sof_int = 0; } } return;}static void csihw_read_config(CSI_CFG * _cfg){ unsigned int tmp; unsigned val;//1. read from register //control reg 1 val = _reg_CSI_CSICR1; _cfg->swap16_en = (val & BIT_SWAP16_EN)? 1 : 0; _cfg->ext_vsync = (val & BIT_EXT_VSYNC)? 1 : 0; _cfg->eof_int_en = (val & BIT_EOF_INT_EN)? 1 : 0; _cfg->prp_if_en = (val & BIT_PRP_IF_EN)? 1 : 0; _cfg->ccir_mode = (val & BIT_CCIR_MODE)? 1 : 0; _cfg->cof_int_en = (val & BIT_COF_INT_EN)? 1 : 0; _cfg->sf_or_inten = (val & BIT_SF_OR_INTEN)? 1 : 0; _cfg->rf_or_inten = (val & BIT_RF_OR_INTEN)? 1 : 0; tmp = (val & BIT_STATFF_LEVEL) >> SHIFT_STATFF_LEVEL; if(tmp == 0x3) _cfg->statff_level = 16; else if(tmp == 0x2) _cfg->statff_level = 12; else if(tmp == 0x1) _cfg->statff_level = 8; else _cfg->statff_level = 4; _cfg->staff_inten = (val & BIT_STATFF_INTEN)? 1 : 0; tmp = (val & BIT_RXFF_LEVEL) >> SHIFT_RXFF_LEVEL; if(tmp == 0x3) _cfg->rxff_level = 24; else if(tmp == 0x2) _cfg->rxff_level = 16; else if(tmp == 0x1) _cfg->rxff_level = 8; else _cfg->rxff_level = 4; _cfg->rxff_inten = (val & BIT_RXFF_INTEN)? 1 : 0; _cfg->sof_pol = (val & BIT_SOF_POL)? 1 : 0; _cfg->sof_inten = (val & BIT_SOF_INTEN)? 1 : 0; tmp = (val & BIT_MCLKDIV) >> SHIFT_MCLKDIV; _cfg->mclkdiv = (tmp + 1) * 2; _cfg->hsync_pol = (val & BIT_HSYNC_POL)? 1 : 0; _cfg->ccir_en = (val & BIT_CCIR_EN)? 1 : 0; _cfg->mclken = (val & BIT_MCLKEN)? 1 : 0; _cfg->fcc = (val & BIT_FCC)? 1 : 0; _cfg->pack_dir = (val & BIT_PACK_DIR)? 1 : 0; _cfg->gclk_mode = (val & BIT_GCLK_MODE)? 1 : 0; _cfg->inv_data = (val & BIT_INV_DATA)? 1 : 0; _cfg->inv_pclk = (val & BIT_INV_PCLK)? 1 : 0; _cfg->redge = (val & BIT_REDGE)? 1 : 0; //control reg 3 val = _reg_CSI_CSICR3; _cfg->csi_sup = (val & BIT_CSI_SUP)? 1 : 0; _cfg->zero_pack_en = (val & BIT_ZERO_PACK_EN)? 1 : 0; _cfg->ecc_int_en = (val & BIT_ECC_INT_EN)? 1 : 0; _cfg->ecc_auto_en = (val & BIT_ECC_AUTO_EN)? 1 : 0; //rxfifo reg val = _reg_CSI_CSIRXCNT; //keep system settings _cfg->module_irq_enable = g_csi_cfg.module_irq_enable;//2. update global config memcpy(&g_csi_cfg, _cfg, sizeof(CSI_CFG)); return;}static void csihw_config(CSI_CFG * _cfg){ unsigned int tmp; unsigned val = 0x0; int rt;//1. write to registers //control reg 1 if(_cfg->swap16_en) val |= BIT_SWAP16_EN; if(_cfg->ext_vsync) val |= BIT_EXT_VSYNC; if(_cfg->eof_int_en) val |= BIT_EOF_INT_EN; if(_cfg->prp_if_en) val |= BIT_PRP_IF_EN; if(_cfg->ccir_mode) val |= BIT_CCIR_MODE; if(_cfg->cof_int_en) val |= BIT_COF_INT_EN; if(_cfg->sf_or_inten) val |= BIT_SF_OR_INTEN; if(_cfg->rf_or_inten) val |= BIT_RF_OR_INTEN; if(_cfg->statff_level == 16) tmp = 0x3; else if(_cfg->statff_level == 12) tmp = 0x2; else if(_cfg->statff_level == 8) tmp = 0x1; else tmp = 0x0; val |= (tmp << SHIFT_STATFF_LEVEL); if(_cfg->staff_inten) val|= BIT_STATFF_INTEN; if(_cfg->rxff_level == 24) tmp = 0x3; else if(_cfg->rxff_level == 16) tmp = 0x2; else if(_cfg->rxff_level == 8) tmp = 0x1; else tmp = 0x0; val |= (tmp << SHIFT_RXFF_LEVEL); if(_cfg->rxff_inten) val |= BIT_RXFF_INTEN; if(_cfg->sof_pol) val |= BIT_SOF_POL; if(_cfg->sof_inten) val |= BIT_SOF_INTEN; tmp = (_cfg->mclkdiv / 2) - 1; val |= (tmp << SHIFT_MCLKDIV); if(_cfg->hsync_pol) val |= BIT_HSYNC_POL; if(_cfg->ccir_en) val |= BIT_CCIR_EN; if(_cfg->mclken) val |= BIT_MCLKEN; if(_cfg->fcc) val |= BIT_FCC; if(_cfg->pack_dir) val |= BIT_PACK_DIR; if(_cfg->gclk_mode) val |= BIT_GCLK_MODE; if(_cfg->inv_data) val |= BIT_INV_DATA; if(_cfg->inv_pclk) val |= BIT_INV_PCLK; if(_cfg->redge) val |= BIT_REDGE; _reg_CSI_CSICR1 = val; //control reg 3 val = 0x0; if(_cfg->csi_sup) val |= BIT_CSI_SUP; if(_cfg->zero_pack_en) val |= BIT_ZERO_PACK_EN; if(_cfg->ecc_int_en) val |= BIT_ECC_INT_EN; if(_cfg->ecc_auto_en) val |= BIT_ECC_AUTO_EN; _reg_CSI_CSICR3 = val; //rxfifo counter _reg_CSI_CSIRXCNT = _cfg->rxcnt;//2. update global config memcpy(&g_csi_cfg, _cfg, sizeof(CSI_CFG));//3. interrupt enable if(_cfg->module_irq_enable) { rt = request_irq(INT_CSI, csi_irq_handler, SA_INTERRUPT, "csi", "csi"); if(rt) printk("csi error: irq request fail\n"); } //4. init status flags memset(&g_csi_status, 0, sizeof(CSI_CFG)); return;}//nothing special, simply set gpiostatic void csihw_init(void){//disable GPIO PB[21..10] _reg_GPIO_GIUS(GPIOB) &= ~0x3FFC00;//note -- csi version check should be here... return;}static void csihw_cleanup(void){//resume GPIO PB[21..10] _reg_GPIO_GIUS(GPIOB) |= 0x3FFC00; csihw_clock_disable(); csihw_reset(); return;}//generate default mclk to drive sensorstatic void csihw_open(void){ unsigned int val; unsigned int perclk4div = 3; //default set to fclk/3 => 88MHz unsigned int mclkdiv = 4; //default set to perclk4/4 => 22MHz csihw_clock_enable();//set default perclk4 for mclk if(g_csi_ver == 2) { val = _reg_CRM_PCDR1; val &= ~(0x3F << 24); val |= (perclk4div - 1) << 24; _reg_CRM_PCDR1 = val; } csihw_reset(); //enable default mclk clock val = CSICR1_RESET_VAL; val |= ((mclkdiv / 2) - 1) << SHIFT_MCLKDIV; val |= BIT_MCLKEN; _reg_CSI_CSICR1 = val; return;}static void csihw_release(void){ //nothing to do //as a result, the csi state will not unchange unless the module is unloaded return;}//Read a frame by pollingstatic int csihw_poll(unsigned int * _buf, int byte_size){ int i, j; int word_size = byte_size >> 2; unsigned int *_kbuf = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -