📄 mcp2515.c
字号:
/* * 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 <asm/semaphore.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)))/* 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_MAJOR 0#define CAN_MINOR 0#define CAN_MAX_DEV 8#define DRIVER_NAME "mcp2515"static dev_t devid;static int can_major = CAN_MAJOR;static int can_minor = CAN_MINOR;struct mcp251x { struct cdev cdev; 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 sned. */ 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 0static 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);}#endifstatic 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);}static void mcp251x_hw_sleep(struct spi_device *spi){ mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);}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(1);}static int mcp251x_set_bit_rate(struct spi_device *spi, int bit_rate){ struct mcp251x *chip = dev_get_drvdata(&spi->dev); struct mcp251x_platform_data *pdata = spi->dev.platform_data; int tqs; /* tbit/TQ */ int brp; int ps1, ps2, propseg, sjw; unsigned char canctrl; /* 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; 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); /* save the state and put it to config mode. */ canctrl = mcp251x_read_reg(spi, CANCTRL); mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_CONF); 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)); /* restore the state */ mcp251x_write_reg(spi, CANCTRL, canctrl); /* Calculate actual bit rate. */ chip->bit_rate = pdata->f_osc / (2 * (brp + 1)) / tqs; 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); mcp251x_write_reg(spi, RXF_BASE(i)+1, local_buf); 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); mcp251x_write_reg(spi, RXF_BASE(i)+1, local_buf); 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); mcp251x_write_bits(spi, RXBCTRL(0), RXBCTRL_MASK, filter->mode << 6); mcp251x_write_bits(spi, RXBCTRL(1), RXBCTRL_MASK, filter->mode << 6); 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 = chip->spi_transfer_buf; struct can_frame *frame; int ret; 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); 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); 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 *buf = chip->spi_transfer_buf; uint8_t *rx_buf; int ret; struct can_frame *frame; 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -