/* * 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, }; /* *CAN驱动移除函数 *probe() 和remove() 函数应该使用__devinit 和__devexit 标记,且只能标记probe() 和remove() */ static int __devexit mcp251x_remove(struct spi_device *spi) { /* *dev_get_drvdata返回驱动数据的指针,参数设备指针 */ struct mcp251x *chip = dev_get_drvdata(&spi->dev); /*内核使用dev_dbg来控制输出信息,这个函数的实质是调用 printk(KERN_DEBUG )来输出打印信息*/ dev_dbg(&spi->dev, "%s: stop\n", __FUNCTION__); /* *在device_unregister 函数中,驱动核心将删除这个设备的驱动程序(如果有)指向 *这个设备的符号链接, 并从它的内部设备链表中删除该设备 */ device_unregister(chip->class_dev); /*删除一个设备*/ cdev_del(&chip->cdev); /*释放中断*/ free_irq(spi->irq, spi); /*kfree负责回收使用的内存*/ kfree(chip->spi_transfer_buf); return 0; } / /* *CAN驱动探测函数 *probe() 和remove() 函数应该使用__devinit 和__devexit 标记,且只能标记probe() 和remove() */ static int __devinit mcp251x_probe(struct spi_device *spi) { struct mcp251x *chip; int ret = 0; int irq; /*内核使用dev_dbg来控制输出信息 */ dev_dbg(&spi->dev,"%s: start\n", __FUNCTION__); chip = kmalloc(sizeof(struct mcp251x), GFP_KERNEL); if (!chip) { ret = -ENOMEM; goto error_alloc; } /* static inline void dev_set_drvdata(struct device *dev, void *data) { dev->driver_data = data; } */ dev_set_drvdata(&spi->dev, chip); chip->txbin = chip->txbout = 0; chip->rxbin = chip->rxbout = 0; chip->count = 0; chip->spi = spi; /* * 2.6.25及以后的linux内核版本废除了init_MUTEX函数 .使用 init_MUTEX(sem)的地方统统替换为sema_init(sem, 1); * Init_MUTEX()函数初始化信号量为互斥量.互斥量为信号量的特例,它可以防止数据被两个不同系统调用读写。 */ init_MUTEX(&chip->lock); init_MUTEX(&chip->txblock); init_MUTEX(&chip->rxblock); /*init_waitqueue_head()函数会将自旋锁初始化为未锁,等待队列初始化为空的双向循环链表*/ init_waitqueue_head(&chip->wq); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) /* *#define INIT_WORK(_work, _func, _data),可以理解为 *INIT_WORK会在你定义的_work工作队列里面增加一个工作任务,该任务就是_func。 *_func这个任务会需要一些数据作为参数,这个参数就是通过_data传递的 */ 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; } /* * int gpio_request(unsigned gpio, const char *label) * gpio则为你要申请的哪一个管脚,label则是为其取一个名字 */ 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; } /* *调用gpio_direction_input函数将对应的GPIO设置为输入 */ 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); 把spi->irq的PIN值转换为相应的IRQ值,并赋值给变量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; } /* *在Linux内核中,request_irq() 函数是注册中断服务函数:函数的原型如下: int request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long frags, const char *device, void *dev_id); 5个参数的含义如下: 第一个参数irq:申请的硬件中断号; 第二个参数handler:是一个函数指针,向系统登记的中断处理函数, 是一个回调函数,当中断发生时,系统调用这个函数,传入的参数包括中断设备 id,寄存器值。 第三个参数flags:指定了快速中断或中断共享等中断处理属性。 第四个参数devices:指定设备驱动程序的名称。 第五个参数dev_id:传入中断处理程序的参数,可以为NULL,在注册共享中断时,此参数不能为NULL,作为共享中断时的中断区别参数。 返回值: 函数运行正常时返回 0 ,否则返回对应错误的负值。 */ ret = request_irq(irq, mcp251x_irq,IRQF_SAMPLE_RANDOM, DRIVER_NAME, spi); 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; /* *int cdev_add(struct cdev* dev,dev_t num,unsigned int count) *num是该设备对应的第一个设备编号,count是应该和该设备关联的设备编号的数量.count经常取1 */ 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 /* *SPI设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口 *SPI设备驱动层可以用两个模块来描述,struct spi_driver和struct spi_device。 *相关的数据结构如下: struct spi_driver { int (*probe)(struct spi_device *spi); int (*remove)(struct spi_device *spi); void (*shutdown)(struct spi_device *spi); int (*suspend)(struct spi_device *spi, pm_message_t mesg); int (*resume)(struct spi_device *spi); struct device_driver driver; }; *Driver是为device服务的,spi_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定, *probe函数用于驱动和设备匹配时被调用。从上面的结构体注释中我们可以知道, *SPI的通信是通过消息队列机制,而不是像I2C那样通过与从设备进行对话的方式。 */ static struct spi_driver mcp251x_driver = { .driver = { /*char* name; *设备驱动程序的名称。在调用driver_register()往设备驱动程序模型中插入一个新的device_driver对象时, *driver_register()函数会调用bus_add_driver()函数,bus_add_driver()调用kobject_set_name()函数将 *name赋给drv>kobj.name或者drv->kobj.k_name。 *注:drv为要调用driver_register()注册的device_driver类型的对象。 */ .name = DRIVER_NAME, /*struct bus_type *bus; *指向总线描述符的指针,总线连接所支持的设备。连接的是所有可使用该驱动程序驱动的设备。 */ .bus = &spi_bus_type, /* *表示实现设备驱动程序的模块。也就是在该驱动的实现中,如果使用了模块,那么该域就指向你所写的模块 */ .owner = THIS_MODULE, }, /*驱动探测函数*/ .probe = mcp251x_probe, /*驱动移除函数 * __devexit_p *#if defined(MODULE) || defined(CONFIG_HOTPLUG) *#define __devexit_p(x) x *#else *#define __devexit_p(x) NULL *#endif */ .remove = __devexit_p(mcp251x_remove), #ifdef CONFIG_PM /*suspend 驱动的休眠 */ .suspend = mcp251x_suspend, /*resume 驱动的唤醒 */ .resume = mcp251x_resume, #endif }; /* *初始化驱动函数 */ static int __init mcp251x_init(void) { int ret; /*在驱动初始化的代码里调用class_create为该设备创建一个class,在/sys/class/下创建类目录*/ can_class = class_create(THIS_MODULE, "can"); /*IS_ERR 判断返回的指针是错误信息还是实际地址,即指针是否落在最后一页 */ if (IS_ERR(can_class)) /*PTR_ERR 将指针转化为错误号 */ return PTR_ERR(can_class); /* 动态分配设备编号,int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name) * static dev_t can_devt; * 该函数需要传递给它指定的第一个次设备号firstminor(一般为0) * 要分配的设备数count,以及设备名,调用该函数后自动分配得到的设备号保存在dev中 */ 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 删除类*/ class_destroy(can_class); return ret; } /* *不直接使用原始设备驱动,而是使用包装后的抽象设备驱动spi_driver, *间接与原始设备驱动建立联系,并最终通过调用driver_register来注册原始设备驱动 */ return spi_register_driver(&mcp251x_driver); } module_init(mcp251x_init); static void __exit mcp251x_exit(void) { /*class_destroy 删除类*/ class_destroy(can_class); /*使用unregister_chrdev_region 被调用用来释放之前申请的设备号*/ unregister_chrdev_region(can_devt, CAN_DEV_MAX); /*注销spi_driver驱动*/ spi_unregister_driver(&mcp251x_driver); } module_exit(mcp251x_exit); MODULE_DESCRIPTION("MCP251x CAN controller driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Renzhou.Meng");