转自http://blog.csdn.net/askbai666888/article/details/8949108
一.系统硬件结构介绍
系统中 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");