📄 csi.c
字号:
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;//read rx fifo 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 < g_csi_cfg.rxff_level; i ++) _kbuf[j ++] = _reg_CSI_CSIRXR; } if(j >= word_size) break; } copy_to_user(_buf, _kbuf, byte_size); free_pages((int)_kbuf, korder); _kbuf = 0; return 0;}static void csihw_reset_frame_count(void){ _reg_CSI_CSICR3 |= BIT_FRMCNT_RST; return;}static int csihw_get_frame_count(void){ int count; count = _reg_CSI_CSICR3 >> SHIFT_FRMCNT; return count;}//block until eof is detected//not to be used with prpstatic int csihw_pol_eof(int rxcnt){ int cnt = 0; int trial_cnt = 10000000; if(rxcnt != 0) { //use this rxcnt _reg_CSI_CSIRXCNT = rxcnt; } else { //otherwise use the rxcnt in csi config _reg_CSI_CSIRXCNT = g_csi_cfg.rxcnt; } //clear interrupt first if(_reg_CSI_CSISR & BIT_EOF_INT) _reg_CSI_CSISR = BIT_EOF_INT; while(1) { if(_reg_CSI_CSISR & BIT_EOF_INT) { _reg_CSI_CSISR = BIT_EOF_INT; break; } else { if(cnt ++ > trial_cnt) {// printk("csi err: eof timeout\n"); return 1; } } } return 0;}//block until sof is detectedstatic int csihw_pol_sof(void){ int cnt = 0; int trial_cnt = 10000000; //clear interrupt first if(_reg_CSI_CSISR & BIT_SOF_INT) _reg_CSI_CSISR = BIT_SOF_INT; while(1) { if(_reg_CSI_CSISR & BIT_SOF_INT) { _reg_CSI_CSISR = BIT_SOF_INT; break; } else { if(cnt ++ > trial_cnt) { printk("csi err: sof timeout\n"); return 1; } } } return 0;}static void csihw_clock_enable(void){//turn on hclk & perclk4//caution -- if sensor clock (mclk) is provided by csi,// make sure csi is resumed before sensor is resumed _reg_CRM_PCCR0 |= 0x80000000; if(g_csi_ver == 2) _reg_CRM_PCCR0 |= 0x00400000; return; }static void csihw_clock_disable(void){//shutdown hclk & perclk4//caution -- if sensor clock (mclk) is provided by csi,// make sure the sensor is suspend before csi is suspend _reg_CRM_PCCR0 &= ~0x80000000; if(g_csi_ver == 2) _reg_CRM_PCCR0 &= ~0x00400000; return;}//csi reset, really can reset??static void csihw_reset(void){ csihw_clock_enable(); _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 } return;}/********************************************************************************---------------------------- LINUX OS SPECIFIC -------------------------------*///global staticstatic devfs_handle_t devfs_handle = NULL;static int gMajor = 0;static struct pm_dev *pmdev;static struct apmc_user *g_csi_apmc;//functions and interfacestatic 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);static int csi_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data);struct file_operations csi_fops = { open: csi_open, release: csi_release, read: csi_read, write: csi_write, ioctl: csi_ioctl,};/***@brief The module entry function of the CSI driver.* It does only the basic things such as csihw_init() and register_chrdev().* Module clock is turned on in open().* DMA & IRQ are turned on later in the function csihw_config().**@return @li 0 Success* @li others Failure*/int __init init_module(){ int result; printk("Motorola CSI Linux driver ver 0.1\n" " - Copyright (C) 2004 Motorola Inc\n\n"); csihw_init();//register CSI character device result = devfs_register_chrdev(0, "csi", &csi_fops); if ( result < 0 ) { printk("csi error: unable to register chr driver\n"); return -ENODEV; } devfs_handle = devfs_register(NULL, "csi", DEVFS_FL_DEFAULT, result, 0, S_IFCHR | S_IRUSR | S_IWUSR, &csi_fops, NULL); if(devfs_handle == NULL) { printk("csi error: unable to register driver\n"); return -ENODEV; } gMajor = result; g_csi_busy = 0;//power management if ((pmdev = pm_register(PM_CSI_DEV, PM_SYS_UNKNOWN, csi_pm_handler)) == NULL) { printk("csi error: failed to register PM... continuing with driver init\n"); } g_csi_apmc = apmc_register(APMC_LEVEL_HIGHEST); return 0;}/***@brief The module exit function of the CSI driver.**@return NULL*/void __exit cleanup_module(){ csihw_cleanup(); apmc_unregister(g_csi_apmc); pm_unregister(pmdev); if(gMajor > 0) { if(devfs_unregister_chrdev(gMajor, "csi") < 0) { printk("csi error: failed to unregister from devfs\n"); return; } } if(devfs_handle != NULL) devfs_unregister(devfs_handle); else { printk("csi error: failed to unregister from devfs, devfs_handle = 0x%08X\n", (int)devfs_handle); return; } printk("CSI driver is unloaded sucessfully\n"); return;}/***@brief Open the CSI **@param inode structure inode list pointer*@param filp structure file list pointer*@return 0*/static int csi_open(struct inode *inode, struct file *filp){ csihw_open(); MOD_INC_USE_COUNT; return 0;}/***@brief Release the CSI **@param inode structure inode list pointer*@param filp structure file list pointer*@return 0*/static int csi_release(struct inode *inode, struct file *filp){ csihw_release(); MOD_DEC_USE_COUNT; return 0; }/***@brief This function is to read the data from the CSI client device through the CSI interface.* Reading the data by calling the function csihw_poll().**@param filp structure file list pointer*@param buf the buffer to store the data*@param size size of the buffer, the number of bytes*@param l loff_t type pointer, not used*@return 0*/static ssize_t csi_read(struct file *filp, char *buf, size_t size, loff_t *l){ g_csi_busy = 1; csihw_poll((unsigned int *)buf, (int)size); g_csi_busy = 0; return 0;}/***@brief This function is only called when "csi error: write ioctl is not implemented" happens.* csi_write() includes only a statement "printk" because it's unnecessary to write to a CSI client device.**@param filp structure file list pointer*@param buf the buffer to store the data*@param size size of the buffer*@param l the register number in the I2C slave (SSI sensor)*@return -1*/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;}/***@brief CSI ioctl operation**There are five kinds of commands*@li IOCTL_CSI_READ_CONFIG*@li IOCTL_CSI_CONFIG*@li IOCTL_CSI_READ_STATUS*@li IOCTL_CSI_GET_FRMCNT*@li IOCTL_CSI_RST_FRMCNT**@param inode structure inode list pointer*@param filp structure file list pointer*@param cmd The command to control the codec.*@param arg The void pointer used to communicate with user space.*@return @li 0 Success* @li others Failure*/static int csi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ switch(cmd) { case IOCTL_CSI_READ_CONFIG: { csihw_read_config(&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; csihw_config(&g_csi_cfg); break; } case IOCTL_CSI_READ_STATUS: { csihw_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 = csihw_get_frame_count(); if(copy_to_user((void *)arg, (void *)&count, sizeof(int))) return -EFAULT; break; } case IOCTL_CSI_RST_FRMCNT: { csihw_reset_frame_count(); break; } case IOCTL_CSI_POLL_EOF: { csihw_pol_eof(arg); //block break; } case IOCTL_CSI_POLL_SOF: { csihw_pol_sof(); //block break; } case IOCTL_CSI_RESET: { csihw_reset(); break; } } return 0;}static int csi_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data){ switch(rqst) { case PM_SUSPEND: { if(g_csi_busy) { //does not allow suspend when there is a data transfer between csi fifo & memory return 1; } else { csihw_clock_disable();// printk("csi: suspend\n"); } break; } case PM_RESUME: { csihw_clock_enable();// printk("csi: resume\n"); break; } } return 0;}/**@}*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -