Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69927fcc authored by AnilKumar Ch's avatar AnilKumar Ch Committed by Marc Kleine-Budde
Browse files

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: default avatarAnilKumar Ch <anilkumar@ti.com>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 33f81009
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
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
+45 −0
Original line number Diff line number Diff line
@@ -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 */
+42 −13
Original line number Diff line number Diff line
@@ -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,15 +116,10 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
	}

	priv = netdev_priv(dev);
	id = platform_get_device_id(pdev);
	switch (id->driver_data) {
	case C_CAN_DEVTYPE:
		priv->regs = reg_map_c_can;

	dev->irq = irq;
	priv->base = addr;
#ifdef CONFIG_HAVE_CLK
	priv->can.clock.freq = clk_get_rate(clk);
	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;
@@ -135,6 +131,24 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
			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;
#ifdef CONFIG_HAVE_CLK
	priv->can.clock.freq = clk_get_rate(clk);
	priv->priv = clk;
#endif

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