]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'can/mcp251x-for-net-next' of git://git.pengutronix.de/git/mkl/linux-2.6
authorDavid S. Miller <davem@davemloft.net>
Mon, 18 Oct 2010 14:11:44 +0000 (07:11 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 18 Oct 2010 14:11:44 +0000 (07:11 -0700)
drivers/net/can/mcp251x.c
include/linux/can/platform/mcp251x.h

index b11a0cb5ed81eb9ffabaa067dcdc544edabadc22..c664be261e98b1bcb93eda8bea211ecb574adbfb 100644 (file)
  * static struct mcp251x_platform_data mcp251x_info = {
  *         .oscillator_frequency = 8000000,
  *         .board_specific_setup = &mcp251x_setup,
- *         .model = CAN_MCP251X_MCP2510,
  *         .power_enable = mcp251x_power_enable,
  *         .transceiver_enable = NULL,
  * };
  *
  * static struct spi_board_info spi_board_info[] = {
  *         {
- *                 .modalias = "mcp251x",
+ *                 .modalias = "mcp2510",
+ *                     // or "mcp2515" depending on your controller
  *                 .platform_data = &mcp251x_info,
  *                 .irq = IRQ_EINT13,
  *                 .max_speed_hz = 2*1000*1000,
 #  define CANINTF_TX0IF 0x04
 #  define CANINTF_RX1IF 0x02
 #  define CANINTF_RX0IF 0x01
+#  define CANINTF_ERR_TX \
+       (CANINTF_ERRIF | CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)
 #define EFLG         0x2d
 #  define EFLG_EWARN   0x01
 #  define EFLG_RXWAR   0x02
@@ -222,10 +224,16 @@ static struct can_bittiming_const mcp251x_bittiming_const = {
        .brp_inc = 1,
 };
 
+enum mcp251x_model {
+       CAN_MCP251X_MCP2510     = 0x2510,
+       CAN_MCP251X_MCP2515     = 0x2515,
+};
+
 struct mcp251x_priv {
        struct can_priv    can;
        struct net_device *net;
        struct spi_device *spi;
+       enum mcp251x_model model;
 
        struct mutex mcp_lock; /* SPI device lock */
 
@@ -250,6 +258,16 @@ struct mcp251x_priv {
        int restart_tx;
 };
 
+#define MCP251X_IS(_model) \
+static inline int mcp251x_is_##_model(struct spi_device *spi) \
+{ \
+       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \
+       return priv->model == CAN_MCP251X_MCP##_model; \
+}
+
+MCP251X_IS(2510);
+MCP251X_IS(2515);
+
 static void mcp251x_clean(struct net_device *net)
 {
        struct mcp251x_priv *priv = netdev_priv(net);
@@ -319,6 +337,20 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
        return val;
 }
 
+static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
+               uint8_t *v1, uint8_t *v2)
+{
+       struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+
+       priv->spi_tx_buf[0] = INSTRUCTION_READ;
+       priv->spi_tx_buf[1] = reg;
+
+       mcp251x_spi_trans(spi, 4);
+
+       *v1 = priv->spi_rx_buf[2];
+       *v2 = priv->spi_rx_buf[3];
+}
+
 static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
 {
        struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
@@ -346,10 +378,9 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
 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);
 
-       if (pdata->model == CAN_MCP251X_MCP2510) {
+       if (mcp251x_is_2510(spi)) {
                int i;
 
                for (i = 1; i < TXBDAT_OFF + len; i++)
@@ -392,9 +423,8 @@ 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;
 
-       if (pdata->model == CAN_MCP251X_MCP2510) {
+       if (mcp251x_is_2510(spi)) {
                int i, len;
 
                for (i = 1; i < RXBDAT_OFF; i++)
@@ -451,7 +481,7 @@ static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
 
        priv->net->stats.rx_packets++;
        priv->net->stats.rx_bytes += frame->can_dlc;
-       netif_rx(skb);
+       netif_rx_ni(skb);
 }
 
 static void mcp251x_hw_sleep(struct spi_device *spi)
@@ -676,7 +706,7 @@ static void mcp251x_error_skb(struct net_device *net, int can_id, int data1)
        if (skb) {
                frame->can_id = can_id;
                frame->data[1] = data1;
-               netif_rx(skb);
+               netif_rx_ni(skb);
        } else {
                dev_err(&net->dev,
                        "cannot allocate error skb\n");
@@ -754,24 +784,39 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
        mutex_lock(&priv->mcp_lock);
        while (!priv->force_quit) {
                enum can_state new_state;
-               u8 intf = mcp251x_read_reg(spi, CANINTF);
-               u8 eflag;
+               u8 intf, eflag;
+               u8 clear_intf = 0;
                int can_id = 0, data1 = 0;
 
+               mcp251x_read_2regs(spi, CANINTF, &intf, &eflag);
+
+               /* receive buffer 0 */
                if (intf & CANINTF_RX0IF) {
                        mcp251x_hw_rx(spi, 0);
-                       /* Free one buffer ASAP */
-                       mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF,
-                                          0x00);
+                       /*
+                        * Free one buffer ASAP
+                        * (The MCP2515 does this automatically.)
+                        */
+                       if (mcp251x_is_2510(spi))
+                               mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);
                }
 
-               if (intf & CANINTF_RX1IF)
+               /* receive buffer 1 */
+               if (intf & CANINTF_RX1IF) {
                        mcp251x_hw_rx(spi, 1);
+                       /* the MCP2515 does this automatically */
+                       if (mcp251x_is_2510(spi))
+                               clear_intf |= CANINTF_RX1IF;
+               }
 
-               mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+               /* any error or tx interrupt we need to clear? */
+               if (intf & CANINTF_ERR_TX)
+                       clear_intf |= intf & CANINTF_ERR_TX;
+               if (clear_intf)
+                       mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);
 
-               eflag = mcp251x_read_reg(spi, EFLG);
-               mcp251x_write_reg(spi, EFLG, 0x00);
+               if (eflag)
+                       mcp251x_write_bits(spi, EFLG, eflag, 0x00);
 
                /* Update can state */
                if (eflag & EFLG_TXBO) {
@@ -816,10 +861,14 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
                if (intf & CANINTF_ERRIF) {
                        /* Handle overflow counters */
                        if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
-                               if (eflag & EFLG_RX0OVR)
+                               if (eflag & EFLG_RX0OVR) {
                                        net->stats.rx_over_errors++;
-                               if (eflag & EFLG_RX1OVR)
+                                       net->stats.rx_errors++;
+                               }
+                               if (eflag & EFLG_RX1OVR) {
                                        net->stats.rx_over_errors++;
+                                       net->stats.rx_errors++;
+                               }
                                can_id |= CAN_ERR_CRTL;
                                data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
                        }
@@ -921,16 +970,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        struct net_device *net;
        struct mcp251x_priv *priv;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
-       int model = spi_get_device_id(spi)->driver_data;
        int ret = -ENODEV;
 
        if (!pdata)
                /* Platform data is required for osc freq */
                goto error_out;
 
-       if (model)
-               pdata->model = model;
-
        /* Allocate can/net device */
        net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
        if (!net) {
@@ -947,6 +992,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        priv->can.clock.freq = pdata->oscillator_frequency / 2;
        priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
                CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
+       priv->model = spi_get_device_id(spi)->driver_data;
        priv->net = net;
        dev_set_drvdata(&spi->dev, priv);
 
@@ -1120,8 +1166,7 @@ static int mcp251x_can_resume(struct spi_device *spi)
 #define mcp251x_can_resume NULL
 #endif
 
-static struct spi_device_id mcp251x_id_table[] = {
-       { "mcp251x",    0 /* Use pdata.model */ },
+static const struct spi_device_id mcp251x_id_table[] = {
        { "mcp2510",    CAN_MCP251X_MCP2510 },
        { "mcp2515",    CAN_MCP251X_MCP2515 },
        { },
index dba28268e651931d8b3094438158d15c10d3ca2c..8e20540043f55dfffc4b2096ceee6ca817e994df 100644 (file)
@@ -12,7 +12,6 @@
 /**
  * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
  * @oscillator_frequency:       - oscillator frequency in Hz
- * @model:                      - actual type of chip
  * @board_specific_setup:       - called before probing the chip (power,reset)
  * @transceiver_enable:         - called to power on/off the transceiver
  * @power_enable:               - called to power on/off the mcp *and* the
@@ -25,9 +24,6 @@
 
 struct mcp251x_platform_data {
        unsigned long oscillator_frequency;
-       int model;
-#define CAN_MCP251X_MCP2510 0x2510
-#define CAN_MCP251X_MCP2515 0x2515
        int (*board_specific_setup)(struct spi_device *spi);
        int (*transceiver_enable)(int enable);
        int (*power_enable) (int enable);