/*
- *
* CAN bus driver for Microchip 251x CAN Controller with SPI Interface
*
* MCP2510 support and bug fixes by Christian Pellegrin
* <chripell@evolware.org>
*
+ * Copyright 2009 Christian Pellegrin EVOL S.r.l.
+ *
* Copyright 2007 Raymarine UK, Ltd. All Rights Reserved.
* Written under contract by:
* Chris Elston, Katalix Systems, Ltd.
*
* static struct spi_board_info spi_board_info[] = {
* {
- * .modalias = "mcp251x",
+ * .modalias = "mcp251x",
* .platform_data = &mcp251x_info,
- * .irq = IRQ_EINT13,
- * .max_speed_hz = 2*1000*1000,
- * .chip_select = 2,
+ * .irq = IRQ_EINT13,
+ * .max_speed_hz = 2*1000*1000,
+ * .chip_select = 2,
* },
* };
*
*
*/
+#include <linux/completion.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
#include <linux/netdevice.h>
-#include <linux/can.h>
+#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/can/dev.h>
-#include <linux/can/core.h>
-#include <linux/if_arp.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/freezer.h>
#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/can/platform/mcp251x.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/dev.h>
+#include <socketcan/can/platform/mcp251x.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+#error This driver does not support Kernel versions < 2.6.22
+#endif
/* SPI interface instruction set */
-#define INSTRUCTION_WRITE 0x02
-#define INSTRUCTION_READ 0x03
+#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) (((n) == 0) ? 0x90 : 0x94)
-#define INSTRUCTION_RESET 0xC0
+#define INSTRUCTION_RESET 0xC0
/* MPC251x registers */
#define CANSTAT 0x0e
#define TEC 0x1c
#define REC 0x1d
#define CNF1 0x2a
+# define CNF1_SJW_SHIFT 6
#define CNF2 0x29
-# define CNF2_BTLMODE 0x80
+# define CNF2_BTLMODE 0x80
+# define CNF2_SAM 0x40
+# define CNF2_PS1_SHIFT 3
#define CNF3 0x28
-# define CNF3_SOF 0x08
-# define CNF3_WAKFIL 0x04
+# define CNF3_SOF 0x08
+# define CNF3_WAKFIL 0x04
# define CNF3_PHSEG2_MASK 0x07
#define CANINTE 0x2b
# define CANINTE_MERRE 0x80
# define EFLG_TXBO 0x20
# define EFLG_RX0OVR 0x40
# define EFLG_RX1OVR 0x80
-#define TXBCTRL(n) ((n * 0x10) + 0x30)
+#define TXBCTRL(n) (((n) * 0x10) + 0x30 + TXBCTRL_OFF)
# define TXBCTRL_ABTF 0x40
# define TXBCTRL_MLOA 0x20
# define TXBCTRL_TXERR 0x10
# define TXBCTRL_TXREQ 0x08
-#define RXBCTRL(n) ((n * 0x10) + 0x60)
-# define RXBCTRL_BUKT 0x04
-# define RXBCTRL_RXM0 0x20
-# define RXBCTRL_RXM1 0x40
+#define TXBSIDH(n) (((n) * 0x10) + 0x30 + TXBSIDH_OFF)
+# define SIDH_SHIFT 3
+#define TXBSIDL(n) (((n) * 0x10) + 0x30 + TXBSIDL_OFF)
+# define SIDL_SID_MASK 7
+# define SIDL_SID_SHIFT 5
+# define SIDL_EXIDE_SHIFT 3
+# define SIDL_EID_SHIFT 16
+# define SIDL_EID_MASK 3
+#define TXBEID8(n) (((n) * 0x10) + 0x30 + TXBEID8_OFF)
+#define TXBEID0(n) (((n) * 0x10) + 0x30 + TXBEID0_OFF)
+#define TXBDLC(n) (((n) * 0x10) + 0x30 + TXBDLC_OFF)
+# define DLC_RTR_SHIFT 6
+#define TXBCTRL_OFF 0
+#define TXBSIDH_OFF 1
+#define TXBSIDL_OFF 2
+#define TXBEID8_OFF 3
+#define TXBEID0_OFF 4
+#define TXBDLC_OFF 5
+#define TXBDAT_OFF 6
+#define RXBCTRL(n) (((n) * 0x10) + 0x60 + RXBCTRL_OFF)
+# define RXBCTRL_BUKT 0x04
+# define RXBCTRL_RXM0 0x20
+# define RXBCTRL_RXM1 0x40
+#define RXBSIDH(n) (((n) * 0x10) + 0x60 + RXBSIDH_OFF)
+# define RXBSIDH_SHIFT 3
+#define RXBSIDL(n) (((n) * 0x10) + 0x60 + RXBSIDL_OFF)
+# define RXBSIDL_IDE 0x08
+# define RXBSIDL_EID 3
+# define RXBSIDL_SHIFT 5
+#define RXBEID8(n) (((n) * 0x10) + 0x60 + RXBEID8_OFF)
+#define RXBEID0(n) (((n) * 0x10) + 0x60 + RXBEID0_OFF)
+#define RXBDLC(n) (((n) * 0x10) + 0x60 + RXBDLC_OFF)
+# define RXBDLC_LEN_MASK 0x0f
+# define RXBDLC_RTR 0x40
+#define RXBCTRL_OFF 0
+#define RXBSIDH_OFF 1
+#define RXBSIDL_OFF 2
+#define RXBEID8_OFF 3
+#define RXBEID0_OFF 4
+#define RXBDLC_OFF 5
+#define RXBDAT_OFF 6
+
+#define GET_BYTE(val, byte) \
+ (((val) >> ((byte) * 8)) & 0xff)
+#define SET_BYTE(val, byte) \
+ (((val) & 0xff) << ((byte) * 8))
-/* Buffer size required for the largest SPI transfer (i.e., reading a
- * frame). */
+/*
+ * Buffer size required for the largest SPI transfer (i.e., reading a
+ * frame)
+ */
#define CAN_FRAME_MAX_DATA_LEN 8
-#define SPI_TRANSFER_BUF_LEN (2*(6 + CAN_FRAME_MAX_DATA_LEN))
+#define SPI_TRANSFER_BUF_LEN (6 + CAN_FRAME_MAX_DATA_LEN)
#define CAN_FRAME_MAX_BITS 128
+#define TX_ECHO_SKB_MAX 1
+
#define DEVICE_NAME "mcp251x"
static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
static struct can_bittiming_const mcp251x_bittiming_const = {
+ .name = DEVICE_NAME,
.tseg1_min = 3,
.tseg1_max = 16,
.tseg2_min = 2,
dma_addr_t spi_rx_dma;
struct sk_buff *tx_skb;
+ int tx_len;
struct workqueue_struct *wq;
struct work_struct tx_work;
struct work_struct irq_work;
#define AFTER_SUSPEND_UP 1
#define AFTER_SUSPEND_DOWN 2
#define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
int restart_tx;
};
-static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+static void mcp251x_clean(struct net_device *net)
+{
+ struct mcp251x_priv *priv = netdev_priv(net);
+
+ net->stats.tx_errors++;
+ if (priv->tx_skb)
+ dev_kfree_skb(priv->tx_skb);
+ if (priv->tx_len)
+ can_free_echo_skb(priv->net, 0);
+ priv->tx_skb = NULL;
+ priv->tx_len = 0;
+}
+
+/*
+ * Note about handling of error return of mcp251x_spi_trans: accessing
+ * registers via SPI is not really different conceptually than using
+ * normal I/O assembler instructions, although it's much more
+ * complicated from a practical POV. So it's not advisable to always
+ * check the return value of this function. Imagine that every
+ * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
+ * error();", it would be a great mess (well there are some situation
+ * when exception handling C++ like could be useful after all). So we
+ * just check that transfers are OK at the beginning of our
+ * conversation with the chip and to avoid doing really nasty things
+ * (like injecting bogus packets in the network stack).
+ */
+static int mcp251x_spi_trans(struct spi_device *spi, int len)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
struct spi_transfer t = {
.tx_buf = priv->spi_tx_buf,
.rx_buf = priv->spi_rx_buf,
- .len = 3,
+ .len = len,
.cs_change = 0,
};
struct spi_message m;
- u8 val = 0;
int ret;
- mutex_lock(&priv->spi_lock);
-
- priv->spi_tx_buf[0] = INSTRUCTION_READ;
- priv->spi_tx_buf[1] = reg;
-
spi_message_init(&m);
if (mcp251x_enable_dma) {
spi_message_add_tail(&t, &m);
ret = spi_sync(spi, &m);
- if (ret < 0)
- dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
- else
- val = priv->spi_rx_buf[2];
+ if (ret)
+ dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
+ return ret;
+}
+
+static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ u8 val = 0;
+
+ mutex_lock(&priv->spi_lock);
+
+ priv->spi_tx_buf[0] = INSTRUCTION_READ;
+ priv->spi_tx_buf[1] = reg;
+
+ mcp251x_spi_trans(spi, 3);
+ val = priv->spi_rx_buf[2];
mutex_unlock(&priv->spi_lock);
- dev_dbg(&spi->dev, "%s: read %02x = %02x\n", __func__, reg, val);
return val;
}
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- struct spi_transfer t = {
- .tx_buf = priv->spi_tx_buf,
- .rx_buf = priv->spi_rx_buf,
- .len = 3,
- .cs_change = 0,
- };
- struct spi_message m;
- int ret;
mutex_lock(&priv->spi_lock);
priv->spi_tx_buf[1] = reg;
priv->spi_tx_buf[2] = val;
- spi_message_init(&m);
-
- if (mcp251x_enable_dma) {
- t.tx_dma = priv->spi_tx_dma;
- t.rx_dma = priv->spi_rx_dma;
- m.is_dma_mapped = 1;
- }
-
- spi_message_add_tail(&t, &m);
-
- ret = spi_sync(spi, &m);
+ mcp251x_spi_trans(spi, 3);
mutex_unlock(&priv->spi_lock);
-
- if (ret < 0)
- dev_dbg(&spi->dev, "%s: failed\n", __func__);
}
static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
u8 mask, uint8_t val)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- struct spi_transfer t = {
- .tx_buf = priv->spi_tx_buf,
- .rx_buf = priv->spi_rx_buf,
- .len = 4,
- .cs_change = 0,
- };
- struct spi_message m;
- int ret;
mutex_lock(&priv->spi_lock);
priv->spi_tx_buf[2] = mask;
priv->spi_tx_buf[3] = val;
- spi_message_init(&m);
-
- if (mcp251x_enable_dma) {
- t.tx_dma = priv->spi_tx_dma;
- t.rx_dma = priv->spi_rx_dma;
- m.is_dma_mapped = 1;
- }
+ mcp251x_spi_trans(spi, 4);
- spi_message_add_tail(&t, &m);
+ mutex_unlock(&priv->spi_lock);
+}
- ret = spi_sync(spi, &m);
+static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
+ int len, int tx_buf_idx)
+{
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- mutex_unlock(&priv->spi_lock);
+ if (pdata->model == CAN_MCP251X_MCP2510) {
+ int i;
- if (ret < 0)
- dev_dbg(&spi->dev, "%s: failed\n", __func__);
+ for (i = 1; i < TXBDAT_OFF + len; i++)
+ mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
+ buf[i]);
+ } else {
+ mutex_lock(&priv->spi_lock);
+ memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);
+ mcp251x_spi_trans(spi, TXBDAT_OFF + len);
+ mutex_unlock(&priv->spi_lock);
+ }
}
-static int mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
+static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
int tx_buf_idx)
{
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
u32 sid, eid, exide, rtr;
-
- dev_dbg(&spi->dev, "%s\n", __func__);
+ u8 buf[SPI_TRANSFER_BUF_LEN];
exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
if (exide)
eid = frame->can_id & CAN_EFF_MASK; /* Extended ID */
rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; /* Remote transmission */
- if (pdata->model == CAN_MCP251X_MCP2510) {
- int i;
-
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 1, sid >> 3);
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 2,
- ((sid & 7) << 5) | (exide << 3) |
- ((eid >> 16) & 3));
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 3,
- (eid >> 8) & 0xff);
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 4, eid & 0xff);
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 5,
- (rtr << 6) | frame->can_dlc);
-
- for (i = 0; i < frame->can_dlc ; i++) {
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + 6 + i,
- frame->data[i]);
- }
- } else {
- struct spi_transfer t = {
- .tx_buf = priv->spi_tx_buf,
- .rx_buf = priv->spi_rx_buf,
- .cs_change = 0,
- .len = 6 + CAN_FRAME_MAX_DATA_LEN,
- };
- struct spi_message m;
- int ret;
- u8 *tx_buf = priv->spi_tx_buf;
-
- mutex_lock(&priv->spi_lock);
+ buf[TXBCTRL_OFF] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
+ buf[TXBSIDH_OFF] = sid >> SIDH_SHIFT;
+ buf[TXBSIDL_OFF] = ((sid & SIDL_SID_MASK) << SIDL_SID_SHIFT) |
+ (exide << SIDL_EXIDE_SHIFT) |
+ ((eid >> SIDL_EID_SHIFT) & SIDL_EID_MASK);
+ buf[TXBEID8_OFF] = GET_BYTE(eid, 1);
+ buf[TXBEID0_OFF] = GET_BYTE(eid, 0);
+ buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc;
+ memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);
+ mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);
+ mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
+}
- tx_buf[0] = INSTRUCTION_LOAD_TXB(tx_buf_idx);
- tx_buf[1] = sid >> 3;
- tx_buf[2] = ((sid & 7) << 5) | (exide << 3) |
- ((eid >> 16) & 3);
- tx_buf[3] = (eid >> 8) & 0xff;
- tx_buf[4] = eid & 0xff;
- tx_buf[5] = (rtr << 6) | frame->can_dlc;
+static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
+ int buf_idx)
+{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- memcpy(tx_buf + 6, frame->data, frame->can_dlc);
+ if (pdata->model == CAN_MCP251X_MCP2510) {
+ int i, len;
- spi_message_init(&m);
+ for (i = 1; i < RXBDAT_OFF; i++)
+ buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
- if (mcp251x_enable_dma) {
- t.tx_dma = priv->spi_tx_dma;
- t.rx_dma = priv->spi_rx_dma;
- m.is_dma_mapped = 1;
- }
-
- spi_message_add_tail(&t, &m);
+ len = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);
+ for (; i < (RXBDAT_OFF + len); i++)
+ buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
+ } else {
+ mutex_lock(&priv->spi_lock);
- ret = spi_sync(spi, &m);
+ priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
+ mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
+ memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
mutex_unlock(&priv->spi_lock);
-
- if (ret < 0) {
- dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__,
- ret);
- return -1;
- }
}
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
- return 0;
}
static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- struct mcp251x_platform_data *pdata = spi->dev.platform_data;
struct sk_buff *skb;
struct can_frame *frame;
+ u8 buf[SPI_TRANSFER_BUF_LEN];
- dev_dbg(&spi->dev, "%s\n", __func__);
-
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = alloc_can_skb(priv->net, &frame);
if (!skb) {
- dev_dbg(&spi->dev, "%s: out of memory for Rx'd frame\n",
- __func__);
+ dev_err(&spi->dev, "cannot allocate RX skb\n");
priv->net->stats.rx_dropped++;
return;
}
- skb->dev = priv->net;
- frame = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
-
- if (pdata->model == CAN_MCP251X_MCP2510) {
- int i;
- u8 rx_buf[6];
-
- rx_buf[1] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 1);
- rx_buf[2] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 2);
- rx_buf[3] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 3);
- rx_buf[4] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 4);
- rx_buf[5] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + 5);
-
- if ((rx_buf[2] >> 3) & 0x1) {
- /* Extended ID format */
- frame->can_id = CAN_EFF_FLAG;
- frame->can_id |= ((rx_buf[2] & 3) << 16) |
- (rx_buf[3] << 8) | rx_buf[4] |
- (((rx_buf[1] << 3) | (rx_buf[2] >> 5)) << 18);
- } else {
- /* Standard ID format */
- frame->can_id = (rx_buf[1] << 3) | (rx_buf[2] >> 5);
- }
- if ((rx_buf[5] >> 6) & 0x1) {
- /* Remote transmission request */
+ mcp251x_hw_rx_frame(spi, buf, buf_idx);
+ if (buf[RXBSIDL_OFF] & RXBSIDL_IDE) {
+ /* Extended ID format */
+ frame->can_id = CAN_EFF_FLAG;
+ frame->can_id |=
+ /* Extended ID part */
+ SET_BYTE(buf[RXBSIDL_OFF] & RXBSIDL_EID, 2) |
+ SET_BYTE(buf[RXBEID8_OFF], 1) |
+ SET_BYTE(buf[RXBEID0_OFF], 0) |
+ /* Standard ID part */
+ (((buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+ (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT)) << 18);
+ /* Remote transmission request */
+ if (buf[RXBDLC_OFF] & RXBDLC_RTR)
frame->can_id |= CAN_RTR_FLAG;
- }
-
- /* Data length */
- frame->can_dlc = rx_buf[5] & 0x0f;
- if (frame->can_dlc > 8) {
- dev_warn(&spi->dev, "invalid frame recevied\n");
- priv->net->stats.rx_errors++;
- dev_kfree_skb(skb);
- return;
- }
-
- for (i = 0; i < frame->can_dlc; i++) {
- frame->data[i] = mcp251x_read_reg(spi,
- RXBCTRL(buf_idx) +
- 6 + i);
- }
} else {
- struct spi_transfer t = {
- .tx_buf = priv->spi_tx_buf,
- .rx_buf = priv->spi_rx_buf,
- .cs_change = 0,
- .len = 14, /* RX buffer: RXBnCTRL to RXBnD7 */
- };
- struct spi_message m;
- int ret;
- u8 *tx_buf = priv->spi_tx_buf;
- u8 *rx_buf = priv->spi_rx_buf;
-
- mutex_lock(&priv->spi_lock);
-
- tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx);
-
- spi_message_init(&m);
-
- if (mcp251x_enable_dma) {
- t.tx_dma = priv->spi_tx_dma;
- t.rx_dma = priv->spi_rx_dma;
- m.is_dma_mapped = 1;
- }
-
- spi_message_add_tail(&t, &m);
-
- ret = spi_sync(spi, &m);
-
- if (ret < 0) {
- dev_dbg(&spi->dev, "%s: failed: ret = %d\n",
- __func__, ret);
- priv->net->stats.rx_errors++;
- mutex_unlock(&priv->spi_lock);
- return;
- }
-
- if ((rx_buf[2] >> 3) & 0x1) {
- /* Extended ID format */
- frame->can_id = CAN_EFF_FLAG;
- frame->can_id |= ((rx_buf[2] & 3) << 16) |
- (rx_buf[3] << 8) | rx_buf[4] |
- (((rx_buf[1] << 3) | (rx_buf[2] >> 5)) << 18);
- } else {
- /* Standard ID format */
- frame->can_id = (rx_buf[1] << 3) | (rx_buf[2] >> 5);
- }
-
- if ((rx_buf[5] >> 6) & 0x1) {
- /* Remote transmission request */
- frame->can_id |= CAN_RTR_FLAG;
- }
-
- /* Data length */
- frame->can_dlc = rx_buf[5] & 0x0f;
- if (frame->can_dlc > 8) {
- dev_warn(&spi->dev, "invalid frame recevied\n");
- priv->net->stats.rx_errors++;
- dev_kfree_skb(skb);
- mutex_unlock(&priv->spi_lock);
- return;
- }
-
- memcpy(frame->data, rx_buf + 6, CAN_FRAME_MAX_DATA_LEN);
-
- mutex_unlock(&priv->spi_lock);
+ /* Standard ID format */
+ frame->can_id =
+ (buf[RXBSIDH_OFF] << RXBSIDH_SHIFT) |
+ (buf[RXBSIDL_OFF] >> RXBSIDL_SHIFT);
}
+ /* Data length */
+ frame->can_dlc = get_can_dlc(buf[RXBDLC_OFF] & RXBDLC_LEN_MASK);
+ memcpy(frame->data, buf + RXBDAT_OFF, frame->can_dlc);
priv->net->stats.rx_packets++;
priv->net->stats.rx_bytes += frame->can_dlc;
-
- skb->protocol = __constant_htons(ETH_P_CAN);
- skb->pkt_type = PACKET_BROADCAST;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
}
dev_err(&spi->dev, "MCP251x didn't wake-up\n");
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
static int mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net)
+#else
+static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *net)
+#endif
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
- dev_dbg(&spi->dev, "%s\n", __func__);
-
- if (priv->tx_skb) {
- dev_warn(&spi->dev, "hard_xmit called with not null tx_skb\n");
+ if (priv->tx_skb || priv->tx_len) {
+ dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+ netif_stop_queue(net);
return NETDEV_TX_BUSY;
}
- if (skb->len != sizeof(struct can_frame)) {
- dev_dbg(&spi->dev, "dropping packet - bad length\n");
- dev_kfree_skb(skb);
- net->stats.tx_dropped++;
- return 0;
- }
+ if (can_dropped_invalid_skb(net, skb))
+ return NETDEV_TX_OK;
netif_stop_queue(net);
priv->tx_skb = skb;
static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
{
struct mcp251x_priv *priv = netdev_priv(net);
- struct spi_device *spi = priv->spi;
-
- dev_dbg(&spi->dev, "%s (unimplemented)\n", __func__);
switch (mode) {
+ case CAN_MODE_START:
+ /* We have to delay work since SPI I/O may sleep */
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ priv->restart_tx = 1;
+ if (priv->can.restart_ms == 0)
+ priv->after_suspend = AFTER_SUSPEND_RESTART;
+ queue_work(priv->wq, &priv->irq_work);
+ break;
default:
return -EOPNOTSUPP;
}
/* Enable interrupts */
mcp251x_write_reg(spi, CANINTE,
- CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
- CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE);
+ CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
+ CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE |
+ CANINTF_MERRF);
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* Put device into loopback mode */
/* Wait for the device to enter normal mode */
timeout = jiffies + HZ;
- while (mcp251x_read_reg(spi, CANSTAT) & 0xE0) {
- udelay(10);
+ while (mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) {
+ schedule();
if (time_after(jiffies, timeout)) {
dev_err(&spi->dev, "MCP251x didn't"
" enter in normal mode\n");
- break;
+ return;
}
}
}
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
static int mcp251x_do_set_bittiming(struct net_device *net)
struct mcp251x_priv *priv = netdev_priv(net);
struct can_bittiming *bt = &priv->can.bittiming;
struct spi_device *spi = priv->spi;
- u8 state;
- dev_dbg(&spi->dev, "%s: BRP = %d, PropSeg = %d, PS1 = %d,"
- " PS2 = %d, SJW = %d\n", __func__, bt->brp,
- bt->prop_seg, bt->phase_seg1, bt->phase_seg2,
- bt->sjw);
-
- /* Store original mode and set mode to config */
- state = mcp251x_read_reg(spi, CANCTRL);
- state = mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK;
- mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK,
- CANCTRL_REQOP_CONF);
-
- mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << 6) | (bt->brp - 1));
+ mcp251x_write_reg(spi, CNF1, ((bt->sjw - 1) << CNF1_SJW_SHIFT) |
+ (bt->brp - 1));
mcp251x_write_reg(spi, CNF2, CNF2_BTLMODE |
- ((bt->phase_seg1 - 1) << 3) |
+ (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES ?
+ CNF2_SAM : 0) |
+ ((bt->phase_seg1 - 1) << CNF2_PS1_SHIFT) |
(bt->prop_seg - 1));
mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
(bt->phase_seg2 - 1));
-
- /* Restore original state */
- mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, state);
+ dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+ mcp251x_read_reg(spi, CNF1),
+ mcp251x_read_reg(spi, CNF2),
+ mcp251x_read_reg(spi, CNF3));
return 0;
}
-static void mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
- struct spi_device *spi)
+static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
+ struct spi_device *spi)
{
- int ret;
-
- /* Set initial baudrate. Make sure that registers are updated
- always by explicitly calling mcp251x_do_set_bittiming */
- ret = can_set_bittiming(net);
- if (ret)
- dev_err(&spi->dev, "unable to set initial baudrate!\n");
- else
- mcp251x_do_set_bittiming(net);
+ mcp251x_do_set_bittiming(net);
/* Enable RX0->RX1 buffer roll over and disable filters */
mcp251x_write_bits(spi, RXBCTRL(0),
mcp251x_write_bits(spi, RXBCTRL(1),
RXBCTRL_RXM0 | RXBCTRL_RXM1,
RXBCTRL_RXM0 | RXBCTRL_RXM1);
-
- dev_dbg(&spi->dev, "%s RXBCTL 0 and 1: %02x %02x\n", __func__,
- mcp251x_read_reg(spi, RXBCTRL(0)),
- mcp251x_read_reg(spi, RXBCTRL(1)));
+ return 0;
}
static void mcp251x_hw_reset(struct spi_device *spi)
mutex_unlock(&priv->spi_lock);
- if (ret < 0)
- dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __func__, ret);
- /* wait for reset to finish */
+ if (ret)
+ dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
+ /* Wait for reset to finish */
mdelay(10);
}
mcp251x_hw_reset(spi);
+ /*
+ * Please note that these are "magic values" based on after
+ * reset defaults taken from data sheet which allows us to see
+ * if we really have a chip on the bus (we avoid common all
+ * zeroes or all ones situations)
+ */
st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
- dev_dbg(&spi->dev, "%s: 0x%02x - 0x%02x\n", __func__,
- st1, st2);
+ dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
- /* check for power up default values */
+ /* Check for power up default values */
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
}
+static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
+{
+ struct net_device *net = (struct net_device *)dev_id;
+ struct mcp251x_priv *priv = netdev_priv(net);
+
+ /* Schedule bottom half */
+ if (!work_pending(&priv->irq_work))
+ queue_work(priv->wq, &priv->irq_work);
+
+ return IRQ_HANDLED;
+}
+
static int mcp251x_open(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ int ret;
- dev_dbg(&spi->dev, "%s\n", __func__);
+ ret = open_candev(net);
+ if (ret) {
+ dev_err(&spi->dev, "unable to set initial baudrate!\n");
+ return ret;
+ }
if (pdata->transceiver_enable)
pdata->transceiver_enable(1);
priv->force_quit = 0;
priv->tx_skb = NULL;
- enable_irq(spi->irq);
+ priv->tx_len = 0;
+
+ ret = request_irq(spi->irq, mcp251x_can_isr,
+ IRQF_TRIGGER_FALLING, DEVICE_NAME, net);
+ if (ret) {
+ dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ close_candev(net);
+ return ret;
+ }
+
mcp251x_hw_wakeup(spi);
mcp251x_hw_reset(spi);
- mcp251x_setup(net, priv, spi);
+ ret = mcp251x_setup(net, priv, spi);
+ if (ret) {
+ free_irq(spi->irq, net);
+ mcp251x_hw_sleep(spi);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ close_candev(net);
+ return ret;
+ }
mcp251x_set_normal_mode(spi);
netif_wake_queue(net);
struct spi_device *spi = priv->spi;
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- dev_dbg(&spi->dev, "%s\n", __func__);
+ close_candev(net);
/* Disable and clear pending interrupts */
mcp251x_write_reg(spi, CANINTE, 0x00);
mcp251x_write_reg(spi, CANINTF, 0x00);
priv->force_quit = 1;
- disable_irq(spi->irq);
+ free_irq(spi->irq, net);
flush_workqueue(priv->wq);
mcp251x_write_reg(spi, TXBCTRL(0), 0);
- if (priv->tx_skb) {
- net->stats.tx_errors++;
- dev_kfree_skb(priv->tx_skb);
- priv->tx_skb = NULL;
- }
+ if (priv->tx_skb || priv->tx_len)
+ mcp251x_clean(net);
mcp251x_hw_sleep(spi);
if (pdata->transceiver_enable)
pdata->transceiver_enable(0);
- return 0;
-}
-
-static int mcp251x_do_get_state(struct net_device *net, enum can_state *state)
-{
- struct mcp251x_priv *priv = netdev_priv(net);
- struct spi_device *spi = priv->spi;
- u8 eflag;
-
- eflag = mcp251x_read_reg(spi, EFLG);
-
- if (eflag & EFLG_TXBO)
- *state = CAN_STATE_BUS_OFF;
- else if (eflag & (EFLG_RXEP | EFLG_TXEP))
- *state = CAN_STATE_BUS_PASSIVE;
- else if (eflag & EFLG_EWARN)
- *state = CAN_STATE_BUS_WARNING;
- else
- *state = CAN_STATE_ACTIVE;
+ priv->can.state = CAN_STATE_STOPPED;
return 0;
}
struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
tx_work);
struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
struct can_frame *frame;
- dev_dbg(&spi->dev, "%s\n", __func__);
-
if (priv->tx_skb) {
frame = (struct can_frame *)priv->tx_skb->data;
+
+ if (priv->can.state == CAN_STATE_BUS_OFF) {
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ return;
+ }
if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
mcp251x_hw_tx(spi, frame, 0);
+ priv->tx_len = 1 + frame->can_dlc;
+ can_put_echo_skb(priv->tx_skb, net, 0);
+ priv->tx_skb = NULL;
}
}
irq_work);
struct spi_device *spi = priv->spi;
struct net_device *net = priv->net;
- u8 intf;
u8 txbnctrl;
+ u8 intf;
+ enum can_state new_state;
if (priv->after_suspend) {
- /* Wait whilst the device wakes up */
mdelay(10);
mcp251x_hw_reset(spi);
mcp251x_setup(net, priv, spi);
- if (priv->after_suspend & AFTER_SUSPEND_UP) {
+ if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
+ mcp251x_set_normal_mode(spi);
+ } else if (priv->after_suspend & AFTER_SUSPEND_UP) {
netif_device_attach(net);
- /* clear since we lost tx buffer */
- if (priv->tx_skb) {
- net->stats.tx_errors++;
- dev_kfree_skb(priv->tx_skb);
- priv->tx_skb = NULL;
+ /* Clean since we lost tx buffer */
+ if (priv->tx_skb || priv->tx_len) {
+ mcp251x_clean(net);
netif_wake_queue(net);
}
mcp251x_set_normal_mode(spi);
- } else
+ } else {
mcp251x_hw_sleep(spi);
+ }
priv->after_suspend = 0;
- return;
}
+ if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF)
+ return;
+
while (!priv->force_quit && !freezing(current)) {
+ u8 eflag = mcp251x_read_reg(spi, EFLG);
+ int can_id = 0, data1 = 0;
+
+ mcp251x_write_reg(spi, EFLG, 0x00);
+
if (priv->restart_tx) {
priv->restart_tx = 0;
- dev_warn(&spi->dev,
- "timeout in txing a packet, restarting\n");
mcp251x_write_reg(spi, TXBCTRL(0), 0);
- if (priv->tx_skb) {
- net->stats.tx_errors++;
- dev_kfree_skb(priv->tx_skb);
- priv->tx_skb = NULL;
- }
+ if (priv->tx_skb || priv->tx_len)
+ mcp251x_clean(net);
netif_wake_queue(net);
+ can_id |= CAN_ERR_RESTARTED;
}
if (priv->wake) {
}
intf = mcp251x_read_reg(spi, CANINTF);
- if (intf == 0x00)
- break;
mcp251x_write_bits(spi, CANINTF, intf, 0x00);
- 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" : "");
-
- if (intf & CANINTF_WAKIF)
- complete(&priv->awake);
+ /* Update can state */
+ if (eflag & EFLG_TXBO) {
+ new_state = CAN_STATE_BUS_OFF;
+ can_id |= CAN_ERR_BUSOFF;
+ } else if (eflag & EFLG_TXEP) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_TX_PASSIVE;
+ } else if (eflag & EFLG_RXEP) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_PASSIVE;
+ } else if (eflag & EFLG_TXWAR) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_TX_WARNING;
+ } else if (eflag & EFLG_RXWAR) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_WARNING;
+ } else {
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
- if (intf & CANINTF_MERRF) {
- /* if there are no pending Tx buffers, restart queue */
- txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
- if (!(txbnctrl & TXBCTRL_TXREQ)) {
- if (priv->tx_skb) {
- net->stats.tx_errors++;
- dev_kfree_skb(priv->tx_skb);
- priv->tx_skb = NULL;
- }
- netif_wake_queue(net);
- }
+ /* Update can state statistics */
+ switch (priv->can.state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ if (new_state >= CAN_STATE_ERROR_WARNING &&
+ new_state <= CAN_STATE_BUS_OFF)
+ priv->can.can_stats.error_warning++;
+ case CAN_STATE_ERROR_WARNING: /* fallthrough */
+ if (new_state >= CAN_STATE_ERROR_PASSIVE &&
+ new_state <= CAN_STATE_BUS_OFF)
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ break;
}
+ priv->can.state = new_state;
- if (intf & CANINTF_ERRIF) {
+ if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) {
struct sk_buff *skb;
- struct can_frame *frame = NULL;
- u8 eflag = mcp251x_read_reg(spi, EFLG);
-
- dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflag);
+ struct can_frame *frame;
/* Create error frame */
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = alloc_can_err_skb(net, &frame);
if (skb) {
- frame = (struct can_frame *)
- skb_put(skb, sizeof(struct can_frame));
- *(unsigned long long *)&frame->data = 0ULL;
- frame->can_id = CAN_ERR_FLAG;
- frame->can_dlc = CAN_ERR_DLC;
-
- skb->dev = net;
- skb->protocol = __constant_htons(ETH_P_CAN);
- skb->pkt_type = PACKET_BROADCAST;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
/* Set error frame flags based on bus state */
- if (eflag & EFLG_TXBO) {
- frame->can_id |= CAN_ERR_BUSOFF;
- } else if (eflag & EFLG_TXEP) {
- frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] |=
- CAN_ERR_CRTL_TX_PASSIVE;
- } else if (eflag & EFLG_RXEP) {
- frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] |=
- CAN_ERR_CRTL_RX_PASSIVE;
- } else if (eflag & EFLG_TXWAR) {
- frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] |=
- CAN_ERR_CRTL_TX_WARNING;
- } else if (eflag & EFLG_RXWAR) {
+ frame->can_id = can_id;
+ frame->data[1] = data1;
+
+ /* Update net stats for overflows */
+ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
+ if (eflag & EFLG_RX0OVR)
+ net->stats.rx_over_errors++;
+ if (eflag & EFLG_RX1OVR)
+ net->stats.rx_over_errors++;
frame->can_id |= CAN_ERR_CRTL;
frame->data[1] |=
- CAN_ERR_CRTL_RX_WARNING;
+ CAN_ERR_CRTL_RX_OVERFLOW;
}
+
+ netif_rx(skb);
+ } else {
+ dev_info(&spi->dev,
+ "cannot allocate error skb\n");
}
+ }
- if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
- if (eflag & EFLG_RX0OVR)
- net->stats.rx_over_errors++;
- if (eflag & EFLG_RX1OVR)
- net->stats.rx_over_errors++;
- if (frame) {
- frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] =
- CAN_ERR_CRTL_RX_OVERFLOW;
- }
+ if (priv->can.state == CAN_STATE_BUS_OFF) {
+ if (priv->can.restart_ms == 0) {
+ can_bus_off(net);
+ mcp251x_hw_sleep(spi);
+ return;
}
- mcp251x_write_reg(spi, EFLG, 0x00);
+ }
- if (skb)
- netif_rx(skb);
+ if (intf == 0)
+ break;
+
+ if (intf & CANINTF_WAKIF)
+ complete(&priv->awake);
+
+ if (intf & CANINTF_MERRF) {
+ /* If there are pending Tx buffers, restart queue */
+ txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
+ if (!(txbnctrl & TXBCTRL_TXREQ)) {
+ if (priv->tx_skb || priv->tx_len)
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ }
}
if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
- if (priv->tx_skb) {
- net->stats.tx_packets++;
- net->stats.tx_bytes +=
- ((struct can_frame *)
- (priv->tx_skb->data))->can_dlc;
- dev_kfree_skb(priv->tx_skb);
- priv->tx_skb = NULL;
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += priv->tx_len - 1;
+ if (priv->tx_len) {
+ can_get_echo_skb(net, 0);
+ priv->tx_len = 0;
}
netif_wake_queue(net);
}
if (intf & CANINTF_RX1IF)
mcp251x_hw_rx(spi, 1);
-
}
-
- mcp251x_read_reg(spi, CANSTAT);
-
- dev_dbg(&spi->dev, "interrupt ended\n");
-}
-
-static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
-{
- struct net_device *net = (struct net_device *)dev_id;
- struct mcp251x_priv *priv = netdev_priv(net);
-
- dev_dbg(&priv->spi->dev, "%s: irq\n", __func__);
- /* Schedule bottom half */
- if (!work_pending(&priv->irq_work))
- queue_work(priv->wq, &priv->irq_work);
-
- return IRQ_HANDLED;
-}
-
-static void mcp251x_tx_timeout(struct net_device *net)
-{
- struct mcp251x_priv *priv = netdev_priv(net);
-
- priv->restart_tx = 1;
- queue_work(priv->wq, &priv->irq_work);
}
-static struct net_device *alloc_mcp251x_netdev(int sizeof_priv)
-{
- struct net_device *net;
- struct mcp251x_priv *priv;
-
- net = alloc_candev(sizeof_priv);
- if (!net)
- return NULL;
-
- priv = netdev_priv(net);
-
- net->open = mcp251x_open;
- net->stop = mcp251x_stop;
- net->hard_start_xmit = mcp251x_hard_start_xmit;
- net->tx_timeout = mcp251x_tx_timeout;
- net->watchdog_timeo = HZ;
-
- priv->can.bittiming_const = &mcp251x_bittiming_const;
- priv->can.do_get_state = mcp251x_do_get_state;
- priv->can.do_set_mode = mcp251x_do_set_mode;
-
- priv->net = net;
-
- return net;
-}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+static const struct net_device_ops mcp251x_netdev_ops = {
+ .ndo_open = mcp251x_open,
+ .ndo_stop = mcp251x_stop,
+ .ndo_start_xmit = mcp251x_hard_start_xmit,
+};
+#endif
static int __devinit mcp251x_can_probe(struct spi_device *spi)
{
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
int ret = -ENODEV;
- if (!pdata) {
+ if (!pdata)
/* Platform data is required for osc freq */
goto error_out;
- }
/* Allocate can/net device */
- net = alloc_mcp251x_netdev(sizeof(struct mcp251x_priv));
+ net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
if (!net) {
ret = -ENOMEM;
goto error_alloc;
}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+ net->netdev_ops = &mcp251x_netdev_ops;
+#else
+ net->open = mcp251x_open;
+ net->stop = mcp251x_stop;
+ net->hard_start_xmit = mcp251x_hard_start_xmit;
+#endif
+ net->flags |= IFF_ECHO;
+
priv = netdev_priv(net);
+ priv->can.bittiming_const = &mcp251x_bittiming_const;
+ priv->can.do_set_mode = mcp251x_do_set_mode;
+ priv->can.clock.freq = pdata->oscillator_frequency / 2;
+ priv->net = net;
dev_set_drvdata(&spi->dev, priv);
priv->spi = spi;
mutex_init(&priv->spi_lock);
- priv->can.bittiming.clock = pdata->oscillator_frequency / 2;
-
/* If requested, allocate DMA buffers */
if (mcp251x_enable_dma) {
- spi->dev.coherent_dma_mask = DMA_32BIT_MASK;
+ spi->dev.coherent_dma_mask = ~0;
- /* Minimum coherent DMA allocation is PAGE_SIZE, so allocate
- that much and share it between Tx and Rx DMA buffers. */
+ /*
+ * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+ * that much and share it between Tx and Rx DMA buffers.
+ */
priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
- PAGE_SIZE, &priv->spi_tx_dma, GFP_DMA);
+ PAGE_SIZE,
+ &priv->spi_tx_dma,
+ GFP_DMA);
if (priv->spi_tx_buf) {
priv->spi_rx_buf = (u8 *)(priv->spi_tx_buf +
- (PAGE_SIZE / 2));
+ (PAGE_SIZE / 2));
priv->spi_rx_dma = (dma_addr_t)(priv->spi_tx_dma +
- (PAGE_SIZE / 2));
+ (PAGE_SIZE / 2));
} else {
/* Fall back to non-DMA */
mcp251x_enable_dma = 0;
goto error_tx_buf;
}
priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
- if (!priv->spi_tx_buf) {
+ if (!priv->spi_rx_buf) {
ret = -ENOMEM;
goto error_rx_buf;
}
spi->bits_per_word = 8;
spi_setup(spi);
- /* Register IRQ */
- if (request_irq(spi->irq, mcp251x_can_isr,
- IRQF_TRIGGER_FALLING, DEVICE_NAME, net) < 0) {
- dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
- goto error_irq;
- }
- disable_irq(spi->irq);
-
if (!mcp251x_hw_probe(spi)) {
dev_info(&spi->dev, "Probe failed\n");
goto error_probe;
pdata->transceiver_enable(0);
ret = register_candev(net);
- if (ret >= 0) {
+ if (!ret) {
dev_info(&spi->dev, "probed\n");
return ret;
}
error_probe:
- free_irq(spi->irq, net);
-error_irq:
if (!mcp251x_enable_dma)
kfree(priv->spi_rx_buf);
error_rx_buf:
kfree(priv->spi_tx_buf);
error_tx_buf:
free_candev(net);
- if (mcp251x_enable_dma) {
+ if (mcp251x_enable_dma)
dma_free_coherent(&spi->dev, PAGE_SIZE,
- priv->spi_tx_buf, priv->spi_tx_dma);
- }
+ priv->spi_tx_buf, priv->spi_tx_dma);
error_alloc:
+ if (pdata->power_enable)
+ pdata->power_enable(0);
dev_err(&spi->dev, "probe failed\n");
error_out:
return ret;
unregister_candev(net);
free_candev(net);
- free_irq(spi->irq, net);
priv->force_quit = 1;
flush_workqueue(priv->wq);
destroy_workqueue(priv->wq);
if (mcp251x_enable_dma) {
dma_free_coherent(&spi->dev, PAGE_SIZE,
- priv->spi_tx_buf, priv->spi_tx_dma);
+ priv->spi_tx_buf, priv->spi_tx_dma);
} else {
kfree(priv->spi_tx_buf);
kfree(priv->spi_rx_buf);
if (pdata->transceiver_enable)
pdata->transceiver_enable(0);
priv->after_suspend = AFTER_SUSPEND_UP;
- } else
+ } else {
priv->after_suspend = AFTER_SUSPEND_DOWN;
+ }
if (pdata->power_enable) {
pdata->power_enable(0);
if (pdata->transceiver_enable)
pdata->transceiver_enable(1);
queue_work(priv->wq, &priv->irq_work);
- } else
+ } else {
priv->after_suspend = 0;
+ }
}
return 0;
}
static struct spi_driver mcp251x_can_driver = {
.driver = {
- .name = DEVICE_NAME,
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
+ .name = DEVICE_NAME,
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
},
- .probe = mcp251x_can_probe,
- .remove = __devexit_p(mcp251x_can_remove),
- .suspend = mcp251x_can_suspend,
- .resume = mcp251x_can_resume,
+ .probe = mcp251x_can_probe,
+ .remove = __devexit_p(mcp251x_can_remove),
+ .suspend = mcp251x_can_suspend,
+ .resume = mcp251x_can_resume,
};
static int __init mcp251x_can_init(void)