can: mcp251x: write intf only when needed
[pandora-kernel.git] / drivers / net / can / mcp251x.c
index b39b108..f5e2edd 100644 (file)
@@ -58,7 +58,6 @@
  *
  */
 
-#include <linux/can.h>
 #include <linux/can/core.h>
 #include <linux/can/dev.h>
 #include <linux/can/platform/mcp251x.h>
 #  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
@@ -320,6 +321,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);
@@ -452,7 +467,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)
@@ -476,7 +491,6 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
 
        netif_stop_queue(net);
        priv->tx_skb = skb;
-       net->trans_start = jiffies;
        queue_work(priv->wq, &priv->tx_work);
 
        return NETDEV_TX_OK;
@@ -678,7 +692,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");
@@ -756,10 +770,13 @@ 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 */
@@ -767,13 +784,20 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
                                           0x00);
                }
 
-               if (intf & CANINTF_RX1IF)
+               /* receive buffer 1 */
+               if (intf & CANINTF_RX1IF) {
                        mcp251x_hw_rx(spi, 1);
+                       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) {
@@ -818,10 +842,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;
                        }
@@ -923,12 +951,16 @@ 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) {
@@ -1118,6 +1150,15 @@ 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 */ },
+       { "mcp2510",    CAN_MCP251X_MCP2510 },
+       { "mcp2515",    CAN_MCP251X_MCP2515 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
+
 static struct spi_driver mcp251x_can_driver = {
        .driver = {
                .name = DEVICE_NAME,
@@ -1125,6 +1166,7 @@ static struct spi_driver mcp251x_can_driver = {
                .owner = THIS_MODULE,
        },
 
+       .id_table = mcp251x_id_table,
        .probe = mcp251x_can_probe,
        .remove = __devexit_p(mcp251x_can_remove),
        .suspend = mcp251x_can_suspend,