From 7fedac525f38a0b47d27d959d1325945d188d787 Mon Sep 17 00:00:00 2001
From: Anil Kumar Ch <anilkumar@ti.com>
Date: Sun, 6 Nov 2011 13:56:35 +0530
Subject: [PATCH 1/7] can: d_can: Added support for Bosch D_CAN controller

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

This patch adds the support for this controller.
The following are the design choices made while writing the controller
driver:
1. Interface Register set IF1 has be used for transmit and IF2 is used for
   receive message objects.
2. Out of the total Message objects available, half of it are kept aside for RX
   purposes and the rest for TX purposes.
3. NAPI implementation is such that both the TX and RX paths functions
   in polling mode.

This patch adds the dcan driver support to am335x chip.

Signed-off-by: Anil Kumar Ch <anilkumar@ti.com>
---
 drivers/net/can/Kconfig                |    2 +
 drivers/net/can/Makefile               |    1 +
 drivers/net/can/d_can/Kconfig          |   14 +
 drivers/net/can/d_can/Makefile         |    8 +
 drivers/net/can/d_can/d_can.c          | 1336 ++++++++++++++++++++++++++++++++
 drivers/net/can/d_can/d_can.h          |   67 ++
 drivers/net/can/d_can/d_can_platform.c |  256 ++++++
 include/linux/can/platform/d_can.h     |   53 ++
 8 files changed, 1737 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/d_can/Kconfig
 create mode 100644 drivers/net/can/d_can/Makefile
 create mode 100644 drivers/net/can/d_can/d_can.c
 create mode 100644 drivers/net/can/d_can/d_can.h
 create mode 100644 drivers/net/can/d_can/d_can_platform.c
 create mode 100644 include/linux/can/platform/d_can.h

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index f6c98fb..6851445 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -116,6 +116,8 @@ source "drivers/net/can/sja1000/Kconfig"
 
 source "drivers/net/can/c_can/Kconfig"
 
+source "drivers/net/can/d_can/Kconfig"
+
 source "drivers/net/can/usb/Kconfig"
 
 source "drivers/net/can/softing/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 24ebfe8..3377679 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -14,6 +14,7 @@ obj-y				+= softing/
 obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
 obj-$(CONFIG_CAN_MSCAN)		+= mscan/
 obj-$(CONFIG_CAN_C_CAN)		+= c_can/
+obj-$(CONFIG_CAN_D_CAN)		+= d_can/
 obj-$(CONFIG_CAN_AT91)		+= at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
diff --git a/drivers/net/can/d_can/Kconfig b/drivers/net/can/d_can/Kconfig
new file mode 100644
index 0000000..e5e9dcf
--- /dev/null
+++ b/drivers/net/can/d_can/Kconfig
@@ -0,0 +1,14 @@
+menuconfig CAN_D_CAN
+	tristate "Bosch D_CAN devices"
+	depends on CAN_DEV && HAS_IOMEM
+
+if CAN_D_CAN
+
+config CAN_D_CAN_PLATFORM
+	tristate "Generic Platform Bus based D_CAN driver"
+	---help---
+	  This driver adds support for the D_CAN chips connected to
+	  the "platform bus" (Linux abstraction for directly to the
+	  processor attached devices) which can be found on am335x
+	  and dm814x boards from TI (http://www.ti.com).
+endif
diff --git a/drivers/net/can/d_can/Makefile b/drivers/net/can/d_can/Makefile
new file mode 100644
index 0000000..80560c5
--- /dev/null
+++ b/drivers/net/can/d_can/Makefile
@@ -0,0 +1,8 @@
+#
+#  Makefile for the Bosch D_CAN controller drivers.
+#
+
+obj-$(CONFIG_CAN_D_CAN) += d_can.o
+obj-$(CONFIG_CAN_D_CAN_PLATFORM) += d_can_platform.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/d_can/d_can.c b/drivers/net/can/d_can/d_can.c
new file mode 100644
index 0000000..e001db0
--- /dev/null
+++ b/drivers/net/can/d_can/d_can.c
@@ -0,0 +1,1336 @@
+/*
+ * CAN bus driver for Bosch D_CAN controller
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/
+ * Anil Kumar Ch <anilkumar@ti.com>
+ *
+ * Base taken from C_CAN driver
+ * Copyright (C) 2010 ST Microelectronics
+ * - Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch D_CAN controller 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
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/io.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "d_can.h"
+
+/* TI D_CAN module registers */
+#define D_CAN_CTL		0x0	/* CAN control register */
+#define D_CAN_ES		0x4	/* Error and status */
+#define D_CAN_PEEOI_REG		0x4	/* Parity error EOI */
+#define D_CAN_ERRC		0x8	/* Error counter */
+#define D_CAN_BTR		0xC	/* Bit timing */
+#define D_CAN_INT		0x10	/* Interrupt register */
+#define D_CAN_TEST		0x14	/* Test register */
+#define D_CAN_PERR		0x1C	/* Parity Error Code */
+#define D_CAN_ABOTR		0x80	/* Auto-Bus-On Time */
+#define D_CAN_TXRQ_X		0x84	/* Transmission Request X */
+#define D_CAN_TXRQ(n)		(0x88 + (n * 4)) /* Transmission request */
+#define D_CAN_NWDAT_X		0x98	/* New data X register */
+#define D_CAN_NWDAT(n)		(0x9C + (n * 4)) /* New data */
+#define D_CAN_INTPND_X		0xAC	/* Interrupt Pending X */
+#define D_CAN_INTPND(n)		(0xB0 + (n * 4)) /* Interrupt Pending */
+#define D_CAN_MSGVAL_X		0xC0		/* Message Valid X */
+#define D_CAN_MSGVAL(n)		(0xC4 + (n * 4)) /* Message Valid */
+#define D_CAN_INTMUX(n)		(0xD8 + (n * 4)) /* Interrupt Multiplexer */
+#define D_CAN_IFCMD(n)		(0x100 + (n * 0x20)) /* Command */
+#define D_CAN_IFMSK(n)		(0x104 + (n * 0x20)) /* Mask */
+#define D_CAN_IFARB(n)		(0x108 + (n * 0x20)) /* Arbitration */
+#define D_CAN_IFMCTL(n)		(0x10c + (n * 0x20)) /* Message ctl */
+#define D_CAN_IFDATA(n)		(0x110 + (n * 0x20)) /* DATA A */
+#define D_CAN_IFDATB(n)		(0x114 + (n * 0x20)) /* DATA B */
+#define D_CAN_IF3OBS		0x140	/* IF3 Observation */
+#define D_CAN_IF3UPD(n)		(0x160 + (n * 4)) /* Update enable */
+#define D_CAN_TIOC		0x1E0	/* CAN TX IO Control */
+#define D_CAN_RIOC		0x1E4	/* CAN RX IO Control */
+
+/* Control register Bit fields */
+#define D_CAN_CTL_WUBA		BIT(26)	/* Automatic wake-up on bus activity */
+#define D_CAN_CTL_PDR		BIT(24)	/* Request for local low power mode */
+#define D_CAN_CTL_DE3		BIT(20)	/* Enable DMA request line for IF3 */
+#define D_CAN_CTL_DE2		BIT(19)	/* Enable DMA request line for IF2 */
+#define D_CAN_CTL_DE1		BIT(18)	/* Enable DMA request line for IF1 */
+#define D_CAN_CTL_IE1		BIT(17)	/* Interrupt line 1 enable */
+#define D_CAN_CTL_INITDBG	BIT(16)	/* Init state for debug access */
+#define D_CAN_CTL_SWR		BIT(15)	/* S/W reset enable */
+#define D_CAN_CTL_PMD		(0xF << 10)	/* Parity on/off */
+#define D_CAN_CTL_ABO		BIT(9)	/* Auto bus on enable */
+#define D_CAN_CTL_IDS		BIT(8)	/* Interruption debug support enable */
+#define D_CAN_CTL_TEST		BIT(7)	/* Test mode enable */
+#define D_CAN_CTL_CCE		BIT(6)	/* Configuration change enable */
+#define D_CAN_CTL_DISABLE_AR	BIT(5)	/* Disable automatic retransmission */
+#define D_CAN_CTL_ENABLE_AR	(0 << 5)
+#define D_CAN_CTL_EIE		BIT(3)	/* Error interrupt enable */
+#define D_CAN_CTL_SIE		BIT(2)	/* Status change int enable */
+#define D_CAN_CTL_IE0		BIT(1)	/* Interrupt line 0 enable */
+#define D_CAN_CTL_INIT		BIT(0)	/* D_CAN initialization mode */
+
+/* D_CAN Error and Status and Parity Error EOI reg bit fields */
+#define D_CAN_ES_PDA		BIT(10)	/* Local power-down ACK */
+#define D_CAN_ES_WUP		BIT(9)	/* Wkae up pending */
+#define D_CAN_ES_PER		BIT(8)	/* Parity error detected */
+#define D_CAN_ES_BOFF		BIT(7)	/* Bus off state */
+#define D_CAN_ES_EWARN		BIT(6)	/* Warning state */
+#define D_CAN_ES_EPASS		BIT(5)	/* Error passive state */
+#define D_CAN_ES_RXOK		BIT(4)	/* Received a msg successfully */
+#define D_CAN_ES_TXOK		BIT(3)	/* Transmitted a msg successfully */
+#define D_CAN_ES_LEC_MASK	0x7	/* Last error code */
+
+/* Parity error reg bit fields */
+#define D_CAN_PEEOI		BIT(8)	/* EOI indication for parity error */
+
+/* Error counter reg bit fields */
+#define D_CAN_ERRC_RP_SHIFT	15
+#define D_CAN_ERRC_RP_MASK	BIT(15)		/* Receive error passive */
+#define D_CAN_ERRC_REC_SHIFT	8
+#define D_CAN_ERRC_REC_MASK	(0x7F << 8)	/* Receive err counter */
+#define D_CAN_ERRC_TEC_SHIFT	0
+#define D_CAN_ERRC_TEC_MASK	(0xFF << 0)	/* Transmit err counter */
+
+/* Bit timing reg bit fields */
+#define D_CAN_BTR_BRPE_SHIFT	16
+#define D_CAN_BTR_BRPE_MASK	(0xF << 16)	/* Baud rate prescaler ext */
+#define D_CAN_BTR_TSEG2_SHIFT	12
+#define D_CAN_BTR_TSEG2_MASK	(0x7 << 12)	/* Time seg after smpl point */
+#define D_CAN_BTR_TSEG1_SHIFT	8
+#define D_CAN_BTR_TSEG1_MASK	(0xF << 8)	/* Time seg before smpl point */
+#define D_CAN_BTR_SJW_SHIFT	6
+#define D_CAN_BTR_SJW_MASK	(0x3 << 6)	/* Syncronization jump width */
+#define D_CAN_BTR_BRP_SHIFT	0
+#define D_CAN_BTR_BRP_MASK	(0x3F << 0)	/* Baud rate prescaler */
+
+/* D_CAN Test register bit fields */
+#define D_CAN_TEST_RDA		BIT(9)	/* RAM direct access enable */
+#define D_CAN_TEST_EXL		BIT(8)	/* External loopback mode */
+#define D_CAN_TEST_RX		BIT(7)	/* Monitors the reveive pin */
+#define D_CAN_TEST_TX		(0x3 << 5)	/* Control of CAN_TX pin */
+#define D_CAN_TEST_LBACK	BIT(4)	/* Loopback mode */
+#define D_CAN_TEST_SILENT	BIT(3)	/* Silent mdoe */
+
+/* D_CAN Parity error reg bit fields */
+#define D_CAN_PERR_WN_MASK	(0x7 << 8)	/* Parity error word nuber */
+#define D_CAN_PERR_MN_MASK	0xFF		/* Parity error msg object */
+
+/* D_CAN X registers bit fields */
+#define D_CAN_BIT_FIELD(n)	(0x3 << (2 * n)) /* X reg's bit field 1 mask */
+
+/* D_CAN IF command reg bit fields */
+#define D_CAN_IF_CMD_WR		BIT(23)	/* Write/read */
+#define D_CAN_IF_CMD_MASK	BIT(22)	/* Access mask bits */
+#define D_CAN_IF_CMD_ARB	BIT(21)	/* Access arbitration bits */
+#define D_CAN_IF_CMD_CONTROL	BIT(20)	/* Acess control bits */
+#define D_CAN_IF_CMD_CIP	BIT(19)	/* Clear int pending */
+#define D_CAN_IF_CMD_TXRQST	BIT(18)	/* Access transmission request */
+#define D_CAN_IF_CMD_DATAA	BIT(17)	/* Access Data Bytes 0-3 */
+#define D_CAN_IF_CMD_DATAB	BIT(16)	/* Access Data Bytes 4-7 */
+#define D_CAN_IF_CMD_BUSY	BIT(15)	/* Busy flag */
+#define D_CAN_IF_CMD_DAM	BIT(14)	/* Activation of DMA */
+#define D_CAN_IF_CMD_MN_MASK	0xFF	/* No. of msg's used for DMA T/F */
+#define D_CAN_IF_CMD_ALL	(D_CAN_IF_CMD_MASK | D_CAN_IF_CMD_ARB | \
+				D_CAN_IF_CMD_CONTROL | D_CAN_IF_CMD_TXRQST | \
+				D_CAN_IF_CMD_DATAA | D_CAN_IF_CMD_DATAB)
+
+/* D_CAN IF mask reg bit fields */
+#define D_CAN_IF_MASK_MX	BIT(31)	/* Mask Extended Identifier */
+#define D_CAN_IF_MASK_MD	BIT(30)	/* Mask Message direction */
+
+/* D_CAN IF Arbitration */
+#define D_CAN_IF_ARB_MSGVAL	BIT(31)	/* Message Vaild */
+#define D_CAN_IF_ARB_MSGXTD	BIT(30)	/* Extended Identifier 0-11 1-29 */
+#define D_CAN_IF_ARB_DIR_XMIT	BIT(29) /* Message direction 0-R 1-T */
+
+/* D_CAN IF Message control */
+#define D_CAN_IF_MCTL_NEWDAT	BIT(15)	/* New data available */
+#define D_CAN_IF_MCTL_MSGLST	BIT(14)	/* Message lost, only for receive */
+#define D_CAN_IF_MCTL_CLR_MSGLST (0 << 14)
+#define D_CAN_IF_MCTL_INTPND	BIT(13)	/* Interrupt pending */
+#define D_CAN_IF_MCTL_UMASK	BIT(12)	/* Use acceptance mask */
+#define D_CAN_IF_MCTL_TXIE	BIT(11)	/* Transmit int enable */
+#define D_CAN_IF_MCTL_RXIE	BIT(10)	/* Receive int enable */
+#define D_CAN_IF_MCTL_RMTEN	BIT(9)	/* Remote enable */
+#define D_CAN_IF_MCTL_TXRQST	BIT(8)	/* Transmit request */
+#define D_CAN_IF_MCTL_EOB	BIT(7)	/* Data frames */
+#define D_CAN_IF_MCTL_DLC_MASK	0xF	/* Data length code */
+
+/* D_CAN IF3 Observation reg bit fields */
+#define D_CAN_IF3OBS_UP		BIT(15)	/* Update data status */
+#define D_CAN_IF3OBS_SDB	BIT(12)	/* DataB read out status */
+#define D_CAN_IF3OBS_SDA	BIT(11)	/* DataA read out status */
+#define D_CAN_IF3OBS_SC		BIT(10)	/* Contol bits read out status */
+#define D_CAN_IF3OBS_SA		BIT(9)	/* Arbitration read out status */
+#define D_CAN_IF3OBS_SM		BIT(8)	/* Mask bits read out status */
+#define D_CAN_IF3OBS_DB		BIT(4)	/* Data B read observation */
+#define D_CAN_IF3OBS_DA		BIT(3)	/* Data A read observation */
+#define D_CAN_IF3OBS_CTL	BIT(2)	/* Control read observation */
+#define D_CAN_IF3OBS_ARB	BIT(1)	/* Arbitration data read observation */
+#define D_CAN_IF3OBS_MASK	BIT(0)	/* Mask data read observation */
+
+/* D_CAN TX I/O reg bit fields */
+#define D_CAN_TIOC_PU		BIT(18)	/* CAN_TX pull up/down select */
+#define D_CAN_TIOC_PD		BIT(17)	/* CAN_TX pull disable */
+#define D_CAN_TIOC_OD		BIT(16)	/* CAN_TX open drain enable */
+#define D_CAN_TIOC_FUNC		BIT(3)	/* CAN_TX function */
+#define D_CAN_TIOC_DIR		BIT(2)	/* CAN_TX data direction */
+#define D_CAN_TIOC_OUT		BIT(1)	/* CAN_TX data out write */
+#define D_CAN_TIOC_IN		BIT(0)	/* CAN_TX data in */
+
+/* D_CAN RX I/O reg bit fields */
+#define D_CAN_RIOC_PU		BIT(18)	/* CAN_RX pull up/down select */
+#define D_CAN_RIOC_PD		BIT(17)	/* CAN_RX pull disable */
+#define D_CAN_RIOC_OD		BIT(16)	/* CAN_RX open drain enable */
+#define D_CAN_RIOC_FUNC		BIT(3)	/* CAN_RX function */
+#define D_CAN_RIOC_DIR		BIT(2)	/* CAN_RX data direction */
+#define D_CAN_RIOC_OUT		BIT(1)	/* CAN_RX data out write */
+#define D_CAN_RTIOC_IN		BIT(0)	/* CAN_RX data in */
+
+#define D_CAN_SET_REG		0xFFFFFFFF
+
+#define D_CAN_CANMID_IDE	BIT(31)	/* Extended frame format */
+#define D_CAN_CANMID_AME	BIT(30)	/* Acceptance mask enable */
+#define D_CAN_CANMID_AAM	BIT(29)	/* Auto answer mode */
+
+/*
+ * IF register masks:
+ */
+#define IFX_WRITE_IDR(x)		((x) & 0x1FFFFFFF)
+
+#define IFX_CMD_BITS(x)			((x) & 0xFFFFFF00)
+#define IFX_CMD_MSG_NUMBER(x)		((x) & 0xFF)
+
+/* message object split */
+#define D_CAN_NUM_OF_OBJECTS		64
+#define D_CAN_MSG_OBJ_RX_NUM		32
+#define D_CAN_MSG_OBJ_TX_NUM		32
+
+#define D_CAN_MSG_OBJ_RX_FIRST		1
+#define D_CAN_MSG_OBJ_RX_LAST		(D_CAN_MSG_OBJ_RX_FIRST + \
+					D_CAN_MSG_OBJ_RX_NUM - 1)
+
+#define D_CAN_MSG_OBJ_TX_FIRST		(D_CAN_MSG_OBJ_RX_LAST + 1)
+#define D_CAN_MSG_OBJ_TX_LAST		(D_CAN_MSG_OBJ_TX_FIRST + \
+					D_CAN_MSG_OBJ_TX_NUM - 1)
+
+#define D_CAN_MSG_OBJ_RX_SPLIT		17
+#define D_CAN_MSG_OBJ_RX_LOW_LAST	(D_CAN_MSG_OBJ_RX_SPLIT - 1)
+
+#define D_CAN_NEXT_MSG_OBJ_MASK		(D_CAN_MSG_OBJ_TX_NUM - 1)
+
+/* status interrupt */
+#define STATUS_INTERRUPT		0x8000
+
+/* global interrupt masks */
+#define ENABLE_ALL_INTERRUPTS		1
+#define DISABLE_ALL_INTERRUPTS		0
+
+/* minimum timeout for checking BUSY status */
+#define MIN_TIMEOUT_VALUE		6
+
+/* Wait for ~1 sec for INIT bit */
+#define D_CAN_WAIT_COUNT		100
+
+#define D_CAN_IF_RX_NUM			0
+#define D_CAN_IF_TX_NUM			1
+
+#define D_CAN_GET_XREG_NUM(priv, reg)	(__ffs(d_can_read(priv, reg))/4)
+
+/* CAN Bittiming constants as per D_CAN specs */
+static struct can_bittiming_const d_can_bittiming_const = {
+	.name = D_CAN_DRV_NAME,
+	.tseg1_min = 1,		/* Time segment 1 = prop_seg + phase_seg1 */
+	.tseg1_max = 16,
+	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 1024,	/* 6-bit BRP field + 4-bit BRPE field*/
+	.brp_inc = 1,
+};
+
+/* d_can lec values */
+enum d_can_lec_type {
+	LEC_NO_ERROR = 0,
+	LEC_STUFF_ERROR,
+	LEC_FORM_ERROR,
+	LEC_ACK_ERROR,
+	LEC_BIT1_ERROR,
+	LEC_BIT0_ERROR,
+	LEC_CRC_ERROR,
+	LEC_UNUSED,
+};
+
+/*
+ * d_can error types:
+ * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
+ */
+enum d_can_bus_error_types {
+	D_CAN_NO_ERROR = 0,
+	D_CAN_BUS_OFF,
+	D_CAN_ERROR_WARNING,
+	D_CAN_ERROR_PASSIVE,
+};
+
+static inline void d_can_write(struct d_can_priv *priv, u32 reg, u32 val)
+{
+	__raw_writel(val, priv->base + reg);
+}
+
+static inline u32 d_can_read(struct d_can_priv *priv, int reg)
+{
+	return __raw_readl(priv->base + reg);
+}
+
+static inline void d_can_set_bit(struct d_can_priv *priv, int reg,
+	u32 bit_mask)
+{
+	d_can_write(priv, reg, d_can_read(priv, reg) | bit_mask);
+}
+
+static inline u32 d_can_get_bit(struct d_can_priv *priv, int reg,
+	u32 bit_mask)
+{
+	return (d_can_read(priv, reg) & bit_mask) ? 1 : 0;
+}
+
+static inline void d_can_clear_bit(struct d_can_priv *priv, int reg,
+	u32 bit_mask)
+{
+	d_can_write(priv, reg, d_can_read(priv, reg) & ~bit_mask);
+}
+
+static inline int get_tx_next_msg_obj(const struct d_can_priv *priv)
+{
+	return (priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) +
+			D_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static inline int get_tx_echo_msg_obj(const struct d_can_priv *priv)
+{
+	return (priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK) +
+			D_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static void d_can_interrupts(struct d_can_priv *priv, int enable)
+{
+	unsigned int cntrl_save = d_can_read(priv, D_CAN_CTL);
+
+	if (enable)
+		cntrl_save |= (D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
+				D_CAN_CTL_IE0);
+	else
+		cntrl_save &= ~(D_CAN_CTL_IE1 | D_CAN_CTL_SIE |
+				D_CAN_CTL_EIE |	D_CAN_CTL_IE0);
+
+	d_can_write(priv, D_CAN_CTL, cntrl_save);
+}
+
+static inline int d_can_msg_obj_is_busy(struct d_can_priv *priv, int iface)
+{
+	int count = MIN_TIMEOUT_VALUE;
+
+	while (count && d_can_read(priv, D_CAN_IFCMD(iface)) &
+				D_CAN_IF_CMD_BUSY) {
+		count--;
+		udelay(1);
+	}
+
+	if (!count)
+		return 1;
+
+	return 0;
+}
+
+static inline void d_can_object_get(struct net_device *dev,
+					int iface, int objno, int mask)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	/*
+	 * As per specs, after writting the message object number in the
+	 * IF command register the transfer b/w interface register and
+	 * message RAM must be complete in 12 CAN-CLK period.
+	 */
+	d_can_write(priv, D_CAN_IFCMD(iface), IFX_CMD_BITS(mask) |
+					IFX_CMD_MSG_NUMBER(objno));
+
+	if (d_can_msg_obj_is_busy(priv, iface))
+		netdev_err(dev, "timed out in object get\n");
+}
+
+static inline void d_can_object_put(struct net_device *dev,
+					int iface, int objno, int mask)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	/*
+	 * As per specs, after writting the message object number in the
+	 * IF command request register the transfer b/w interface
+	 * register and message RAM must be complete in 12 CAN-CLK
+	 * period.
+	 */
+	d_can_write(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_WR |
+		IFX_CMD_BITS(mask) | IFX_CMD_MSG_NUMBER(objno));
+
+	if (d_can_msg_obj_is_busy(priv, iface))
+		netdev_err(dev, "timed out in object put\n");
+}
+
+static void d_can_write_msg_object(struct net_device *dev,
+			int iface, struct can_frame *frame, int objno)
+{
+	int i;
+	u32 flags = 0;
+	unsigned int id;
+	u32 dataA = 0;
+	u32 dataB = 0;
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	if (!(frame->can_id & CAN_RTR_FLAG))
+		flags |= D_CAN_IF_ARB_DIR_XMIT;
+
+	if (frame->can_id & CAN_EFF_FLAG) {
+		id = frame->can_id & CAN_EFF_MASK;
+		flags |= D_CAN_IF_ARB_MSGXTD;
+	} else
+		id = ((frame->can_id & CAN_SFF_MASK) << 18);
+
+	flags |= D_CAN_IF_ARB_MSGVAL;
+	d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags);
+
+	for (i = 0; i < frame->can_dlc; i++) {
+		if (i < 4)
+			dataA |= (frame->data[i] << (8 * i));
+		else
+			dataB |= (frame->data[i] << (8 * (i - 4)));
+	}
+
+	/* DATA write to Message object registers DATAA and DATAB */
+	if (frame->can_dlc < 4)
+		d_can_write(priv, D_CAN_IFDATA(iface), dataA);
+	else {
+		d_can_write(priv, D_CAN_IFDATB(iface), dataB);
+		d_can_write(priv, D_CAN_IFDATA(iface), dataA);
+	}
+
+	/* enable interrupt for this message object */
+	d_can_write(priv, D_CAN_IFMCTL(iface),
+			D_CAN_IF_MCTL_TXIE | D_CAN_IF_MCTL_EOB |
+			D_CAN_IF_MCTL_TXRQST | D_CAN_IF_MCTL_NEWDAT |
+			frame->can_dlc);
+
+	/* Put message data into message RAM */
+	d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL);
+}
+
+static inline void d_can_mark_rx_msg_obj(struct net_device *dev,
+						int iface, int ctrl_mask,
+						int obj)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	d_can_write(priv, D_CAN_IFMCTL(iface), ctrl_mask
+		& ~(D_CAN_IF_MCTL_MSGLST | D_CAN_IF_MCTL_INTPND));
+
+	d_can_object_put(dev, iface, obj, D_CAN_IF_CMD_CONTROL);
+}
+
+static inline void d_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
+						int iface,
+						int ctrl_mask)
+{
+	int i;
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_MSG_OBJ_RX_LOW_LAST; i++) {
+		d_can_write(priv, D_CAN_IFMCTL(iface),
+				ctrl_mask & ~(D_CAN_IF_MCTL_MSGLST |
+				D_CAN_IF_MCTL_INTPND | D_CAN_IF_MCTL_NEWDAT));
+		d_can_object_put(dev, iface, i, D_CAN_IF_CMD_CONTROL);
+	}
+}
+
+static inline void d_can_activate_rx_msg_obj(struct net_device *dev,
+						int iface, int ctrl_mask,
+						int obj)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	d_can_write(priv, D_CAN_IFMCTL(iface),
+			ctrl_mask & ~(D_CAN_IF_MCTL_MSGLST |
+			D_CAN_IF_MCTL_INTPND | D_CAN_IF_MCTL_NEWDAT));
+	d_can_object_put(dev, iface, obj, D_CAN_IF_CMD_CONTROL);
+}
+
+static void d_can_handle_lost_msg_obj(struct net_device *dev,
+					int iface, int objno)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct sk_buff *skb;
+	struct can_frame *frame;
+
+	netdev_err(dev, "msg lost in buffer %d\n", objno);
+
+	d_can_object_get(dev, iface, objno, D_CAN_IF_CMD_ALL &
+					~D_CAN_IF_CMD_TXRQST);
+
+	d_can_write(priv, D_CAN_IFMCTL(iface), D_CAN_IF_MCTL_CLR_MSGLST);
+
+	d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_CONTROL);
+
+	/* create an error msg */
+	skb = alloc_can_err_skb(dev, &frame);
+	if (unlikely(!skb))
+		return;
+
+	frame->can_id |= CAN_ERR_CRTL;
+	frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+	stats->rx_errors++;
+	stats->rx_over_errors++;
+
+	netif_receive_skb(skb);
+}
+
+static int d_can_read_msg_object(struct net_device *dev, int iface, int ctrl)
+{
+	int i;
+	u32 dataA = 0;
+	u32 dataB = 0;
+	unsigned int arb_val;
+	unsigned int mctl_val;
+	struct d_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct sk_buff *skb;
+	struct can_frame *frame;
+
+	skb = alloc_can_skb(dev, &frame);
+	if (!skb) {
+		stats->rx_dropped++;
+		return -ENOMEM;
+	}
+
+	frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+
+	arb_val = d_can_read(priv, D_CAN_IFARB(iface));
+	mctl_val = d_can_read(priv, D_CAN_IFMCTL(iface));
+
+	if (arb_val & D_CAN_IF_ARB_MSGXTD)
+		frame->can_id = (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+	else
+		frame->can_id = (arb_val >> 18) & CAN_SFF_MASK;
+
+	if (mctl_val & D_CAN_IF_MCTL_RMTEN)
+		frame->can_id |= CAN_RTR_FLAG;
+	else {
+		dataA = d_can_read(priv, D_CAN_IFDATA(iface));
+		dataB = d_can_read(priv, D_CAN_IFDATB(iface));
+		for (i = 0; i < frame->can_dlc; i++) {
+			/* Writing MO higher 4 data bytes to skb */
+			if (i <= 3)
+				frame->data[i] = dataA >> (8 * i); /* Lower */
+			if (i > 3)
+				frame->data[i] = dataB >> (8 * (i-4));
+		}
+	}
+
+	netif_receive_skb(skb);
+
+	stats->rx_packets++;
+	stats->rx_bytes += frame->can_dlc;
+
+	return 0;
+}
+
+static void d_can_setup_receive_object(struct net_device *dev, int iface,
+					int objno, unsigned int mask,
+					unsigned int id, unsigned int mcont)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	d_can_write(priv, D_CAN_IFMSK(iface), IFX_WRITE_IDR(mask));
+	d_can_write(priv, D_CAN_IFARB(iface), IFX_WRITE_IDR(id) |
+			D_CAN_IF_ARB_MSGVAL);
+	d_can_write(priv, D_CAN_IFMCTL(iface), mcont);
+
+	d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ALL &
+					~D_CAN_IF_CMD_TXRQST);
+
+	netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
+		D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
+}
+
+static void d_can_inval_msg_object(struct net_device *dev, int iface, int objno)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	d_can_write(priv, D_CAN_IFARB(iface), 0);
+	d_can_write(priv, D_CAN_IFMCTL(iface), 0);
+
+	d_can_object_put(dev, iface, objno, D_CAN_IF_CMD_ARB |
+					D_CAN_IF_CMD_CONTROL);
+
+	netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno, d_can_read(priv,
+		D_CAN_MSGVAL(D_CAN_GET_XREG_NUM(priv, D_CAN_MSGVAL_X))));
+}
+
+static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, int objno)
+{
+	u32 txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
+
+	/*
+	 * as transmission request register's bit n-1 corresponds to
+	 * message object n, we need to handle the same properly.
+	 */
+	if (d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val)) &
+			(1 << (objno - 1)))
+		return 1;
+
+	return 0;
+}
+
+static netdev_tx_t d_can_start_xmit(struct sk_buff *skb,
+					struct net_device *dev)
+{
+	u32 msg_obj_no;
+	struct d_can_priv *priv = netdev_priv(dev);
+	struct can_frame *frame = (struct can_frame *)skb->data;
+
+	if (can_dropped_invalid_skb(dev, skb))
+		return NETDEV_TX_OK;
+
+	msg_obj_no = get_tx_next_msg_obj(priv);
+
+	/* prepare message object for transmission */
+	d_can_write_msg_object(dev, D_CAN_IF_TX_NUM, frame, msg_obj_no);
+	can_put_echo_skb(skb, dev, msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
+
+	/*
+	 * we have to stop the queue in case of a wrap around or
+	 * if the next TX message object is still in use
+	 */
+	priv->tx_next++;
+	if (d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
+		(priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK)
+		== 0)
+		netif_stop_queue(dev);
+
+	return NETDEV_TX_OK;
+}
+
+static int d_can_set_bittiming(struct net_device *dev)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+	const struct can_bittiming *bt = &priv->can.bittiming;
+	u32 can_btc;
+
+	can_btc = ((bt->phase_seg2 - 1) & 0x7) << D_CAN_BTR_TSEG2_SHIFT;
+	can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1)
+			& 0xF) << D_CAN_BTR_TSEG1_SHIFT;
+
+	can_btc |= ((bt->sjw - 1) & 0x3) << D_CAN_BTR_SJW_SHIFT;
+
+	/* Ten bits contains the BRP, 6 bits for BRP and upper 4 bits for brpe*/
+	can_btc |= ((bt->brp - 1) & 0x3F) << D_CAN_BTR_BRP_SHIFT;
+	can_btc |= ((((bt->brp - 1) >> 6) & 0xF) << D_CAN_BTR_BRPE_SHIFT);
+
+	d_can_write(priv, D_CAN_BTR, can_btc);
+
+	netdev_info(dev, "setting CAN BT = %#x\n", can_btc);
+
+	return 0;
+}
+
+/*
+ * Configure D_CAN message objects for Tx and Rx purposes:
+ * D_CAN provides a total of 64 message objects that can be configured
+ * either for Tx or Rx purposes. In this driver first 32 message objects
+ * are used as a reception FIFO and the reception FIFO is signified by the
+ * EoB bit being SET. The remaining 32 message objects are kept aside for
+ * Tx purposes. See user guide document for further details on configuring
+ * message objects.
+ */
+static void d_can_configure_msg_objects(struct net_device *dev)
+{
+	unsigned int i;
+
+	/* first invalidate all message objects */
+	for (i = D_CAN_MSG_OBJ_RX_FIRST; i <= D_CAN_NUM_OF_OBJECTS; i++)
+		d_can_inval_msg_object(dev, D_CAN_IF_RX_NUM, i);
+
+	/* setup receive message objects */
+	for (i = D_CAN_MSG_OBJ_RX_FIRST; i < D_CAN_MSG_OBJ_RX_LAST; i++)
+		d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, i, 0, 0,
+			(D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK) &
+			~D_CAN_IF_MCTL_EOB);
+
+	/* Last object EoB bit should be 1 for terminate */
+	d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM, D_CAN_MSG_OBJ_RX_LAST,
+			0, 0, D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK |
+			D_CAN_IF_MCTL_EOB);
+}
+
+static void d_can_test_mode(struct net_device *dev)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	/* Test mode is enabled in this step & the specific TEST bits
+	 * are enabled accordingly */
+	d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE |
+			D_CAN_CTL_IE1 |	D_CAN_CTL_IE0 | D_CAN_CTL_TEST);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+		/* silent mode : bus-monitoring mode */
+		d_can_write(priv, D_CAN_TEST, D_CAN_TEST_SILENT);
+	} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+		/* loopback mode : useful for self-test function */
+		d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK);
+	} else {
+		/* loopback + silent mode : useful for hot self-test */
+		d_can_write(priv, D_CAN_TEST, D_CAN_TEST_LBACK |
+				D_CAN_TEST_SILENT);
+	}
+}
+
+/*
+ * Configure D_CAN chip:
+ * - enable/disable auto-retransmission
+ * - set operating mode
+ * - configure message objects
+ */
+static void d_can_init(struct net_device *dev)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+	u32 cnt;
+
+	netdev_dbg(dev, "resetting d_can ...\n");
+	d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_SWR);
+
+	/* Enter initialization mode by setting the Init bit */
+	d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
+
+	/* enable automatic retransmission */
+	d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_ENABLE_AR);
+
+	/* Set the Configure Change Enable ( CCE) bit */
+	d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_CCE);
+
+	/* Wait for the Init bit to get set */
+	cnt = D_CAN_WAIT_COUNT;
+	while (!d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) && cnt != 0) {
+		--cnt;
+		udelay(10);
+	}
+
+	/* set bittiming params */
+	d_can_set_bittiming(dev);
+
+	d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT | D_CAN_CTL_CCE);
+
+	/* Wait for the Init bit to get clear */
+	cnt = D_CAN_WAIT_COUNT;
+	while (d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) && cnt != 0) {
+		--cnt;
+		udelay(10);
+	}
+
+	if (!priv->test_mode) {
+		/* normal mode*/
+		d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | D_CAN_CTL_IE1 |
+							D_CAN_CTL_IE0);
+	} else
+		d_can_test_mode(dev);
+
+	/* Enable TX and RX I/O Control pins */
+	d_can_write(priv, D_CAN_TIOC, D_CAN_TIOC_FUNC);
+	d_can_write(priv, D_CAN_RIOC, D_CAN_RIOC_FUNC);
+
+	/* configure message objects */
+	d_can_configure_msg_objects(dev);
+
+	/* set a `lec` value so that we can check for updates later */
+	d_can_write(priv, D_CAN_ES, LEC_UNUSED);
+}
+
+static void d_can_start(struct net_device *dev)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	/* basic d_can initialization */
+	d_can_init(dev);
+
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	/* reset tx helper pointers */
+	priv->tx_next = priv->tx_echo = 0;
+
+	/* enable status change, error and module interrupts */
+	d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+}
+
+static void d_can_stop(struct net_device *dev)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	/* disable all interrupts */
+	d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+	/* set the state as STOPPED */
+	priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int d_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+	switch (mode) {
+	case CAN_MODE_START:
+		d_can_start(dev);
+		netif_wake_queue(dev);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int d_can_get_berr_counter(const struct net_device *dev,
+					struct can_berr_counter *bec)
+{
+	unsigned int reg_err_counter;
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	reg_err_counter = d_can_read(priv, D_CAN_ERRC);
+	bec->rxerr = (reg_err_counter & D_CAN_ERRC_REC_MASK) >>
+				D_CAN_ERRC_REC_SHIFT;
+	bec->txerr = reg_err_counter & D_CAN_ERRC_TEC_MASK;
+
+	return 0;
+}
+
+/*
+ * theory of operation:
+ *
+ * priv->tx_echo holds the number of the oldest can_frame put for
+ * transmission into the hardware, but not yet ACKed by the CAN tx
+ * complete IRQ.
+ *
+ * We iterate from priv->tx_echo to priv->tx_next and check if the
+ * packet has been transmitted, echo it back to the CAN framework.
+ * If we discover a not yet transmitted package, stop looking for more.
+ */
+static void d_can_do_tx(struct net_device *dev)
+{
+	u32 msg_obj_no;
+	struct d_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	u32 txrq_x_reg_val;
+	u32 txrq_reg_val;
+
+	for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+		msg_obj_no = get_tx_echo_msg_obj(priv);
+		txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
+		txrq_reg_val = d_can_read(priv, D_CAN_TXRQ(txrq_x_reg_val));
+		if (!(txrq_reg_val & (1 << (msg_obj_no - 1)))) {
+			can_get_echo_skb(dev,
+					msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
+			stats->tx_bytes += d_can_read(priv,
+					D_CAN_IFMCTL(D_CAN_IF_TX_NUM))
+					& D_CAN_IF_MCTL_DLC_MASK;
+			stats->tx_packets++;
+			d_can_inval_msg_object(dev, D_CAN_IF_TX_NUM,
+					msg_obj_no);
+		} else
+			break;
+	}
+
+	/* restart queue if wrap-up or if queue stalled on last pkt */
+	if (((priv->tx_next & D_CAN_NEXT_MSG_OBJ_MASK) != 0)
+		|| ((priv->tx_echo & D_CAN_NEXT_MSG_OBJ_MASK)
+		== 0))
+		netif_wake_queue(dev);
+}
+
+/*
+ * theory of operation:
+ *
+ * d_can core saves a received CAN message into the first free message
+ * object it finds free (starting with the lowest). Bits NEWDAT and
+ * INTPND are set for this message object indicating that a new message
+ * has arrived. To work-around this issue, we keep two groups of message
+ * objects whose partitioning is defined by D_CAN_MSG_OBJ_RX_SPLIT.
+ *
+ * To ensure in-order frame reception we use the following
+ * approach while re-activating a message object to receive further
+ * frames:
+ * - if the current message object number is lower than
+ *   D_CAN_MSG_RX_LOW_LAST, do not clear the NEWDAT bit while clearing
+ *   the INTPND bit.
+ * - if the current message object number is equal to
+ *   D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of all lower
+ *   receive message objects.
+ * - if the current message object number is greater than
+ *   D_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
+ *   only this message object.
+ */
+static int d_can_do_rx_poll(struct net_device *dev, int quota)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+	unsigned int msg_obj, mctrl_reg_val;
+	u32 num_rx_pkts = 0;
+	u32 intpnd_x_reg_val;
+	u32 intpnd_reg_val;
+
+	for (msg_obj = D_CAN_MSG_OBJ_RX_FIRST; msg_obj <= D_CAN_MSG_OBJ_RX_LAST
+				&& quota > 0; msg_obj++) {
+
+		intpnd_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X);
+		intpnd_reg_val = d_can_read(priv,
+					D_CAN_INTPND(intpnd_x_reg_val));
+
+		/*
+		 * as interrupt pending register's bit n-1 corresponds to
+		 * message object n, we need to handle the same properly.
+		 */
+		if (intpnd_reg_val & (1 << (msg_obj - 1))) {
+
+			d_can_object_get(dev, D_CAN_IF_RX_NUM, msg_obj,
+					D_CAN_IF_CMD_ALL &
+					~D_CAN_IF_CMD_TXRQST);
+
+			mctrl_reg_val = d_can_read(priv,
+					D_CAN_IFMCTL(D_CAN_IF_RX_NUM));
+
+			if (!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT))
+				continue;
+
+			/* read the data from the message object */
+			d_can_read_msg_object(dev, D_CAN_IF_RX_NUM,
+						mctrl_reg_val);
+
+			if (mctrl_reg_val & D_CAN_IF_MCTL_EOB)
+				d_can_setup_receive_object(dev, D_CAN_IF_RX_NUM,
+					D_CAN_MSG_OBJ_RX_LAST, 0, 0,
+					D_CAN_IF_MCTL_RXIE | D_CAN_IF_MCTL_UMASK
+					| D_CAN_IF_MCTL_EOB);
+
+			if (mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) {
+				d_can_handle_lost_msg_obj(dev, D_CAN_IF_RX_NUM,
+					msg_obj);
+				num_rx_pkts++;
+				quota--;
+				continue;
+			}
+
+			if (msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST)
+				d_can_mark_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
+						mctrl_reg_val, msg_obj);
+			else if (msg_obj > D_CAN_MSG_OBJ_RX_LOW_LAST)
+				/* activate this msg obj */
+				d_can_activate_rx_msg_obj(dev, D_CAN_IF_RX_NUM,
+						mctrl_reg_val, msg_obj);
+			else if (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST)
+				/* activate all lower message objects */
+				d_can_activate_all_lower_rx_msg_obj(dev,
+						D_CAN_IF_RX_NUM, mctrl_reg_val);
+
+			num_rx_pkts++;
+			quota--;
+		}
+	}
+
+	return num_rx_pkts;
+}
+
+static inline int d_can_has_and_handle_berr(struct d_can_priv *priv)
+{
+	return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+		(priv->current_status & LEC_UNUSED);
+}
+
+static int d_can_handle_state_change(struct net_device *dev,
+				enum d_can_bus_error_types error_type)
+{
+	unsigned int reg_err_counter;
+	unsigned int rx_err_passive;
+	struct d_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct can_berr_counter bec;
+
+	/* propagate the error condition to the CAN stack */
+	skb = alloc_can_err_skb(dev, &cf);
+	if (unlikely(!skb))
+		return 0;
+
+	d_can_get_berr_counter(dev, &bec);
+	reg_err_counter = d_can_read(priv, D_CAN_ERRC);
+	rx_err_passive = (reg_err_counter & D_CAN_ERRC_RP_MASK) >>
+				D_CAN_ERRC_RP_SHIFT;
+
+	switch (error_type) {
+	case D_CAN_ERROR_WARNING:
+		/* error warning state */
+		priv->can.can_stats.error_warning++;
+		priv->can.state = CAN_STATE_ERROR_WARNING;
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[1] = (bec.txerr > bec.rxerr) ?
+			CAN_ERR_CRTL_TX_WARNING :
+			CAN_ERR_CRTL_RX_WARNING;
+		cf->data[6] = bec.txerr;
+		cf->data[7] = bec.rxerr;
+
+		break;
+	case D_CAN_ERROR_PASSIVE:
+		/* error passive state */
+		priv->can.can_stats.error_passive++;
+		priv->can.state = CAN_STATE_ERROR_PASSIVE;
+		cf->can_id |= CAN_ERR_CRTL;
+		if (rx_err_passive)
+			cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+		if (bec.txerr > 127)
+			cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+
+		cf->data[6] = bec.txerr;
+		cf->data[7] = bec.rxerr;
+		break;
+	case D_CAN_BUS_OFF:
+		/* bus-off state */
+		priv->can.state = CAN_STATE_BUS_OFF;
+		cf->can_id |= CAN_ERR_BUSOFF;
+		/*
+		 * disable all interrupts in bus-off mode to ensure that
+		 * the CPU is not hogged down
+		 */
+		d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+		can_bus_off(dev);
+		break;
+	default:
+		break;
+	}
+
+	netif_receive_skb(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+
+	return 1;
+}
+
+static int d_can_handle_bus_err(struct net_device *dev,
+				enum d_can_lec_type lec_type)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+
+	/*
+	 * early exit if no lec update or no error.
+	 * no lec update means that no CAN bus event has been detected
+	 * since CPU wrote 0x7 value to status reg.
+	 */
+	if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
+		return 0;
+
+	/* propagate the error condition to the CAN stack */
+	skb = alloc_can_err_skb(dev, &cf);
+	if (unlikely(!skb))
+		return 0;
+
+	/*
+	 * check for 'last error code' which tells us the
+	 * type of the last error to occur on the CAN bus
+	 */
+
+	/* common for all type of bus errors */
+	priv->can.can_stats.bus_error++;
+	stats->rx_errors++;
+	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+	cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+	switch (lec_type) {
+	case LEC_STUFF_ERROR:
+		netdev_dbg(dev, "stuff error\n");
+		cf->data[2] |= CAN_ERR_PROT_STUFF;
+		break;
+	case LEC_FORM_ERROR:
+		netdev_dbg(dev, "form error\n");
+		cf->data[2] |= CAN_ERR_PROT_FORM;
+		break;
+	case LEC_ACK_ERROR:
+		netdev_dbg(dev, "ack error\n");
+		cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
+				CAN_ERR_PROT_LOC_ACK_DEL);
+		break;
+	case LEC_BIT1_ERROR:
+		netdev_dbg(dev, "bit1 error\n");
+		cf->data[2] |= CAN_ERR_PROT_BIT1;
+		break;
+	case LEC_BIT0_ERROR:
+		netdev_dbg(dev, "bit0 error\n");
+		cf->data[2] |= CAN_ERR_PROT_BIT0;
+		break;
+	case LEC_CRC_ERROR:
+		netdev_dbg(dev, "CRC error\n");
+		cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+				CAN_ERR_PROT_LOC_CRC_DEL);
+		break;
+	default:
+		break;
+	}
+
+	/* set a `lec` value so that we can check for updates later */
+	d_can_write(priv, D_CAN_ES, LEC_UNUSED);
+
+	netif_receive_skb(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+
+	return 1;
+}
+
+static int d_can_poll(struct napi_struct *napi, int quota)
+{
+	int lec_type = 0;
+	int work_done = 0;
+	struct net_device *dev = napi->dev;
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	priv->irqstatus = d_can_read(priv, D_CAN_INT);
+	if (!priv->irqstatus)
+		goto end;
+
+	/* status events have the highest priority */
+	if (priv->irqstatus == STATUS_INTERRUPT) {
+		priv->current_status = d_can_read(priv, D_CAN_ES);
+
+		/* handle Tx/Rx events */
+		if (priv->current_status & D_CAN_ES_TXOK)
+			d_can_write(priv, D_CAN_ES,
+					priv->current_status & ~D_CAN_ES_TXOK);
+
+		if (priv->current_status & D_CAN_ES_RXOK)
+			d_can_write(priv, D_CAN_ES,
+					priv->current_status & ~D_CAN_ES_RXOK);
+
+		/* handle state changes */
+		if ((priv->current_status & D_CAN_ES_EWARN) &&
+				(!(priv->last_status & D_CAN_ES_EWARN))) {
+			netdev_dbg(dev, "entered error warning state\n");
+			work_done += d_can_handle_state_change(dev,
+						D_CAN_ERROR_WARNING);
+		}
+		if ((priv->current_status & D_CAN_ES_EPASS) &&
+				(!(priv->last_status & D_CAN_ES_EPASS))) {
+			netdev_dbg(dev, "entered error passive state\n");
+			work_done += d_can_handle_state_change(dev,
+						D_CAN_ERROR_PASSIVE);
+		}
+		if ((priv->current_status & D_CAN_ES_BOFF) &&
+				(!(priv->last_status & D_CAN_ES_BOFF))) {
+			netdev_dbg(dev, "entered bus off state\n");
+			work_done += d_can_handle_state_change(dev,
+						D_CAN_BUS_OFF);
+		}
+
+		/* handle bus recovery events */
+		if ((!(priv->current_status & D_CAN_ES_BOFF)) &&
+				(priv->last_status & D_CAN_ES_BOFF)) {
+			netdev_dbg(dev, "left bus off state\n");
+			priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		}
+		if ((!(priv->current_status & D_CAN_ES_EPASS)) &&
+				(priv->last_status & D_CAN_ES_EPASS)) {
+			netdev_dbg(dev, "left error passive state\n");
+			priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		}
+
+		priv->last_status = priv->current_status;
+
+		/* handle lec errors on the bus */
+		lec_type = d_can_has_and_handle_berr(priv);
+		if (lec_type)
+			work_done += d_can_handle_bus_err(dev, lec_type);
+	} else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&
+			(priv->irqstatus <= D_CAN_MSG_OBJ_RX_LAST)) {
+		/* handle events corresponding to receive message objects */
+		work_done += d_can_do_rx_poll(dev, (quota - work_done));
+	} else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&
+			(priv->irqstatus <= D_CAN_MSG_OBJ_TX_LAST)) {
+		/* handle events corresponding to transmit message objects */
+		d_can_do_tx(dev);
+	}
+
+end:
+	if (work_done < quota) {
+		napi_complete(napi);
+		/* enable all IRQs */
+		d_can_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+	}
+
+	return work_done;
+}
+
+static irqreturn_t d_can_isr(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	priv->irqstatus = d_can_read(priv, D_CAN_INT);
+	if (!priv->irqstatus)
+		return IRQ_NONE;
+
+	/* disable all interrupts and schedule the NAPI */
+	d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+	napi_schedule(&priv->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int d_can_open(struct net_device *ndev)
+{
+	int err;
+	struct d_can_priv *priv = netdev_priv(ndev);
+
+	/* Open common can device */
+	err = open_candev(ndev);
+	if (err) {
+		netdev_err(ndev, "open_candev() failed %d\n", err);
+		return err;
+	}
+
+	/* register interrupt handler for Message Object (MO)
+	 * and Error + status change (ES) */
+	err = request_irq(ndev->irq, &d_can_isr, IRQF_SHARED, ndev->name,
+				ndev);
+	if (err) {
+		netdev_err(ndev, "failed to request MO_ES interrupt\n");
+		goto exit_close_candev;
+	}
+
+	/* register interrupt handler for only Message Object */
+	err = request_irq(priv->irq_obj, &d_can_isr, IRQF_SHARED, ndev->name,
+				ndev);
+	if (err) {
+		netdev_err(ndev, "failed to request MO interrupt\n");
+		goto exit_free_irq;
+	}
+
+	/* start the d_can controller */
+	d_can_start(ndev);
+
+	napi_enable(&priv->napi);
+	netif_start_queue(ndev);
+
+	return 0;
+exit_free_irq:
+	free_irq(ndev->irq, ndev);
+exit_close_candev:
+	close_candev(ndev);
+	return err;
+}
+
+static int d_can_close(struct net_device *ndev)
+{
+	struct d_can_priv *priv = netdev_priv(ndev);
+
+	netif_stop_queue(ndev);
+	napi_disable(&priv->napi);
+	d_can_stop(ndev);
+	free_irq(ndev->irq, ndev);
+	free_irq(priv->irq_obj, ndev);
+	close_candev(ndev);
+
+	return 0;
+}
+
+struct net_device *alloc_d_can_dev(int num_objs)
+{
+	struct net_device *dev;
+	struct d_can_priv *priv;
+
+	dev = alloc_candev(sizeof(struct d_can_priv), num_objs/2);
+	if (!dev)
+		return NULL;
+
+	priv = netdev_priv(dev);
+	netif_napi_add(dev, &priv->napi, d_can_poll, num_objs/2);
+
+	priv->dev = dev;
+	priv->can.bittiming_const = &d_can_bittiming_const;
+	priv->can.do_set_mode = d_can_set_mode;
+	priv->can.do_get_berr_counter = d_can_get_berr_counter;
+	priv->can.ctrlmode_supported = (CAN_CTRLMODE_LOOPBACK |
+					CAN_CTRLMODE_LISTENONLY |
+					CAN_CTRLMODE_BERR_REPORTING |
+					CAN_CTRLMODE_3_SAMPLES);
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_d_can_dev);
+
+void free_d_can_dev(struct net_device *dev)
+{
+	free_candev(dev);
+}
+EXPORT_SYMBOL_GPL(free_d_can_dev);
+
+static const struct net_device_ops d_can_netdev_ops = {
+	.ndo_open = d_can_open,
+	.ndo_stop = d_can_close,
+	.ndo_start_xmit = d_can_start_xmit,
+};
+
+int register_d_can_dev(struct net_device *dev)
+{
+	/* we support local echo */
+	dev->flags |= IFF_ECHO;
+	dev->netdev_ops = &d_can_netdev_ops;
+
+	return register_candev(dev);
+}
+EXPORT_SYMBOL_GPL(register_d_can_dev);
+
+void unregister_d_can_dev(struct net_device *dev)
+{
+	struct d_can_priv *priv = netdev_priv(dev);
+
+	/* disable all interrupts */
+	d_can_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+	unregister_candev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_d_can_dev);
+
+MODULE_AUTHOR("Anil Kumar Ch <anilkumar@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(D_CAN_VERSION);
+MODULE_DESCRIPTION(D_CAN_DRV_DESC);
diff --git a/drivers/net/can/d_can/d_can.h b/drivers/net/can/d_can/d_can.h
new file mode 100644
index 0000000..f096944
--- /dev/null
+++ b/drivers/net/can/d_can/d_can.h
@@ -0,0 +1,67 @@
+/*
+ * CAN bus driver for Bosch D_CAN controller
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/
+ * Anil Kumar Ch <anilkumar@ti.com>
+ *
+ * Base taken from C_CAN driver
+ * Copyright (C) 2010 ST Microelectronics
+ * - Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch D_CAN controller 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
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef D_CAN_H
+#define D_CAN_H
+
+#define D_CAN_DRV_NAME	"d_can"
+#define D_CAN_VERSION	"1.0"
+#define D_CAN_DRV_DESC	"CAN bus driver for Bosch D_CAN controller " \
+			D_CAN_VERSION
+
+/* d_can private data structure */
+struct d_can_priv {
+	struct can_priv can;	/* must be the first member */
+	struct napi_struct napi;
+	struct net_device *dev;
+	int current_status;
+	int last_status;
+	unsigned int irqstatus;
+	void __iomem *base;
+	u32 napi_weight;
+	struct clk *fck;
+	struct clk *ick;
+	bool test_mode;
+	unsigned int irq;	/* device IRQ number, for all MO and ES	*/
+	unsigned int irq_obj;	/* device IRQ number for only Msg Object */
+	unsigned int irq_parity; /* device IRQ number for parity error */
+	unsigned long irq_flags; /* for request_irq() */
+	unsigned int tx_next;
+	unsigned int tx_echo;
+	unsigned int rx_next;
+	void *priv;		/* for board-specific data */
+};
+
+struct net_device *alloc_d_can_dev(int);
+void free_d_can_dev(struct net_device *dev);
+int register_d_can_dev(struct net_device *dev);
+void unregister_d_can_dev(struct net_device *dev);
+
+#endif /* D_CAN_H */
diff --git a/drivers/net/can/d_can/d_can_platform.c b/drivers/net/can/d_can/d_can_platform.c
new file mode 100644
index 0000000..b430a18
--- /dev/null
+++ b/drivers/net/can/d_can/d_can_platform.c
@@ -0,0 +1,256 @@
+/*
+ * Platform CAN bus driver for Bosch D_CAN controller
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/
+ * Anil Kumar Ch <anilkumar@ti.com>
+ *
+ * Base taken from C_CAN driver
+ * Copyright (C) 2010 ST Microelectronics
+ * - Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch D_CAN controller 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
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Your platform definitions should specify module ram offsets and interrupt
+ * number to use as follows:
+ *
+ * static struct d_can_platform_data am33xx_evm_d_can_pdata = {
+ *	.d_can_offset		= 0,
+ *	.d_can_ram_offset	= 0x1000,
+ *	.num_of_msg_objs	= 64,
+ *	.dma_support		= true,
+ *	.test_mode_enable	= false,
+ *	.parity_check		= false,
+ *	.version		= 0x1,
+ *	.hw_raminit		= d_can_hw_raminit,
+ * };
+ *
+ * Please see include/linux/can/platform/d_can.h for description of
+ * above fields.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/can/platform/d_can.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/can/dev.h>
+
+#include "d_can.h"
+
+#define D_CAN_CLK_NAME_LEN	40
+
+static int __devinit d_can_plat_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	void __iomem *addr;
+	struct net_device *ndev;
+	struct d_can_priv *priv;
+	struct resource *mem;
+	struct d_can_platform_data *pdata;
+	char *clk_name;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "No platform data\n");
+		goto exit;
+	}
+
+	/* allocate the d_can device */
+	ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
+	if (!ndev) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
+		goto exit;
+	}
+
+	clk_name = kzalloc(D_CAN_CLK_NAME_LEN + 1, GFP_KERNEL);
+	if (!clk_name)
+		goto exit;
+
+	priv = netdev_priv(ndev);
+	clk_name = "dcan";
+	if (pdev->id == 0)
+		strcat(clk_name, "0_fck");
+	else
+		strcat(clk_name, "1_fck");
+	/* get the appropriate clk */
+	priv->fck = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(priv->fck)) {
+		dev_err(&pdev->dev, "%s is not found\n", clk_name);
+		ret = -ENODEV;
+		goto exit_free_ndev;
+	}
+	clk_enable(priv->fck);
+
+	/* clk_name = D_CAN_DRV_NAME; */
+	clk_name = "dcan";
+	if (pdev->id == 0)
+		strcat(clk_name, "0_ick");
+	else
+		strcat(clk_name, "1_ick");
+	priv->ick = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(priv->ick)) {
+		dev_err(&pdev->dev, "%s is not found\n", clk_name);
+		ret = -ENODEV;
+		goto exit_free_fck;
+	}
+	clk_enable(priv->ick);
+
+	/* get the platform data */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "No mem resource\n");
+		goto exit_free_clks;
+	}
+
+	if (!request_mem_region(mem->start, resource_size(mem),
+				D_CAN_DRV_NAME)) {
+		dev_err(&pdev->dev, "resource unavailable\n");
+		ret = -EBUSY;
+		goto exit_free_clks;
+	}
+
+	addr = ioremap(mem->start, resource_size(mem));
+	if (!addr) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto exit_release_mem;
+	}
+
+	/* IRQ specific to Error and status & can be used for Message Object */
+	ndev->irq = platform_get_irq_byname(pdev, "d_can_int0");
+	if (!ndev->irq) {
+		dev_err(&pdev->dev, "No irq0 resource\n");
+		goto exit_iounmap;
+	}
+
+	/* IRQ specific for Message Object */
+	priv->irq_obj = platform_get_irq_byname(pdev, "d_can_int1");
+	if (!priv->irq_obj) {
+		dev_err(&pdev->dev, "No irq1 resource\n");
+		goto exit_iounmap;
+	}
+
+	priv->base = addr;
+	priv->can.clock.freq = clk_get_rate(priv->fck);
+
+	/* RAM init */
+	pdata->hw_raminit(pdev->id);
+
+	priv->test_mode = pdata->test_mode_enable;
+
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	ret = register_d_can_dev(ndev);
+	if (ret) {
+		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+				D_CAN_DRV_NAME, ret);
+		goto exit_free_device;
+	}
+
+	dev_info(&pdev->dev, "%s device registered (irq=%d, irq_obj=%d)\n",
+				D_CAN_DRV_NAME, ndev->irq, priv->irq_obj);
+
+	return 0;
+
+exit_free_device:
+	platform_set_drvdata(pdev, NULL);
+exit_iounmap:
+	iounmap(addr);
+exit_release_mem:
+	release_mem_region(mem->start, resource_size(mem));
+exit_free_clks:
+#ifdef CONFIG_HAVE_CLK
+	clk_disable(priv->ick);
+	clk_put(priv->ick);
+exit_free_fck:
+	clk_disable(priv->fck);
+	clk_put(priv->fck);
+exit_free_ndev:
+	free_d_can_dev(ndev);
+exit:
+#endif
+	dev_err(&pdev->dev, "probe failed\n");
+
+	return ret;
+}
+
+static int __devexit d_can_plat_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct d_can_priv *priv = netdev_priv(ndev);
+	struct resource *mem;
+
+	free_d_can_dev(ndev);
+	iounmap(priv->base);
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+#ifdef CONFIG_HAVE_CLK
+	clk_disable(priv->ick);
+	clk_disable(priv->fck);
+	clk_put(priv->ick);
+	clk_put(priv->fck);
+#endif
+	unregister_d_can_dev(ndev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver d_can_plat_driver = {
+	.driver = {
+		.name	= D_CAN_DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= d_can_plat_probe,
+	.remove = __devexit_p(d_can_plat_remove),
+};
+
+static int __init d_can_plat_init(void)
+{
+	printk(KERN_INFO D_CAN_DRV_DESC "\n");
+	return platform_driver_register(&d_can_plat_driver);
+}
+module_init(d_can_plat_init);
+
+static void __exit d_can_plat_exit(void)
+{
+	printk(KERN_INFO D_CAN_DRV_DESC " unloaded\n");
+	platform_driver_unregister(&d_can_plat_driver);
+}
+module_exit(d_can_plat_exit);
+
+MODULE_AUTHOR("Anil Kumar Ch <anilkumar@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(D_CAN_VERSION);
+MODULE_DESCRIPTION(D_CAN_DRV_DESC);
diff --git a/include/linux/can/platform/d_can.h b/include/linux/can/platform/d_can.h
new file mode 100644
index 0000000..b139e05
--- /dev/null
+++ b/include/linux/can/platform/d_can.h
@@ -0,0 +1,53 @@
+#ifndef __CAN_PLATFORM_TI_D_CAN_H__
+#define __CAN_PLATFORM_TI_D_CAN_H__
+
+/*
+ * D_CAN controller driver platform header
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/
+ * Anil Kumar Ch <anilkumar@ti.com>
+ *
+ * Bosch D_CAN controller 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
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * struct d_can_platform_data - DCAN Platform Data
+ *
+ * @d_can_offset:	mostly 0 - should really never change
+ * @d_can_ram_offset:	d_can RAM offset
+ * @msg_obj_offset:	Mailbox RAM offset
+ * @num_of_msg_objs:	Number of message objects
+ * @dma_support:	DMA support is required/not
+ * test_mode_enable:	Test mode enable bit
+ * @parity_check:	Parity error checking is needed/not
+ * @version:		version for future use
+ * @hw_raminit:		platform specific callback fn for h/w ram init
+ *
+ * Platform data structure to get all platform specific settings.
+ * this structure also accounts the fact that the IP may have different
+ * RAM and mailbox offsets for different SOC's
+ */
+struct d_can_platform_data {
+	u32 d_can_offset;
+	u32 d_can_ram_offset;
+	u32 msg_obj_offset;
+	u32 num_of_msg_objs;
+	bool dma_support;
+	bool test_mode_enable;
+	bool parity_check;
+	u32 version;
+	void (*hw_raminit) (unsigned int);
+};
+#endif
-- 
1.7.2.5

