⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcp2515.c

📁 spi接口的 LINUX CAN driver
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -