can: c_can: Add support for Bosch D_CAN controller

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>
This commit is contained in:
AnilKumar Ch 2012-05-29 11:13:16 +05:30 committed by Marc Kleine-Budde
parent 33f8100977
commit 69927fccd9
3 changed files with 94 additions and 19 deletions

View 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

View 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 */

View 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);