1
0
Fork 0

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>
hifive-unleashed-5.1
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 menuconfig CAN_C_CAN
tristate "Bosch C_CAN devices" tristate "Bosch C_CAN/D_CAN devices"
depends on CAN_DEV && HAS_IOMEM depends on CAN_DEV && HAS_IOMEM
if CAN_C_CAN if CAN_C_CAN
config CAN_C_CAN_PLATFORM config CAN_C_CAN_PLATFORM
tristate "Generic Platform Bus based C_CAN driver" tristate "Generic Platform Bus based C_CAN/D_CAN driver"
---help--- ---help---
This driver adds support for the C_CAN chips connected to This driver adds support for the C_CAN/D_CAN chips connected
the "platform bus" (Linux abstraction for directly to the to the "platform bus" (Linux abstraction for directly to the
processor attached devices) which can be found on various processor attached devices) which can be found on various
boards from ST Microelectronics (http://www.st.com) boards from ST Microelectronics (http://www.st.com) like the
like the SPEAr1310 and SPEAr320 evaluation boards. SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
boards like am335x, dm814x, dm813x and dm811x.
endif endif

View File

@ -102,6 +102,51 @@ static const u16 reg_map_c_can[] = {
[C_CAN_MSGVAL2_REG] = 0xB2, [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 */ /* c_can private data structure */
struct c_can_priv { struct c_can_priv {
struct can_priv can; /* must be the first member */ 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; void __iomem *addr;
struct net_device *dev; struct net_device *dev;
struct c_can_priv *priv; struct c_can_priv *priv;
const struct platform_device_id *id;
struct resource *mem; struct resource *mem;
int irq; int irq;
#ifdef CONFIG_HAVE_CLK #ifdef CONFIG_HAVE_CLK
@ -115,7 +116,32 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
} }
priv = netdev_priv(dev); 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; dev->irq = irq;
priv->base = addr; priv->base = addr;
@ -124,18 +150,6 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
priv->priv = clk; priv->priv = clk;
#endif #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); platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &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; 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 = { static struct platform_driver c_can_plat_driver = {
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
@ -196,6 +224,7 @@ static struct platform_driver c_can_plat_driver = {
}, },
.probe = c_can_plat_probe, .probe = c_can_plat_probe,
.remove = __devexit_p(c_can_plat_remove), .remove = __devexit_p(c_can_plat_remove),
.id_table = c_can_id_table,
}; };
module_platform_driver(c_can_plat_driver); module_platform_driver(c_can_plat_driver);