can: c_can: Add support for Bosch D_CAN controller
authorAnilKumar Ch <anilkumar@ti.com>
Tue, 29 May 2012 05:43:16 +0000 (11:13 +0530)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Thu, 7 Jun 2012 08:02:27 +0000 (10:02 +0200)
This patch adds the support for D_CAN controller driver to the existing
C_CAN driver.

Bosch D_CAN controller is a full-CAN implementation which is compliant
to CAN protocol version 2.0 part A and B. Bosch D_CAN user manual can be
obtained from: http://www.semiconductors.bosch.de/media/en/pdf/
ipmodules_1/can/d_can_users_manual_111.pdf

A new array is added for accessing the d_can registers, according to d_can
controller register space.

Current D_CAN implementation has following limitations, this is done
to avoid large changes to the C_CAN driver.
1. Message objects are limited to 32, 16 for RX and 16 for TX. C_CAN IP
   supports upto 32 message objects but in case of D_CAN we can configure
   upto 128 message objects.
2. Using two 16bit reads/writes for accessing the 32bit D_CAN registers.
3. These patches have been tested on little endian machine, there might
   be some hidden endian-related issues due to the nature of the accesses
   (32-bit registers accessed as 2 16-bit registers). However, I do not
   have a big-endian D_CAN implementation to confirm.

Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/c_can/Kconfig
drivers/net/can/c_can/c_can.h
drivers/net/can/c_can/c_can_platform.c

index ffb9773..25d371c 100644 (file)
@@ -1,15 +1,16 @@
 menuconfig CAN_C_CAN
-       tristate "Bosch C_CAN devices"
+       tristate "Bosch C_CAN/D_CAN devices"
        depends on CAN_DEV && HAS_IOMEM
 
 if CAN_C_CAN
 
 config CAN_C_CAN_PLATFORM
-       tristate "Generic Platform Bus based C_CAN driver"
+       tristate "Generic Platform Bus based C_CAN/D_CAN driver"
        ---help---
-         This driver adds support for the C_CAN chips connected to
-         the "platform bus" (Linux abstraction for directly to the
+         This driver adds support for the C_CAN/D_CAN chips connected
+         to the "platform bus" (Linux abstraction for directly to the
          processor attached devices) which can be found on various
-         boards from ST Microelectronics (http://www.st.com)
-         like the SPEAr1310 and SPEAr320 evaluation boards.
+         boards from ST Microelectronics (http://www.st.com) like the
+         SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
+         boards like am335x, dm814x, dm813x and dm811x.
 endif
index d1e141e..01a7049 100644 (file)
@@ -102,6 +102,51 @@ static const u16 reg_map_c_can[] = {
        [C_CAN_MSGVAL2_REG]     = 0xB2,
 };
 
+static const u16 reg_map_d_can[] = {
+       [C_CAN_CTRL_REG]        = 0x00,
+       [C_CAN_STS_REG]         = 0x04,
+       [C_CAN_ERR_CNT_REG]     = 0x08,
+       [C_CAN_BTR_REG]         = 0x0C,
+       [C_CAN_BRPEXT_REG]      = 0x0E,
+       [C_CAN_INT_REG]         = 0x10,
+       [C_CAN_TEST_REG]        = 0x14,
+       [C_CAN_TXRQST1_REG]     = 0x88,
+       [C_CAN_TXRQST2_REG]     = 0x8A,
+       [C_CAN_NEWDAT1_REG]     = 0x9C,
+       [C_CAN_NEWDAT2_REG]     = 0x9E,
+       [C_CAN_INTPND1_REG]     = 0xB0,
+       [C_CAN_INTPND2_REG]     = 0xB2,
+       [C_CAN_MSGVAL1_REG]     = 0xC4,
+       [C_CAN_MSGVAL2_REG]     = 0xC6,
+       [C_CAN_IF1_COMREQ_REG]  = 0x100,
+       [C_CAN_IF1_COMMSK_REG]  = 0x102,
+       [C_CAN_IF1_MASK1_REG]   = 0x104,
+       [C_CAN_IF1_MASK2_REG]   = 0x106,
+       [C_CAN_IF1_ARB1_REG]    = 0x108,
+       [C_CAN_IF1_ARB2_REG]    = 0x10A,
+       [C_CAN_IF1_MSGCTRL_REG] = 0x10C,
+       [C_CAN_IF1_DATA1_REG]   = 0x110,
+       [C_CAN_IF1_DATA2_REG]   = 0x112,
+       [C_CAN_IF1_DATA3_REG]   = 0x114,
+       [C_CAN_IF1_DATA4_REG]   = 0x116,
+       [C_CAN_IF2_COMREQ_REG]  = 0x120,
+       [C_CAN_IF2_COMMSK_REG]  = 0x122,
+       [C_CAN_IF2_MASK1_REG]   = 0x124,
+       [C_CAN_IF2_MASK2_REG]   = 0x126,
+       [C_CAN_IF2_ARB1_REG]    = 0x128,
+       [C_CAN_IF2_ARB2_REG]    = 0x12A,
+       [C_CAN_IF2_MSGCTRL_REG] = 0x12C,
+       [C_CAN_IF2_DATA1_REG]   = 0x130,
+       [C_CAN_IF2_DATA2_REG]   = 0x132,
+       [C_CAN_IF2_DATA3_REG]   = 0x134,
+       [C_CAN_IF2_DATA4_REG]   = 0x136,
+};
+
+enum c_can_dev_id {
+       C_CAN_DEVTYPE,
+       D_CAN_DEVTYPE,
+};
+
 /* c_can private data structure */
 struct c_can_priv {
        struct can_priv can;    /* must be the first member */
index a6e9b93..f0921d1 100644 (file)
@@ -71,6 +71,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
        void __iomem *addr;
        struct net_device *dev;
        struct c_can_priv *priv;
+       const struct platform_device_id *id;
        struct resource *mem;
        int irq;
 #ifdef CONFIG_HAVE_CLK
@@ -115,7 +116,32 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
        }
 
        priv = netdev_priv(dev);
-       priv->regs = reg_map_c_can;
+       id = platform_get_device_id(pdev);
+       switch (id->driver_data) {
+       case C_CAN_DEVTYPE:
+               priv->regs = reg_map_c_can;
+               switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+               case IORESOURCE_MEM_32BIT:
+                       priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
+                       priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
+                       break;
+               case IORESOURCE_MEM_16BIT:
+               default:
+                       priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+                       priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+                       break;
+               }
+               break;
+       case D_CAN_DEVTYPE:
+               priv->regs = reg_map_d_can;
+               priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+               priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+               priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+               break;
+       default:
+               ret = -EINVAL;
+               goto exit_free_device;
+       }
 
        dev->irq = irq;
        priv->base = addr;
@@ -124,18 +150,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
        priv->priv = clk;
 #endif
 
-       switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
-       case IORESOURCE_MEM_32BIT:
-               priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
-               priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
-               break;
-       case IORESOURCE_MEM_16BIT:
-       default:
-               priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
-               priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
-               break;
-       }
-
        platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -189,6 +203,20 @@ static int __devexit c_can_plat_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id c_can_id_table[] = {
+       {
+               .name = KBUILD_MODNAME,
+               .driver_data = C_CAN_DEVTYPE,
+       }, {
+               .name = "c_can",
+               .driver_data = C_CAN_DEVTYPE,
+       }, {
+               .name = "d_can",
+               .driver_data = D_CAN_DEVTYPE,
+       }, {
+       }
+};
+
 static struct platform_driver c_can_plat_driver = {
        .driver = {
                .name = KBUILD_MODNAME,
@@ -196,6 +224,7 @@ static struct platform_driver c_can_plat_driver = {
        },
        .probe = c_can_plat_probe,
        .remove = __devexit_p(c_can_plat_remove),
+       .id_table = c_can_id_table,
 };
 
 module_platform_driver(c_can_plat_driver);