📄 s3c2410-can-mcp2510.c
字号:
}// Setup the CAN buffers used by the application.// We currently use only one for reception and one for transmission.// It is possible to use several to get a simple form of queue.//// We setup the unit to receive all CAN messages.// As we only have at most 4 different messages to receive, we could use the// filters to select them for us.//// mcp_init() should already have been called.static void MCP2510_Setup(PCanFilter pfilter){ // As no filters are active, all messages will be stored in RXB0 only if // no roll-over is active. We want to recieve all CAN messages (standard and extended) // (RXM<1:0> = 11). //SPI_mcp_write_bits(RXB0CTRL, RXB_RX_ANY, 0xFF); //SPI_mcp_write_bits(RXB1CTRL, RXB_RX_ANY, 0xFF); // But there is a bug in the chip, so we have to activate roll-over. if(pfilter){ //有过滤器 MCP2510_WriteBits(RXB0CTRL, (RXB_BUKT|RXB_RX_STDEXT|RXB_RXRTR|RXB_RXF0), 0xFF); MCP2510_WriteBits(RXB1CTRL, RXB_RX_STDEXT, 0xFF); } else{ MCP2510_WriteBits(RXB0CTRL, (RXB_BUKT|RXB_RX_ANY|RXB_RXRTR), 0xFF); MCP2510_WriteBits(RXB1CTRL, RXB_RX_ANY, 0xFF); }}/***********************************************************************************\ 发送数据 参数: data,发送数据 Note: 使用三个缓冲区循环发送,没有做缓冲区有效检测\***********************************************************************************/static int ntxbuffer=0;static inline void MCP2510_canTxBuffer(void){ switch(ntxbuffer){ case 0: MCP2510_transmit(TXB0CTRL); ntxbuffer=1; break; case 1: MCP2510_transmit(TXB1CTRL); ntxbuffer=2; break; case 2: MCP2510_transmit(TXB2CTRL); ntxbuffer=0; break; }}static inline void MCP2510_canWrite(PCanData data){ MCP2510_Write_Can(ntxbuffer, data); MCP2510_canTxBuffer();}static inline void MCP2510_canWriteData(char *pbuffer, int nbuffer){ MCP2510_Write_CanData(ntxbuffer, pbuffer, nbuffer); MCP2510_canTxBuffer();}static inline void MCP2510_canWriteRTR(void){ MCP2510_Write_CanRTR(ntxbuffer); MCP2510_canTxBuffer();}/***********************************************************************************\ 中断服务程序 \***********************************************************************************/static void s3c2410_isr_mcp2510(int irq, void *dev_id, struct pt_regs *reg){ unsigned char byte; DPRINTK("enter interrupt!\n"); byte=MCP2510_Read(CANINTF); if(byte & RX0INT){ MCP2510_Read_Can(3,&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanRevpos])); MCP2510_WriteBits(CANINTF, ~RX0INT, RX0INT); // Clear interrupt NextCanDataPos(mcp2510dev.nCanRevpos); DPRINTK("mcp2510dev.nCanRevpos= %d\n", mcp2510dev.nCanRevpos); DPRINTK("mcp2510dev.nCanReadpos= %d\n", mcp2510dev.nCanReadpos); } if(byte & RX1INT){ MCP2510_Read_Can(4,&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanRevpos])); MCP2510_WriteBits(CANINTF, ~RX1INT, RX1INT); // Clear interrupt NextCanDataPos(mcp2510dev.nCanRevpos); } if(byte & (RX0INT|RX1INT)){ wake_up_interruptible(&(mcp2510dev.wq)); }}/*********************************************************************\ CAN设备初始化函数 参数: bandrate,CAN波特率\*********************************************************************/static int init_MCP2510(CanBandRate bandrate){ unsigned char i,j,a; MCP2510_Reset(); MCP2510_SetBandRate(bandrate,FALSE); // Disable interrups. MCP2510_Write(CANINTE, NO_IE); // Mark all filter bits as don't care: MCP2510_Write_Can_ID(RXM0SIDH, 0, TRUE); MCP2510_Write_Can_ID(RXM1SIDH, 0, TRUE); // Anyway, set all filters to 0: MCP2510_Write_Can_ID(RXF0SIDH, 0, 0); MCP2510_Write_Can_ID(RXF1SIDH, 0, 0); MCP2510_Write_Can_ID(RXF2SIDH, 0, 0); MCP2510_Write_Can_ID(RXF3SIDH, 0, 0); MCP2510_Write_Can_ID(RXF4SIDH, 0, 0); MCP2510_Write_Can_ID(RXF5SIDH, 0, 0); MCP2510_Write_Can_ID(TXB0SIDH, 123, 0); MCP2510_Write_Can_ID(TXB1SIDH, 100, 0); MCP2510_Write_Can_ID(TXB2SIDH, 111, 0); //Enable clock output MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); // Clear, deactivate the three transmit buffers a = TXB0CTRL; for (i = 0; i < 3; i++) { for (j = 0; j < 14; j++) { MCP2510_Write(a, 0); a++; } a += 2; // We did not clear CANSTAT or CANCTRL } // and the two receive buffers. MCP2510_Write(RXB0CTRL, 0); MCP2510_Write(RXB1CTRL, 0); // The two pins RX0BF and RX1BF are used to control two LEDs; set them as outputs and set them as 00. MCP2510_Write(BFPCTRL, 0x3C); return 0;}static void MCP2510_SetFilter(PCanFilter pfilter){ MCP2510_Write(MCP2510REG_CANCTRL, MODE_CONFIG); // Disable interrups. MCP2510_Write(CANINTE, NO_IE); if(!pfilter){ // Mark all filter bits as don't care: MCP2510_Write_Can_ID(RXM0SIDH, 0, TRUE); MCP2510_Write_Can_ID(RXM1SIDH, 0, TRUE); // Anyway, set all filters to 0: MCP2510_Write_Can_ID(RXF0SIDH, 0, 0); MCP2510_Write_Can_ID(RXF1SIDH, 0, 0); MCP2510_Write_Can_ID(RXF2SIDH, 0, 0); MCP2510_Write_Can_ID(RXF3SIDH, 0, 0); MCP2510_Write_Can_ID(RXF4SIDH, 0, 0); MCP2510_Write_Can_ID(RXF5SIDH, 0, 0); } else{ // Mark MCP2510_Write_Can_ID(RXM0SIDH, pfilter->Mask, TRUE); MCP2510_Write_Can_ID(RXM1SIDH, pfilter->Mask, TRUE); // set all filters to same = pfilter->Filter: MCP2510_Write_Can_ID(RXF0SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF1SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF2SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF3SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF4SIDH, pfilter->Filter, pfilter->IsExt); MCP2510_Write_Can_ID(RXF5SIDH, pfilter->Filter, pfilter->IsExt); } //Enable clock output if(mcp2510dev.loopbackmode) MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); else MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1); // and the two receive buffers. MCP2510_Write(RXB0CTRL, 0); MCP2510_Write(RXB1CTRL, 0); MCP2510_Setup(pfilter);}static int s3c2410_mcp2510_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int flags;local_irq_save(flags); switch (cmd){ case UPCAN_IOCTRL_SETBAND: //set can bus band rate MCP2510_SetBandRate((CanBandRate)arg ,TRUE); mdelay(10); break; case UPCAN_IOCTRL_SETID: //set can frame id data MCP2510_Write_Can_ID(TXB0SIDH, arg, arg&UPCAN_EXCAN); MCP2510_Write_Can_ID(TXB1SIDH, arg, arg&UPCAN_EXCAN); MCP2510_Write_Can_ID(TXB2SIDH, arg, arg&UPCAN_EXCAN); break; case UPCAN_IOCTRL_SETLPBK: //set can device in loop back mode or normal mode if(arg){ MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); mcp2510dev.loopbackmode=1; } else{ MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1); mcp2510dev.loopbackmode=0; } break; case UPCAN_IOCTRL_SETFILTER://set a filter for can device MCP2510_SetFilter((PCanFilter)arg); break; case UPCAN_IOCTRL_PRINTRIGISTER://set a filter for can device printGPE(); printSPI(); printRegisters(); break; } local_irq_restore(flags); DPRINTK("IO control command=0x%x\n", cmd); return 0;}/***************************************************************\* write and send Can data interface for can device file ** there are 2 mode for send data: ** 1, if write data size = sizeof(CanData) then send a full can frame ** 2, if write data size <=8 then send can data, ** we must set frame id first *\****************************************************************/static ssize_t s3c2410_mcp2510_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){ char sendbuffer[sizeof(CanData)]; if(count==sizeof(CanData)){ //send full Can frame---frame id and frame data copy_from_user(sendbuffer, buffer, sizeof(CanData)); MCP2510_canWrite((PCanData)sendbuffer); DPRINTK("Send a Full Frame\n"); return count; } if(count>8) return 0; //count <= 8 copy_from_user(sendbuffer, buffer, count); MCP2510_canWriteData(sendbuffer, count); DPRINTK("Send data size=%d\n", count); DPRINTK("data=%x,%x,%x,%x,%x,%x,%x,%x\n", sendbuffer[0],sendbuffer[1],sendbuffer[2],sendbuffer[3], sendbuffer[4],sendbuffer[5],sendbuffer[6],sendbuffer[7]); return count;}static int RevRead(CanData *candata_ret){ spin_lock_irq(&(mcp2510dev.lock)); memcpy(candata_ret, &(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanReadpos]), sizeof(CanData)); NextCanDataPos(mcp2510dev.nCanReadpos); spin_unlock_irq(&(mcp2510dev.lock)); return sizeof(CanData);}static ssize_t s3c2410_mcp2510_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){ CanData candata_ret; DPRINTK("run in s3c2410_mcp2510_read\n");retry: if (mcp2510dev.nCanReadpos != mcp2510dev.nCanRevpos) { int count; count = RevRead(&candata_ret); if (count) copy_to_user(buffer, (char *)&candata_ret, count); DPRINTK("read data size=%d\n", count); DPRINTK("id=%x, data=%x,%x,%x,%x,%x,%x,%x,%x\n", candata_ret.id, candata_ret.data[0], candata_ret.data[1], candata_ret.data[2], candata_ret.data[3], candata_ret.data[4], candata_ret.data[5], candata_ret.data[6], candata_ret.data[7]); return count; } else { if (filp->f_flags & O_NONBLOCK) { return -EAGAIN; } interruptible_sleep_on(&(mcp2510dev.wq)); if (signal_pending(current)){ return -ERESTARTSYS; } goto retry; } DPRINTK("read data size=%d\n", sizeof(candata_ret)); return sizeof(candata_ret);}static int s3c2410_mcp2510_open(struct inode *inode, struct file *file){ int i,j,a; if(opencount==1) return -EBUSY; opencount++; memset(&mcp2510dev, 0 ,sizeof(mcp2510dev)); init_waitqueue_head(&(mcp2510dev.wq)); //Enable clock output MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1); // Clear, deactivate the three transmit buffers a = TXB0CTRL; for (i = 0; i < 3; i++) { for (j = 0; j < 14; j++) { MCP2510_Write(a, 0); a++; } a += 2; // We did not clear CANSTAT or CANCTRL } // and the two receive buffers. MCP2510_Write(RXB0CTRL, 0); MCP2510_Write(RXB1CTRL, 0); //Open Interrupt MCP2510_Write(CANINTE, RX0IE|RX1IE); MCP2510_Setup(NULL); MCP2510_OPEN_INT(); set_gpio_ctrl(GPIO_MCP2510_CS); MOD_INC_USE_COUNT; DPRINTK("device open\n"); return 0;}static int s3c2410_mcp2510_release(struct inode *inode, struct file *filp){ opencount--; MCP2510_Write(CANINTE, NO_IE); MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1); MCP2510_CLOSE_INT(); MOD_DEC_USE_COUNT; DPRINTK("device release\n"); return 0;}static struct file_operations s3c2410_fops = { owner: THIS_MODULE, write: s3c2410_mcp2510_write, read: s3c2410_mcp2510_read, ioctl: s3c2410_mcp2510_ioctl, open: s3c2410_mcp2510_open, release: s3c2410_mcp2510_release,};#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_spi_dir, devfs_spiraw;#endifstatic int __init s3c2410_mcp2510_init(void){ int ret; int flags; set_gpio_ctrl(GPIO_MCP2510_CS); printGPE(); printSPI(); printRegisters(); local_irq_save(flags); init_MCP2510(BandRate_250kbps); /* Register IRQ handlers */ ret = set_external_irq(MCP2510_IRQ, EXT_LOWLEVEL, GPIO_PULLUP_DIS); if (ret) return ret; local_irq_restore(flags); ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops); if (ret < 0) { printk(DEVICE_NAME " can't get major number\n"); return ret; } Major = ret; /* Enable touch interrupt */ ret = request_irq(MCP2510_IRQ, s3c2410_isr_mcp2510, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_mcp2510); if (ret) return ret; MCP2510_CLOSE_INT();#ifdef CONFIG_DEVFS_FS devfs_spi_dir = devfs_mk_dir(NULL, "can", NULL); devfs_spiraw = devfs_register(devfs_spi_dir, "0", DEVFS_FL_DEFAULT, Major, SPIRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_fops, NULL);#endif printk(DEVICE_NAME " initialized\n"); return 0;}static void __exit s3c2410_mcp2510_exit(void){ printk(DEVICE_NAME " unloaded\n");}module_init(s3c2410_mcp2510_init);module_exit(s3c2410_mcp2510_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -