一.系统硬件结构介绍
系统中 CAN 总线主要用来完成 S3C2410 开发板和 CAN 总线分析仪的数据传输。在S3C2410 开发平台上,MCP2515 芯片用作 CAN 控制器,MCP2551 芯片用作 CAN 收发器,S3C2410 微处理器用作节点控制器。如下图1所示。
1.1 S3C2410 的 SPI 接口简介
SPI( Serial Peripheral Interface) 是一个同步串行外围接口,允许 MCU 与各种外围设备以串行方式进行通信。S3C2410 微处理器包括两路 SPI,每一路分别有两个 8 位转移寄存器,用来发送和接收数据。在 SPI 进行传输时,数据同时发送和接收。如果只想发送数据,接收到的数据将是无效的;如果只想接收数据,应当发送全是 1 的数据。
1.2 MCP2551 功能简介
MCP2551 是 CAN 协议控制器和物理总线之间的接口。这个器件向总线提供了差动的发送能力,向 CAN 控制器提供了差动的接收能力。
1.3 MCP2515 功能简介
MCP2515是一款独立CAN控制器,是为简化连接CAN总线的应用而开发的。图2 简要显示了MCP2515的结构框图[3]。该器件主要由三个部分组成:
(1)CAN 协议引擎(处理所有总线上的报文发送和接收) ;
(2)用来为器件及其运行进行配置的控制逻辑和SRAM寄存器;
(3 )SPI协议模块,用来实现SPI通信模式。
二. 驱动程序设计
驱动源码:
/* * Microchip MCP2515 CAN controller driver. * * Copyright (C) 2007 Embedall Technology Co., Ltd. * * 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. */ #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/version.h> #include <linux/device.h> #include <linux/netdevice.h> #include <linux/cdev.h> #include <linux/interrupt.h> #include <linux/list.h> #include <linux/ioctl.h> #include <linux/fs.h> #include <linux/workqueue.h> #include <linux/spi/spi.h> #include <linux/can/can.h> #include <linux/delay.h> #include <linux/can/mcp251x.h> #include <linux/semaphore.h> #include <asm/gpio.h> /* SPI interface instruction set */ #define INSTRUCTION_WRITE 0x02 #define INSTRUCTION_READ 0x03 #define INSTRUCTION_BIT_MODIFY 0x05 #define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n)) #define INSTRUCTION_READ_RXB(n) (0x90 + 4 * (n)) #define INSTRUCTION_RESET 0xc0 #define INSTRUCTION_RTS(n) (0x80 + (1<<n)) #define INSTRUCTION_RX_STATE 0xb0 # define RX_STATE_RTR 0x04 # define RX_STATE_IDE 0x08 #define INSTRUCTION_CAN_STATE 0xa0 # define CAN_STATE_TX2IF 0x01 # define CAN_STATE_TX2REQ 0x02 # define CAN_STATE_TX1IF 0x04 # define CAN_STATE_TX1REQ 0x08 # define CAN_STATE_TX0IF 0x10 # define CAN_STATE_TX0REQ 0x20 # define CAN_STATE_RX1IF 0x40 # define CAN_STATE_RX0IF 0x80 /* MPC251x registers */ #define CANSTAT 0x0e #define CANCTRL 0x0f # define CANCTRL_REQOP_MASK 0xe0 # define CANCTRL_REQOP_CONF 0x80 # define CANCTRL_REQOP_LISTEN_ONLY 0x60 # define CANCTRL_REQOP_LOOPBACK 0x40 # define CANCTRL_REQOP_SLEEP 0x20 # define CANCTRL_REQOP_NORMAL 0x00 # define CANCTRL_OSM 0x08 # define CANCTRL_ABAT 0x10 #define TEC 0x1c #define REC 0x1d #define CNF1 0x2a #define CNF2 0x29 # define CNF2_BTLMODE 0x80 #define CNF3 0x28 # define CNF3_SOF 0x08 # define CNF3_WAKFIL 0x04 # define CNF3_PHSEG2_MASK 0x07 #define CANINTE 0x2b # define CANINTE_MERRE 0x80 # define CANINTE_WAKIE 0x40 # define CANINTE_ERRIE 0x20 # define CANINTE_TX2IE 0x10 # define CANINTE_TX1IE 0x08 # define CANINTE_TX0IE 0x04 # define CANINTE_RX1IE 0x02 # define CANINTE_RX0IE 0x01 #define CANINTF 0x2c # define CANINTF_MERRF 0x80 # define CANINTF_WAKIF 0x40 # define CANINTF_ERRIF 0x20 # define CANINTF_TX2IF 0x10 # define CANINTF_TX1IF 0x08 # define CANINTF_TX0IF 0x04 # define CANINTF_RX1IF 0x02 # define CANINTF_RX0IF 0x01 #define EFLG 0x2d # define EFLG_RX1OVR 0x80 # define EFLG_RX0OVR 0x40 #define TXBCTRL(n) ((n * 0x10) + 0x30) # define TXBCTRL_TXREQ 0x08 # define TXBCTRL_TXPRI(n) (n) # define TXBCTRL_TXERR (1 << 4) # define TXBCTRL_MLOA (1 << 5) # define TXBCTRL_ABTF (1 << 6) #define RXBCTRL(n) ((n * 0x10) + 0x60) # define RXBCTRL_MASK 0x60 # define RXBCTRL_RXRTR 0x08 # define RXBCTRL_BULK (1 << 2) # define RXBCTRL_RXM_MACH_ALL (0 << 6) # define RXBCTRL_RXM_MACH_STD (1 << 6) # define RXBCTRL_RXM_MACH_EXT (2 << 6) # define RXBCTRL_TXM_MACH_OFF (3 << 6) # define RXBCTRL_FILHIT_MASK 0x07 #define RXM_BASE(n) (0x20 + (n * 4)) #define RXF_BASE(n) ((n>2)?(0x10 + (n-3)*4):(0x00 + (n*4))) #define SJW1 0x00 #define SJW2 0x40 #define SJW3 0x80 #define SJW4 0xC0 #define BTLMODE_CNF3 0x80 #define SEG1 0x00 #define SEG2 0x01 #define SEG3 0x02 #define SEG4 0x03 #define SEG5 0x04 #define SEG6 0x05 #define SEG7 0x06 #define SEG8 0x07 #define BRP1 0x00 #define BRP2 0x01 #define BRP3 0x02 #define BRP4 0x03 #define BRP5 0x04 #define BRP6 0x05 #define BRP7 0x06 #define BRP8 0x07 //#define CAN_FOSC_12MHZ #define CAN_FOSC_16MHZ #if defined(CAN_FOSC_12MHZ) #define CAN_CNF1_10K (SJW3 | 0x1d) #define CAN_CNF2_10K (BTLMODE_CNF3|(SEG6<<3)|SEG7) #define CAN_CNF3_10K (SEG6) #define CAN_CNF1_20K (SJW2 | 0x0E) #define CAN_CNF2_20K (BTLMODE_CNF3|(SEG6<<3)|SEG7) #define CAN_CNF3_20K (SEG6) #define CAN_CNF1_50K (SJW1 | 0x05) #define CAN_CNF2_50K (BTLMODE_CNF3|(SEG6<<3)|SEG7) #define CAN_CNF3_50K (SEG6) #define CAN_CNF1_100K (SJW1 | BRP3) #define CAN_CNF2_100K (BTLMODE_CNF3|(SEG6<<3)|SEG7) #define CAN_CNF3_100K (SEG6) #define CAN_CNF1_125K (SJW1 | BRP3) #define CAN_CNF2_125K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_125K (SEG4) #define CAN_CNF1_250K (SJW1 | BRP2) #define CAN_CNF2_250K (BTLMODE_CNF3|(SEG3<<3)|SEG5) #define CAN_CNF3_250K (SEG3) #define CAN_CNF1_500K (SJW1 | BRP1) #define CAN_CNF2_500K (BTLMODE_CNF3|(SEG3<<3)|SEG5) #define CAN_CNF3_500K (SEG3) #define CAN_CNF1_750K (SJW1 | BRP1) #define CAN_CNF2_750K (BTLMODE_CNF3|(SEG3<<2)|SEG1) #define CAN_CNF3_750K (SEG3) #define CAN_CNF1_1000K (SJW1 | BRP1) #define CAN_CNF2_1000K (BTLMODE_CNF3|(SEG2<<3)|SEG1) #define CAN_CNF3_1000K (SEG2) #elif defined(CAN_FOSC_16MHZ) #define CAN_CNF1_10K (SJW1 | 0x31) #define CAN_CNF2_10K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_10K (SEG4) #define CAN_CNF1_20K (SJW1 | 0x18) #define CAN_CNF2_20K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_20K (SEG4) #define CAN_CNF1_50K (SJW1 | 0x09) #define CAN_CNF2_50K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_50K (SEG4) #define CAN_CNF1_100K (SJW1 | BRP5) #define CAN_CNF2_100K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_100K (SEG4) #define CAN_CNF1_125K (SJW1 | BRP4) #define CAN_CNF2_125K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_125K (SEG4) #define CAN_CNF1_250K (SJW1 | BRP2) #define CAN_CNF2_250K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_250K (SEG4) #define CAN_CNF1_500K (SJW1 | BRP1) #define CAN_CNF2_500K (BTLMODE_CNF3|(SEG4<<3)|SEG7) #define CAN_CNF3_500K (SEG4) #define CAN_CNF1_750K (SJW1 | BRP1) #define CAN_CNF2_750K (BTLMODE_CNF3|(SEG3<<3)|SEG4) #define CAN_CNF3_750K (SEG3) #define CAN_CNF1_800K (SJW1 | BRP1) #define CAN_CNF2_800K (BTLMODE_CNF3|(SEG3<<3)|SEG3) #define CAN_CNF3_800K (SEG3) #define CAN_CNF1_1000K (SJW1 | BRP1) #define CAN_CNF2_1000K (BTLMODE_CNF3|(SEG2<<3)|SEG3) #define CAN_CNF3_1000K (SEG2) #endif /* end define CAN_FOSC_12MHZ */ /* Buffer size required for the largest SPI transfer (i.e., reading a frame). */ #define SPI_TRANSFER_BUF_LEN (2*(6 + CAN_FRAME_MAX_DATA_LEN)) /* Buffer size required for ring buffer of receive and send */ #define MCP251X_BUF_LEN 8 #define CAN_DEV_MAX 8 #define DRIVER_NAME "mcp2515" static dev_t can_devt; static int can_minor = 0; static struct class *can_class; static int write_udelay=1024; struct mcp251x { struct cdev cdev; //struct class_device *class_dev; struct device *class_dev; struct semaphore lock; /* semaphore for spi bus share. */ struct semaphore rxblock; /* semaphore for ring buffer of receive. */ struct semaphore txblock; /* semaphore for ring buffer of send. */ uint8_t *spi_transfer_buf; /* temp buffer for spi bus transfer. */ struct can_frame rxb[MCP251X_BUF_LEN]; /* ring buffer for receive. */ struct can_frame txb[MCP251X_BUF_LEN]; /* ring buffer for send. */ int txbin; /* pos of in for ring buffer of send. */ int txbout; /* pos of out for ring buffer of send. */ int rxbin; /* pos of in for ring buffer of receive. */ int rxbout; /* pos of out for ring buffer of receive. */ int bit_rate; /* save bit rate of current set. */ int count; /* count of the device opened. */ wait_queue_head_t wq; /* queue for read process. */ struct work_struct irq_work; /* bottom half of interrupt task. */ struct spi_device *spi; /* save the point of struce spi_device. */ struct can_filter filter; /* save the filter data of current set. */ }; /* ........................................................................ */ #if 0 static void mcp251x_start_tx(struct spi_device *spi, uint8_t buf_idx) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); uint8_t *tx_buf; int ret; tx_buf = chip->spi_transfer_buf; down(&chip->lock); tx_buf[0] = INSTRUCTION_RTS(buf_idx); ret = spi_write(spi, chip->spi_transfer_buf, 1); if (ret < 0) dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); up(&chip->lock); } #endif static uint8_t mcp251x_read_state(struct spi_device *spi, uint8_t cmd) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); uint8_t *tx_buf, *rx_buf; uint8_t val; int ret; tx_buf = chip->spi_transfer_buf; rx_buf = chip->spi_transfer_buf + 8; down(&chip->lock); tx_buf[0] = cmd; ret = spi_write_then_read(spi, tx_buf, 1, rx_buf, 1); if (ret < 0) { dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); val = 0; } else val = rx_buf[0]; up(&chip->lock); return val; } static uint8_t mcp251x_read_reg(struct spi_device *spi, uint8_t reg) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); uint8_t *tx_buf, *rx_buf; uint8_t val; int ret; tx_buf = chip->spi_transfer_buf; rx_buf = chip->spi_transfer_buf + 8; down(&chip->lock); tx_buf[0] = INSTRUCTION_READ; tx_buf[1] = reg; ret = spi_write_then_read(spi, tx_buf, 2, rx_buf, 1); if (ret < 0) { dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); val = 0; } else val = rx_buf[0]; up(&chip->lock); return val; } static void mcp251x_write_reg(struct spi_device *spi, uint8_t reg, uint8_t val) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); int ret; down(&chip->lock); chip->spi_transfer_buf[0] = INSTRUCTION_WRITE; chip->spi_transfer_buf[1] = reg; chip->spi_transfer_buf[2] = val; ret = spi_write(spi, chip->spi_transfer_buf, 3); if (ret < 0) dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); up(&chip->lock); } static void mcp251x_write_bits(struct spi_device *spi, uint8_t reg, uint8_t mask, uint8_t val) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); int ret; down(&chip->lock); chip->spi_transfer_buf[0] = INSTRUCTION_BIT_MODIFY; chip->spi_transfer_buf[1] = reg; chip->spi_transfer_buf[2] = mask; chip->spi_transfer_buf[3] = val; ret = spi_write(spi, chip->spi_transfer_buf, 4); if (ret < 0) dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); up(&chip->lock); } static void mcp251x_hw_reset(struct spi_device *spi) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); int ret; down(&chip->lock); chip->spi_transfer_buf[0] = INSTRUCTION_RESET; ret = spi_write(spi, chip->spi_transfer_buf, 1); if (ret < 0) dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); up(&chip->lock); } static void __devinit mcp251x_hw_init(struct spi_device *spi) { mcp251x_hw_reset(spi); mcp251x_write_reg(spi,0x0c,0x0c); } static void mcp251x_hw_sleep(struct spi_device *spi) { #if 0 /* sleep disable */ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP); #endif } static void mcp251x_hw_wakeup(struct spi_device *spi) { /* Can only wake up by generating a wake-up interrupt. */ mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE); mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF); mdelay(10); } static int mcp251x_set_bit_rate(struct spi_device *spi, int bit_rate) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); unsigned char canctrl,val; #if 0 struct mcp251x_platform_data *pdata = spi->dev.platform_data; int tqs; /* tbit/TQ */ int brp; int ps1, ps2, propseg, sjw; /* Determine the BRP value that gives the requested bit rate. */ for(brp = 0; brp < 8; brp++) { tqs = pdata->f_osc / (2 * (brp + 1)) / bit_rate; if (tqs >= 5 && tqs <= 25 && (pdata->f_osc / (2 * (brp + 1)) / tqs) == bit_rate) break; } if (brp >= 8) return -EINVAL; /* The CAN bus bit time (tbit) is determined by: * tbit = (SyncSeg + PropSeg + PS1 + PS2) * TQ * with: * SyncSeg = 1 * sample point (between PS1 and PS2) must be at 60%-70% of the bit time * PropSeg + PS1 >= PS2 * PropSeg + PS1 >= Tdelay * PS2 > SJW * 1 <= PropSeg <= 8, 1 <= PS1 <=8, 2 <= PS2 <= 8 * SJW = 1 is sufficient in most cases. * Tdelay is usually 1 or 2 TQ. */ propseg = ps1 = ps2 = (tqs - 1) / 3; if (tqs - (1 + propseg + ps1 + ps2) == 2) ps1++; if (tqs - (1 + propseg + ps1 + ps2) == 1) ps2++; sjw = 1; printk("bit rate: BRP = %d, Tbit = %d TQ, PropSeg = %d, PS1 = %d, PS2 = %d, SJW = %d\n", brp, tqs, propseg, ps1, ps2, sjw); dev_dbg(&spi->dev,"bit rate: BRP = %d, Tbit = %d TQ, PropSeg = %d, PS1 = %d, PS2 = %d, SJW = %d\n", brp, tqs, propseg, ps1, ps2, sjw); mcp251x_write_reg(spi, CNF1, ((sjw-1) << 6) | brp); mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE | ((ps1-1) << 3) | (propseg-1)); mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (ps2-1)); chip->bit_rate = pdata->f_osc / (2 * (brp + 1)) / tqs; #endif #if 1 canctrl = mcp251x_read_reg(spi, CANCTRL); /* if(canctrl == 0) { printk("mcp2515 read CANCTRL reg error!\n"); return -1; } else { printk("mcp2515 read CANCTRL reg [%x] ok!\n", canctrl); }*/ do { mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_CONF); val = mcp251x_read_reg(spi, CANCTRL); }while((val&0xe0) != CANCTRL_REQOP_CONF); switch(bit_rate) { case 10000: /* save the state and put it to config mode. */ mcp251x_write_reg(spi, CNF1, CAN_CNF1_10K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_10K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_10K); write_udelay=12800; break; case 20000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_20K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_20K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_20K); write_udelay=6400; break; case 50000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_50K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_50K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_50K); write_udelay=2560; break; case 100000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_100K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_100K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_100K); write_udelay=1280; break; case 125000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_125K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_125K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_125K); write_udelay=1024; break; case 250000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_250K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_250K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_250K); write_udelay=512; break; case 500000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_500K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_500K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_500K); write_udelay=256; break; case 750000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_750K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_750K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_750K); write_udelay=171; break; case 800000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_800K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_800K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_800K); write_udelay=160; break; case 1000000: mcp251x_write_reg(spi, CNF1, CAN_CNF1_1000K); mcp251x_write_reg(spi, CNF2, CAN_CNF2_1000K); mcp251x_write_reg(spi, CNF3, CAN_CNF3_1000K); write_udelay=128; break; default: printk("<kernel>: baud rate %d not support\n", bit_rate); break; } mcp251x_write_reg(spi, CANCTRL, canctrl); chip->bit_rate = bit_rate; #endif return 0; } static int mcp251x_get_bit_rate(struct spi_device *spi) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); return chip->bit_rate; } static int mcp251x_set_filter(struct spi_device *spi, struct can_filter *filter) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); uint8_t canctrl; uint8_t local_buf; int i; canctrl = mcp251x_read_reg(spi, CANCTRL); mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_CONF); for (i=0; i<CAN_FILTER_REG_NUM; i++) { if (filter->fid[i].active == 0) { local_buf = 0; mcp251x_write_reg(spi, RXF_BASE(i)+0, local_buf); #if 1 /* set RXFnSIDL EXIDE(bit 3) = 0 for receive standard frame */ mcp251x_write_reg(spi, RXF_BASE(i)+1, local_buf); #else /* set RXFnSIDL EXIDE(bit 3) = 1 for receive extend frame */ mcp251x_write_reg(spi, RXF_BASE(i)+1, local_buf | 0x08); #endif mcp251x_write_reg(spi, RXF_BASE(i)+2, local_buf); mcp251x_write_reg(spi, RXF_BASE(i)+3, local_buf); continue; } local_buf = filter->fid[i].id >> 3; mcp251x_write_reg(spi, RXF_BASE(i)+0, local_buf); local_buf = (filter->fid[i].id << 5) | (filter->fid[i].ide << 3) | (filter->fid[i].eid >> 16); #if 1 mcp251x_write_reg(spi, RXF_BASE(i)+1, local_buf); #else mcp251x_write_reg(spi, RXF_BASE(i)+1, local_buf | 0x08); #endif local_buf = filter->fid[i].eid >> 8; mcp251x_write_reg(spi, RXF_BASE(i)+2, local_buf); local_buf = filter->fid[i].eid; mcp251x_write_reg(spi, RXF_BASE(i)+3, local_buf); } for (i=0; i<2; i++) { local_buf = filter->sidmask >> 3; mcp251x_write_reg(spi, RXM_BASE(i)+0, local_buf); local_buf = (filter->sidmask << 5) | (filter->eidmask >> 16); mcp251x_write_reg(spi, RXM_BASE(i)+1, local_buf); local_buf = filter->eidmask >> 8; mcp251x_write_reg(spi, RXM_BASE(i)+2, local_buf); local_buf = filter->eidmask; mcp251x_write_reg(spi, RXM_BASE(i)+3, local_buf); } mcp251x_write_reg(spi, CANCTRL, canctrl); /* set receive buffer work mode */ mcp251x_write_bits(spi, RXBCTRL(0), RXBCTRL_MASK, filter->mode << 5); mcp251x_write_bits(spi, RXBCTRL(1), RXBCTRL_MASK, filter->mode << 5); memcpy(&chip->filter, filter, sizeof(struct can_filter)); return 0; } static int mcp251x_get_filter(struct spi_device *spi, struct can_filter *filter) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); memcpy(filter, &chip->filter, sizeof(struct can_filter)); return 0; } /* If MCP251X ready, copy data from ring buffer to MCP251X send buffer and set * TXBCTRL_TXREQ. */ static int mcp251x_hw_tx(struct spi_device *spi, int tx_buf_idx) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); uint8_t buf[13] ; // unsigned char val; struct can_frame *frame; // int ret; int i; dev_dbg(&spi->dev,"%s()\n", __FUNCTION__); if (chip->txbout != chip->txbin) { if (down_interruptible(&chip->txblock)) return -ERESTARTSYS; frame = &chip->txb[chip->txbout]; // down(&chip->lock); if (frame->header.dlc > CAN_FRAME_MAX_DATA_LEN) frame->header.dlc = CAN_FRAME_MAX_DATA_LEN; if (frame->header.ide == 0) frame->header.eid = 0; /* buf[0] = INSTRUCTION_LOAD_TXB(tx_buf_idx); buf[1] = frame->header.id >> 3; buf[2] = (frame->header.id << 5) | (frame->header.ide << 3) | (frame->header.eid >> 16); buf[3] = frame->header.eid >> 8; buf[4] = frame->header.eid; buf[5] = (frame->header.rtr << 6) | frame->header.dlc; memcpy(buf + 6, frame->data, frame->header.dlc); for(i=0;i<frame->header.dlc+6;i++) { printk("buf[%d] : %d\n",i,buf[i]); } ret = spi_write(spi, buf, 6 + CAN_FRAME_MAX_DATA_LEN); if (ret < 0) dev_dbg(&spi->dev,"%s: failed: ret = %d\n", __FUNCTION__, ret); */ buf[0] = frame->header.id >> 3; buf[1] = (frame->header.id << 5) | (frame->header.ide << 3) | (frame->header.eid >> 16); buf[2] = frame->header.eid >> 8; buf[3] = frame->header.eid; buf[4] = (frame->header.rtr << 6) | frame->header.dlc; memcpy(buf + 5, frame->data, frame->header.dlc); /* for(i=0;i<frame->header.dlc+5;i++) { printk("buf[%d] : %x\n",i,buf[i]); } */ if (tx_buf_idx == 0) { for(i=0;i<(frame->header.dlc+5);i++) { mcp251x_write_reg(spi,(0x31+i),buf[i]); } } else if(tx_buf_idx ==1) { for(i=0;i<(frame->header.dlc+5);i++) { mcp251x_write_reg(spi,(0x41+i),buf[i]); } } else { for(i=0;i<(frame->header.dlc+5);i++) { mcp251x_write_reg(spi,(0x51+i),buf[i]); } } // up(&chip->lock); /* update pos of ring buffer */ chip->txbout++; if (chip->txbout >= MCP251X_BUF_LEN) chip->txbout = 0; up(&chip->txblock); mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ); } return 0; } /* Receive data from internat buffer of MCP251X and save it to ring buffer. */ static int mcp251x_hw_rx(struct spi_device *spi, int buf_idx) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); uint8_t rx_buf[13]; // int ret; struct can_frame *frame; int i; if (down_interruptible(&chip->rxblock)) return -ERESTARTSYS; frame = &chip->rxb[chip->rxbin]; // down(&chip->lock); /* buf[0] = INSTRUCTION_READ_RXB(buf_idx); rx_buf = buf + (6 + CAN_FRAME_MAX_DATA_LEN); ret = spi_write_then_read(spi, buf, 1, rx_buf, 13); if (ret < 0) dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret); */ if (buf_idx == 0) for(i=0;i<(5 + CAN_FRAME_MAX_DATA_LEN);i++) { rx_buf[i] = mcp251x_read_reg(spi,0x61+i); } else for(i=0;i<(5 + CAN_FRAME_MAX_DATA_LEN);i++) { rx_buf[i] = mcp251x_read_reg(spi,0x71+i); } frame->header.id = (rx_buf[0] << 3) | (rx_buf[1] >> 5); frame->header.ide = (rx_buf[1] >> 3) & 0x1; frame->header.srr = (rx_buf[1] >> 4) & 0x1; if (frame->header.ide == 1) frame->header.eid = (rx_buf[1] << 16) | (rx_buf[2] << 8) | rx_buf[3]; else frame->header.eid = 0; frame->header.rtr = (rx_buf[4] >> 6) & 0x1; frame->header.rb1 = (rx_buf[4] >> 5) & 0x1; frame->header.rb0 = (rx_buf[4] >> 4) & 0x1; frame->header.dlc = rx_buf[4] & 0x0f; memcpy(frame->data, rx_buf + 5, CAN_FRAME_MAX_DATA_LEN); // up(&chip->lock); /* update pos of ring buffer */ chip->rxbin++; if (chip->rxbin >= MCP251X_BUF_LEN) chip->rxbin = 0; up(&chip->rxblock); return 0; } /* ........................................................................ */ /* bottom half task for interrupt */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) static void mcp251x_irq_handler(struct work_struct *work) { struct mcp251x *chip = container_of(work, struct mcp251x, irq_work); struct spi_device *spi = chip->spi; #else static void mcp251x_irq_handler(void *dev_id) { struct spi_device *spi = dev_id; struct mcp251x *chip = dev_get_drvdata(&spi->dev); #endif uint8_t intf, rxs; for(;;) { intf = mcp251x_read_reg(spi, CANINTF); if (intf == 0x00) break; dev_dbg(&spi->dev,"interrupt:%s%s%s%s%s%s%s%s\n", (intf & CANINTF_MERRF) ? " MERR":"", (intf & CANINTF_WAKIF) ? " WAK":"", (intf & CANINTF_ERRIF) ? " ERR":"", (intf & CANINTF_TX2IF) ? " TX2":"", (intf & CANINTF_TX1IF) ? " TX1":"", (intf & CANINTF_TX0IF) ? " TX0":"", (intf & CANINTF_RX1IF) ? " RX1":"", (intf & CANINTF_RX0IF) ? " RX0":""); rxs = mcp251x_read_state(spi, INSTRUCTION_RX_STATE); dev_dbg(&spi->dev, "rx_state:%s%s\n", (rxs & RX_STATE_IDE) ? " IDE":"", (rxs & RX_STATE_RTR) ? " RTR":""); if (intf & CANINTF_MERRF) { #if 0 uint8_t txbnctrl; /* if there are no pending Tx buffers, restart queue */ txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0)); if (!(txbnctrl & TXBCTRL_TXREQ)) netif_wake_queue(&chip->can->ndev); #endif } if (intf & CANINTF_ERRIF) { uint8_t eflg = mcp251x_read_reg(spi, EFLG); dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflg); if (eflg & (EFLG_RX0OVR | EFLG_RX1OVR)) { #if 0 if (eflg & EFLG_RX0OVR) chip->stats.rx_over_errors++; if (eflg & EFLG_RX1OVR) chip->stats.rx_over_errors++; #endif mcp251x_write_reg(spi, EFLG, 0x00); } } if (intf & CANINTF_TX0IF) /* If ready to send, copy data to send buffer. */ mcp251x_hw_tx(spi, 0); if (intf & CANINTF_TX1IF) mcp251x_hw_tx(spi, 1); if (intf & CANINTF_TX2IF) mcp251x_hw_tx(spi, 2); if (intf & CANINTF_RX0IF) /* If received data, copy data to ring buffer. */ mcp251x_hw_rx(spi, 0); if (intf & CANINTF_RX1IF) mcp251x_hw_rx(spi, 1); mcp251x_write_bits(spi, CANINTF, intf, 0x00); /* If ring buffer of receive is not empty, wake up the read queue. */ if (chip->rxbin != chip->rxbout) wake_up_interruptible(&chip->wq); } } static irqreturn_t mcp251x_irq(int irq, void *dev_id) { struct spi_device *spi = dev_id; struct mcp251x *chip = dev_get_drvdata(&spi->dev); /* Can't do anything in interrupt context so fire of the interrupt * handling workqueue. */ schedule_work(&chip->irq_work); return IRQ_HANDLED; } /* ........................................................................ */ static int mcp251x_open(struct inode *inode, struct file *file) { struct mcp251x *chip = container_of(inode->i_cdev, struct mcp251x, cdev); struct spi_device *spi = chip->spi; struct mcp251x_platform_data *pdata = spi->dev.platform_data; file->private_data = chip; if (!chip->count) { if (pdata->transceiver_enable) pdata->transceiver_enable(1); mcp251x_hw_reset(spi); mcp251x_hw_wakeup(spi); /* Enable interrupts */ mcp251x_write_reg(spi, CANINTE, CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE | CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE); /* put device into normal mode */ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); mcp251x_write_reg(spi, RXBCTRL(0), RXBCTRL_BULK); } chip->count++; return 0; } static int mcp251x_release(struct inode *inode, struct file *file) { struct mcp251x *chip = container_of(inode->i_cdev, struct mcp251x, cdev); struct spi_device *spi = chip->spi; struct mcp251x_platform_data *pdata = spi->dev.platform_data; chip->count--; if (chip->count) return 0; /* disable and clear pending interrupts */ mcp251x_write_reg(spi, CANINTE, 0x00); mcp251x_write_reg(spi, CANINTF, 0x00); /* go to sleep */ mcp251x_hw_sleep(spi); if (pdata->transceiver_enable) pdata->transceiver_enable(0); return 0; } static int mcp251x_write(struct file *file, const char __user *buf, size_t count, loff_t *ofs) { struct mcp251x *chip = file->private_data; struct spi_device *spi = chip->spi; struct can_frame *frame; int ret; uint8_t txreq; if (count < sizeof(struct can_frame)) return -EINVAL; if (down_interruptible(&chip->txblock)) return -ERESTARTSYS; frame = &chip->txb[chip->txbin]; ret = copy_from_user(frame, buf, sizeof(struct can_frame)); chip->txbin++; if (chip->txbin >= MCP251X_BUF_LEN) chip->txbin = 0; up(&chip->txblock); txreq = mcp251x_read_state(spi, INSTRUCTION_CAN_STATE); if (!(txreq & CAN_STATE_TX0REQ)) mcp251x_hw_tx(spi, 0); if (!(txreq & CAN_STATE_TX1REQ)) mcp251x_hw_tx(spi, 1); if (!(txreq & CAN_STATE_TX2REQ)) mcp251x_hw_tx(spi, 2); udelay(write_udelay); return count; } static ssize_t mcp251x_read(struct file *file, char __user *buf, size_t count, loff_t *ofs) { struct mcp251x *chip = file->private_data; struct can_frame *frame; if (count != sizeof(struct can_frame)) return -EINVAL; if (down_interruptible(&chip->rxblock)) return -ERESTARTSYS; while (chip->rxbin == chip->rxbout) { up(&chip->rxblock); if (file->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(chip->wq, (chip->rxbin != chip->rxbout))) return -ERESTARTSYS; if (down_interruptible(&chip->rxblock)) return -ERESTARTSYS; } frame = &chip->rxb[chip->rxbout]; if (copy_to_user(buf, frame, sizeof(struct can_frame))) { up(&chip->rxblock); return -EFAULT; } chip->rxbout++; if(chip->rxbout >= MCP251X_BUF_LEN) chip->rxbout = 0; up(&chip->rxblock); return count; #if 0 retry: if (chip->rxbin != chip->rxbout) { down(&chip->rxblock); frame = &chip->rxb[chip->rxbout]; if (copy_to_user(buf, frame, sizeof(struct can_frame))) { up(&chip->rxblock); return -EFAULT; } chip->rxbout++; if(chip->rxbout >= MCP251X_BUF_LEN) chip->rxbout = 0; up(&chip->rxblock); return count; } else { if (file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&chip->wq); if (signal_pending(current)) return -ERESTARTSYS; goto retry; } #endif } static int mcp251x_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct mcp251x *chip = container_of(inode->i_cdev, struct mcp251x, cdev); struct spi_device *spi = chip->spi; int ret = 0; switch(cmd) { case CAN_IOCTRESET: /* reset devcie */ mcp251x_hw_reset(spi); break; case CAN_IOCTWAKEUP: /* wake up device */ mcp251x_hw_wakeup(spi); break; case CAN_IOCSRATE: /* set bit rate */ ret = mcp251x_set_bit_rate(spi, (int)arg); mdelay(10); break; case CAN_IOCGRATE: /* get bit rate */ *((int *)arg) = mcp251x_get_bit_rate(spi); break; case CAN_IOCSFILTER: /* set filter */ ret = mcp251x_set_filter(spi, (struct can_filter *)arg); break; case CAN_IOCGFILTER: /* get filter */ ret = mcp251x_get_filter(spi, (struct can_filter *)arg); break; case CAN_IOCTNORMALMODE: /* turn to normal mode */ //mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_NORMAL); mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL); break; case CAN_IOCTLOOPBACKMODE: /* turn to loopback mode */ //mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_LOOPBACK); mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK); break; case CAN_IOCTLISTENONLYMODE: /* turn to listen only mode */ //mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_LISTEN_ONLY); mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LISTEN_ONLY); break; case CAN_IOCTSLEEPMODE: /* turn to sleep mode */ mcp251x_hw_sleep(spi); break; default: return -ENOTTY; } return ret; } static const struct file_operations mcp251x_fops = { .owner = THIS_MODULE, .read = mcp251x_read, .write = mcp251x_write, .ioctl = mcp251x_ioctl, .open = mcp251x_open, .release = mcp251x_release, }; /* ........................................................................ */ static int __devexit mcp251x_remove(struct spi_device *spi) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); dev_dbg(&spi->dev, "%s: stop\n", __FUNCTION__); device_unregister(chip->class_dev); cdev_del(&chip->cdev); free_irq(spi->irq, spi); kfree(chip->spi_transfer_buf); return 0; } static int __devinit mcp251x_probe(struct spi_device *spi) { struct mcp251x *chip; int ret = 0; int irq; dev_dbg(&spi->dev,"%s: start\n", __FUNCTION__); chip = kmalloc(sizeof(struct mcp251x), GFP_KERNEL); if (!chip) { ret = -ENOMEM; goto error_alloc; } dev_set_drvdata(&spi->dev, chip); chip->txbin = chip->txbout = 0; chip->rxbin = chip->rxbout = 0; chip->count = 0; chip->spi = spi; init_MUTEX(&chip->lock); init_MUTEX(&chip->txblock); init_MUTEX(&chip->rxblock); init_waitqueue_head(&chip->wq); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) INIT_WORK(&chip->irq_work, mcp251x_irq_handler); #else INIT_WORK(&chip->irq_work, mcp251x_irq_handler, spi); #endif chip->spi_transfer_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL); if (!chip->spi_transfer_buf) { ret = -ENOMEM; goto error_buf; } ret = gpio_request(spi->irq, spi->modalias); if (ret < 0) { pr_err("mcp251x: failed to request GPIO %d," " error %d\n", spi->irq, ret); goto error_irq; } ret = gpio_direction_input(spi->irq); if (ret < 0) { pr_err("mcp251x: failed to configure input" " direction for GPIO %d, error %d\n", spi->irq, ret); gpio_free(spi->irq); goto error_irq; } irq = gpio_to_irq(spi->irq); if (irq < 0) { ret = irq; pr_err("mcp251x: Unable to get irq number" " for GPIO %d, error %d\n", spi->irq, ret); gpio_free(spi->irq); goto error_irq; } ret = request_irq(irq, mcp251x_irq,IRQF_SAMPLE_RANDOM, DRIVER_NAME, spi);// SA_SAMPLE_RANDOM, if (ret < 0) { dev_err(&spi->dev,"request irq %d failed (ret = %d)\n", spi->irq, ret); gpio_free(spi->irq); goto error_irq; } cdev_init(&chip->cdev, &mcp251x_fops); chip->cdev.owner = THIS_MODULE; ret = cdev_add(&chip->cdev, MKDEV(MAJOR(can_devt), can_minor), 1); if (ret < 0) { dev_err(&spi->dev, "register char device failed (ret = %d)\n", ret); goto error_register; } chip->class_dev = device_create(can_class, NULL, MKDEV(MAJOR(can_devt), can_minor), &spi->dev, "can%d", can_minor); if (IS_ERR(chip->class_dev)) { dev_err(&spi->dev, "cannot create CAN class device\n"); ret = PTR_ERR(chip->class_dev); goto error_class_reg; } dev_info(&spi->dev, "device register at dev(%d:%d)\n", MAJOR(can_devt), can_minor); mcp251x_hw_init(spi); ret = mcp251x_set_bit_rate(spi, 125000); /* A reasonable default */ if(ret == -1) { printk("mcp2515 set bit rate error!\n"); cdev_del(&chip->cdev); free_irq(spi->irq, spi); kfree(chip->spi_transfer_buf); kfree(chip); return ret; } mcp251x_hw_sleep(spi); can_minor++; return 0; error_class_reg: cdev_del(&chip->cdev); error_register: free_irq(spi->irq, spi); error_irq: free_irq(gpio_to_irq(spi->irq), spi); gpio_free(spi->irq); kfree(chip->spi_transfer_buf); error_buf: kfree(chip); error_alloc: return ret; } #ifdef CONFIG_PM static int mcp251x_suspend(struct spi_device *spi, pm_message_t mesg) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); struct mcp251x_platform_data *pdata = spi->dev.platform_data; if (chip->count) return 0; mcp251x_hw_sleep(spi); if (pdata->transceiver_enable) pdata->transceiver_enable(0); return 0; } static int mcp251x_resume(struct spi_device *spi) { struct mcp251x *chip = dev_get_drvdata(&spi->dev); struct mcp251x_platform_data *pdata = spi->dev.platform_data; if (!chip->count) return 0; if (pdata->transceiver_enable) pdata->transceiver_enable(1); mcp251x_hw_wakeup(spi); return 0; } #endif static struct spi_driver mcp251x_driver = { .driver = { .name = DRIVER_NAME, .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = mcp251x_probe, .remove = __devexit_p(mcp251x_remove), #ifdef CONFIG_PM .suspend = mcp251x_suspend, .resume = mcp251x_resume, #endif }; static int __init mcp251x_init(void) { int ret; can_class = class_create(THIS_MODULE, "can"); if (IS_ERR(can_class)) return PTR_ERR(can_class); ret = alloc_chrdev_region(&can_devt, 0, CAN_DEV_MAX, DRIVER_NAME); if (ret < 0) { printk(KERN_ERR "%s: failed to allocate char dev region\n", __FILE__); class_destroy(can_class); return ret; } return spi_register_driver(&mcp251x_driver); } module_init(mcp251x_init); static void __exit mcp251x_exit(void) { class_destroy(can_class); unregister_chrdev_region(can_devt, CAN_DEV_MAX); spi_unregister_driver(&mcp251x_driver); } module_exit(mcp251x_exit); MODULE_DESCRIPTION("MCP251x CAN controller driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Quanlin.Bai");