linux-ti335x-psp 3.1: add CAN bus patches
authorKoen Kooi <koen@dominion.thruhere.net>
Thu, 10 Nov 2011 14:43:47 +0000 (15:43 +0100)
committerKoen Kooi <koen@dominion.thruhere.net>
Thu, 10 Nov 2011 14:43:47 +0000 (15:43 +0100)
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
recipes-kernel/linux/linux-ti33x-psp-3.1/beaglebone/defconfig
recipes-kernel/linux/linux-ti33x-psp-3.1/can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch [new file with mode: 0644]
recipes-kernel/linux/linux-ti33x-psp-3.1/can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch [new file with mode: 0644]
recipes-kernel/linux/linux-ti33x-psp-3.1/can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch [new file with mode: 0644]
recipes-kernel/linux/linux-ti33x-psp-3.1/can/0004-can-d_can-fix-for-cansend-loop-issue.patch [new file with mode: 0644]
recipes-kernel/linux/linux-ti33x-psp-3.1/can/0005-can-d_can-fixes-the-rmmod-crash.patch [new file with mode: 0644]
recipes-kernel/linux/linux-ti33x-psp-3.1/can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch [new file with mode: 0644]
recipes-kernel/linux/linux-ti33x-psp_3.1.bb

index 2222733796441d5444efc7121c43a517959a7d79..f1a014cb877e1e66557a9bb934a49110a382c093 100644 (file)
@@ -786,6 +786,8 @@ CONFIG_CAN_TI_HECC=m
 # CONFIG_CAN_MCP251X is not set
 # CONFIG_CAN_SJA1000 is not set
 # CONFIG_CAN_C_CAN is not set
+CONFIG_CAN_D_CAN=m
+CONFIG_CAN_D_CAN_PLATFORM=m
 
 #
 # CAN USB interfaces
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch
new file mode 100644 (file)
index 0000000..79bac4e
--- /dev/null
@@ -0,0 +1,1839 @@
+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
+
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch
new file mode 100644 (file)
index 0000000..c3fd4cd
--- /dev/null
@@ -0,0 +1,260 @@
+From f2da2b163827a075c98f1897801c90bf736784a3 Mon Sep 17 00:00:00 2001
+From: Anil Kumar Ch <anilkumar@ti.com>
+Date: Sun, 6 Nov 2011 02:46:12 +0530
+Subject: [PATCH 2/7] can: d_can: Added platform data for am33xx device
+
+This patch adds the platform data needed by the driver. Added the
+resources to the difference d_can instances.
+
+Initialization of message ram is necessary to read/write the message object
+from/into the message RAM
+
+Signed-off-by: Anil Kumar Ch <anilkumar@ti.com>
+---
+ arch/arm/mach-omap2/board-am335xevm.c    |  131 ++++++++++++++++++++++++++++++
+ arch/arm/mach-omap2/clock33xx_data.c     |   18 ++++
+ arch/arm/mach-omap2/mux33xx.c            |    8 +-
+ arch/arm/plat-omap/include/plat/am33xx.h |    3 +
+ 4 files changed, 156 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
+index c84857e..6773f3b 100644
+--- a/arch/arm/mach-omap2/board-am335xevm.c
++++ b/arch/arm/mach-omap2/board-am335xevm.c
+@@ -24,6 +24,7 @@
+ #include <linux/mtd/nand.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/platform_device.h>
++#include <linux/can/platform/d_can.h>
+ #include <linux/clk.h>
+ #include <linux/err.h>
+ #include <linux/wl12xx.h>
+@@ -50,6 +51,7 @@
+ /* LCD controller is similar to DA850 */
+ #include <video/da8xx-fb.h>
++#include "control.h"
+ #include "board-flash.h"
+ #include "mux.h"
+ #include "devices.h"
+@@ -991,6 +993,133 @@ static void mmc2_wl12xx_init(int evm_id, int profile)
+       return;
+ }
++#define AM33XX_D_CAN_RAM_BASE         0x1000
++#define AM33XX_D_CAN_NUM_MSG_OBJS     64
++#define AM33XX_D_CAN_VERSION          0x1
++#define AM33XX_CTL_DCAN_RAMINIT_OFFSET        0x644
++#define AM33XX_D_CAN_RAMINIT_START(n) (0x1 << n)
++
++static void d_can_hw_raminit(unsigned int instance)
++{
++      u32 raminit_reg_val;
++
++      /* Read the value */
++      raminit_reg_val = __raw_readl(AM33XX_CTRL_REGADDR(
++                              AM33XX_CTL_DCAN_RAMINIT_OFFSET));
++
++      /* Modify by setting "0" */
++      raminit_reg_val &= ~AM33XX_D_CAN_RAMINIT_START(instance);
++      __raw_writel(raminit_reg_val, AM33XX_CTRL_REGADDR(
++                              AM33XX_CTL_DCAN_RAMINIT_OFFSET));
++
++      /* Reset to one */
++      raminit_reg_val |= AM33XX_D_CAN_RAMINIT_START(instance);
++      __raw_writel(raminit_reg_val, AM33XX_CTRL_REGADDR(
++                      AM33XX_CTL_DCAN_RAMINIT_OFFSET));
++      udelay(10);
++}
++
++static struct d_can_platform_data am33xx_evm_d_can_pdata = {
++      .d_can_offset           = 0,
++      .d_can_ram_offset       = AM33XX_D_CAN_RAM_BASE,
++      .num_of_msg_objs        = AM33XX_D_CAN_NUM_MSG_OBJS,
++      .dma_support            = false,
++      .test_mode_enable       = false,
++      .parity_check           = false,
++      .version                = AM33XX_D_CAN_VERSION,
++      .hw_raminit             = d_can_hw_raminit,
++};
++
++static struct resource am33xx_d_can0_resources[] = {
++      {
++              .start  = AM33XX_D_CAN0_BASE,
++              .end    = AM33XX_D_CAN0_BASE + 0x3FFF,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = "d_can_int0",
++              .start  = AM33XX_IRQ_DCAN0_0,
++              .end    = AM33XX_IRQ_DCAN0_0,
++              .flags  = IORESOURCE_IRQ,
++      },
++      {
++              .name   = "d_can_int1",
++              .start  = AM33XX_IRQ_DCAN0_1,
++              .end    = AM33XX_IRQ_DCAN0_1,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device am33xx_d_can0_device = {
++      .dev            = {
++              .platform_data = &am33xx_evm_d_can_pdata,
++      },
++      .name           = "d_can",
++      .id             = 0,
++      .num_resources  = ARRAY_SIZE(am33xx_d_can0_resources),
++      .resource       = am33xx_d_can0_resources,
++};
++
++static struct pinmux_config d_can0_pin_mux[] = {
++      {"uart1_ctsn.d_can0_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL},
++      {"uart1_rtsn.d_can0_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP},
++      {NULL, 0},
++};
++
++static void d_can0_init(int evm_id, int profile)
++{
++      /* For instance 0 */
++      if (profile == PROFILE_1) {
++              setup_pin_mux(d_can0_pin_mux);
++              platform_device_register(&am33xx_d_can0_device);
++      }
++}
++
++/* DCAN instnace 1 specific resources */
++static struct resource am33xx_d_can1_resources[] = {
++      {
++              .start  = AM33XX_D_CAN1_BASE,
++              .end    = AM33XX_D_CAN1_BASE + 0x3FFF,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = "d_can_int0",
++              .start  = AM33XX_IRQ_DCAN1_0,
++              .end    = AM33XX_IRQ_DCAN1_0,
++              .flags  = IORESOURCE_IRQ,
++      },
++      {
++              .name   = "d_can_int1",
++              .start  = AM33XX_IRQ_DCAN1_1,
++              .end    = AM33XX_IRQ_DCAN1_1,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device am33xx_d_can1_device = {
++      .dev            = {
++              .platform_data = &am33xx_evm_d_can_pdata,
++      },
++      .name           = "d_can",
++      .id             = 1,
++      .num_resources  = ARRAY_SIZE(am33xx_d_can1_resources),
++      .resource       = am33xx_d_can1_resources,
++};
++
++static struct pinmux_config d_can1_pin_mux[] = {
++      {"uart1_rxd.d_can1_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL},
++      {"uart1_txd.d_can1_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP},
++      {NULL, 0},
++};
++
++static void d_can1_init(int evm_id, int profile)
++{
++      /* For instance 1 */
++      if (profile == PROFILE_4) {
++              setup_pin_mux(d_can1_pin_mux);
++              platform_device_register(&am33xx_d_can1_device);
++      }
++}
+ static void uart1_wl12xx_init(int evm_id, int profile)
+ {
+       setup_pin_mux(uart1_wl12xx_pin_mux);
+@@ -1194,6 +1323,8 @@ static struct evm_dev_cfg gen_purp_evm_dev_cfg[] = {
+       {uart1_wl12xx_init,     DEV_ON_BASEBOARD, (PROFILE_0 | PROFILE_3 |
+                                                               PROFILE_5)},
+       {wl12xx_init,   DEV_ON_BASEBOARD, (PROFILE_0 | PROFILE_3 | PROFILE_5)},
++      {d_can0_init,   DEV_ON_BASEBOARD, PROFILE_1},
++      {d_can1_init,   DEV_ON_BASEBOARD, PROFILE_4},
+       {NULL, 0, 0},
+ };
+diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c
+index 6763c59..d8670f2 100644
+--- a/arch/arm/mach-omap2/clock33xx_data.c
++++ b/arch/arm/mach-omap2/clock33xx_data.c
+@@ -421,6 +421,22 @@ static struct clk dcan1_fck = {
+       .recalc         = &followparent_recalc,
+ };
++static struct clk dcan0_ick = {
++      .name           = "dcan0_ick",
++      .parent         = &dpll_per_m2_ck ,
++      .ops            = &clkops_null,
++      .clkdm_name     = "l4ls_clkdm",
++      .recalc         = &followparent_recalc,
++};
++
++static struct clk dcan1_ick = {
++      .name           = "dcan1_ick",
++      .parent         = &dpll_per_m2_ck ,
++      .ops            = &clkops_null,
++      .clkdm_name     = "l4ls_clkdm",
++      .recalc         = &followparent_recalc,
++};
++
+ static struct clk debugss_fck = {
+       .name           = "debugss_fck",
+       .ops            = &clkops_omap2_dflt,
+@@ -1771,6 +1787,8 @@ static struct omap_clk am33xx_clks[] = {
+       CLK("cpsw.0",   NULL,                   &cpgmac0_fck,   CK_AM33XX),
+       CLK(NULL,       "dcan0_fck",            &dcan0_fck,     CK_AM33XX),
+       CLK(NULL,       "dcan1_fck",            &dcan1_fck,     CK_AM33XX),
++      CLK(NULL,       "dcan0_ick",            &dcan0_ick,     CK_AM33XX),
++      CLK(NULL,       "dcan1_ick",            &dcan1_ick,     CK_AM33XX),
+       CLK(NULL,       "debugss_fck",          &debugss_fck,   CK_AM33XX),
+       CLK(NULL,       "elm_fck",              &elm_fck,       CK_AM33XX),
+       CLK(NULL,       "emif_fck",             &emif_fck,      CK_AM33XX),
+diff --git a/arch/arm/mach-omap2/mux33xx.c b/arch/arm/mach-omap2/mux33xx.c
+index 0286c4f..8232b46 100644
+--- a/arch/arm/mach-omap2/mux33xx.c
++++ b/arch/arm/mach-omap2/mux33xx.c
+@@ -315,16 +315,16 @@ static struct omap_mux __initdata am33xx_muxmodes[] = {
+               "uart0_txd", "spi1_cs1", NULL, NULL,
+               NULL, NULL, NULL, NULL),
+       _AM33XX_MUXENTRY(UART1_CTSN, 0,
+-              "uart1_ctsn", NULL, NULL, NULL,
++              "uart1_ctsn", NULL, "d_can0_tx", NULL,
+               "spi1_cs0", NULL, NULL, NULL),
+       _AM33XX_MUXENTRY(UART1_RTSN, 0,
+-              "uart1_rtsn", NULL, NULL, NULL,
++              "uart1_rtsn", NULL, "d_can0_rx", NULL,
+               "spi1_cs1", NULL, NULL, NULL),
+       _AM33XX_MUXENTRY(UART1_RXD, 0,
+-              "uart1_rxd", "mmc1_sdwp", NULL, NULL,
++              "uart1_rxd", "mmc1_sdwp", "d_can1_tx", NULL,
+               NULL, NULL, NULL, NULL),
+       _AM33XX_MUXENTRY(UART1_TXD, 0,
+-              "uart1_txd", "mmc2_sdwp", NULL, NULL,
++              "uart1_txd", "mmc2_sdwp", "d_can1_rx", NULL,
+               NULL, NULL, NULL, NULL),
+       _AM33XX_MUXENTRY(I2C0_SDA, 0,
+               "i2c0_sda", NULL, NULL, NULL,
+diff --git a/arch/arm/plat-omap/include/plat/am33xx.h b/arch/arm/plat-omap/include/plat/am33xx.h
+index a77c38e..cfd1883 100644
+--- a/arch/arm/plat-omap/include/plat/am33xx.h
++++ b/arch/arm/plat-omap/include/plat/am33xx.h
+@@ -30,6 +30,9 @@
+ #define AM33XX_TSC_BASE               0x44E0D000
+ #define AM33XX_RTC_BASE               0x44E3E000
++#define AM33XX_D_CAN0_BASE    0x481CC000
++#define AM33XX_D_CAN1_BASE    0x481D0000
++
+ #define AM33XX_ASP0_BASE      0x48038000
+ #define AM33XX_ASP1_BASE      0x4803C000
+-- 
+1.7.2.5
+
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch
new file mode 100644 (file)
index 0000000..5728519
--- /dev/null
@@ -0,0 +1,57 @@
+From 68a9166b306c9b7a542a8ddcf31cc5fa738f52b3 Mon Sep 17 00:00:00 2001
+From: Anil Kumar Ch <anilkumar@ti.com>
+Date: Sun, 6 Nov 2011 10:44:26 +0530
+Subject: [PATCH 3/7] can: d_can: DCAN config added to am335x_evm_defconfig
+
+This patch adds the DCAN and dependent modules configurations
+to am335x_evm_defconfig
+
+Dependent modules are:
+CONFIG_CAN_RAW
+CONFIG_CAN_BCM
+
+Signed-off-by: Anil Kumar Ch <anilkumar@ti.com>
+---
+ arch/arm/configs/am335x_evm_defconfig |   26 +++++++++++++++++++++++++-
+ 1 files changed, 25 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
+index 02ee0c3..a90dffd 100644
+--- a/arch/arm/configs/am335x_evm_defconfig
++++ b/arch/arm/configs/am335x_evm_defconfig
+@@ -658,7 +658,31 @@ CONFIG_DNS_RESOLVER=y
+ #
+ # CONFIG_NET_PKTGEN is not set
+ # CONFIG_HAMRADIO is not set
+-# CONFIG_CAN is not set
++CONFIG_CAN=y
++CONFIG_CAN_RAW=y
++CONFIG_CAN_BCM=y
++
++#
++# CAN Device Drivers
++#
++# CONFIG_CAN_VCAN is not set
++# CONFIG_CAN_SLCAN is not set
++CONFIG_CAN_DEV=y
++CONFIG_CAN_CALC_BITTIMING=y
++# CONFIG_CAN_TI_HECC is not set
++# CONFIG_CAN_MCP251X is not set
++# CONFIG_CAN_SJA1000 is not set
++# CONFIG_CAN_C_CAN is not set
++CONFIG_CAN_D_CAN=y
++CONFIG_CAN_D_CAN_PLATFORM=y
++
++#
++# CAN USB interfaces
++#
++# CONFIG_CAN_EMS_USB is not set
++# CONFIG_CAN_ESD_USB2 is not set
++# CONFIG_CAN_SOFTING is not set
++# CONFIG_CAN_DEBUG_DEVICES is not set
+ # CONFIG_IRDA is not set
+ CONFIG_BT=y
+ CONFIG_BT_L2CAP=y
+-- 
+1.7.2.5
+
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0004-can-d_can-fix-for-cansend-loop-issue.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0004-can-d_can-fix-for-cansend-loop-issue.patch
new file mode 100644 (file)
index 0000000..7d7b397
--- /dev/null
@@ -0,0 +1,49 @@
+From 3788f8da920468db766e5e8ec03785d2fc2c8f12 Mon Sep 17 00:00:00 2001
+From: Anil Kumar Ch <anilkumar@ti.com>
+Date: Thu, 10 Nov 2011 12:36:12 +0530
+Subject: [PATCH 4/7] can: d_can: fix for cansend loop issue
+
+The specified number of packets are not transmitting with the
+help of cansend --loop=10. This pacth fixes the issue and able
+to transmit upto 32 packets. This limitation is because of no.
+of objects availability on AM335X
+
+Signed-off-by: Anil Kumar Ch <anilkumar@ti.com>
+---
+ drivers/net/can/d_can/d_can.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/can/d_can/d_can.c b/drivers/net/can/d_can/d_can.c
+index e001db0..d31b019 100644
+--- a/drivers/net/can/d_can/d_can.c
++++ b/drivers/net/can/d_can/d_can.c
+@@ -611,7 +611,7 @@ static inline int d_can_is_next_tx_obj_busy(struct d_can_priv *priv, int objno)
+        * 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)))
++                      (1 << (objno - D_CAN_MSG_OBJ_TX_FIRST)))
+               return 1;
+       return 0;
+@@ -858,7 +858,8 @@ static void d_can_do_tx(struct net_device *dev)
+               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)))) {
++              if (!(txrq_reg_val & (1 << (msg_obj_no -
++                                              D_CAN_MSG_OBJ_TX_FIRST)))) {
+                       can_get_echo_skb(dev,
+                                       msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);
+                       stats->tx_bytes += d_can_read(priv,
+@@ -1124,7 +1125,6 @@ static int d_can_poll(struct napi_struct *napi, int quota)
+       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;
+-- 
+1.7.2.5
+
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0005-can-d_can-fixes-the-rmmod-crash.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0005-can-d_can-fixes-the-rmmod-crash.patch
new file mode 100644 (file)
index 0000000..5c8b063
--- /dev/null
@@ -0,0 +1,60 @@
+From 332ec54d00463875532584604f364fc4347d918b Mon Sep 17 00:00:00 2001
+From: Anil Kumar Ch <anilkumar@ti.com>
+Date: Thu, 10 Nov 2011 17:59:16 +0530
+Subject: [PATCH 5/7] can: d_can: fixes the rmmod crash
+
+This patch fixes the rmmod crash while unloading the
+DCAN driver from the kernel.
+
+Signed-off-by: Anil Kumar Ch <anilkumar@ti.com>
+---
+ drivers/net/can/d_can/d_can_platform.c |   11 +++++------
+ 1 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/can/d_can/d_can_platform.c b/drivers/net/can/d_can/d_can_platform.c
+index b430a18..859756b 100644
+--- a/drivers/net/can/d_can/d_can_platform.c
++++ b/drivers/net/can/d_can/d_can_platform.c
+@@ -190,7 +190,6 @@ exit_iounmap:
+ 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:
+@@ -199,7 +198,6 @@ exit_free_fck:
+ exit_free_ndev:
+       free_d_can_dev(ndev);
+ exit:
+-#endif
+       dev_err(&pdev->dev, "probe failed\n");
+       return ret;
+@@ -211,18 +209,19 @@ static int __devexit d_can_plat_remove(struct platform_device *pdev)
+       struct d_can_priv *priv = netdev_priv(ndev);
+       struct resource *mem;
++      unregister_d_can_dev(ndev);
++      platform_set_drvdata(pdev, NULL);
++
+       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;
+ }
+-- 
+1.7.2.5
+
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch b/recipes-kernel/linux/linux-ti33x-psp-3.1/can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch
new file mode 100644 (file)
index 0000000..123266f
--- /dev/null
@@ -0,0 +1,47 @@
+From 0aea3e2629cd1681d8d8e6e0a4409959b31ea4e9 Mon Sep 17 00:00:00 2001
+From: Anil Kumar Ch <anilkumar@ti.com>
+Date: Thu, 10 Nov 2011 15:21:47 +0100
+Subject: [PATCH 7/7] can: d_can: am335x profile modification for dcan0
+
+This patch modifies the profile information of am335x device.
+
+Profile reads of cpld_client from smbus gives an error leads to put
+the device into default profile 0. So by default the board configured
+to beaglebone even if we set the sw8 switch on daughter card to other
+profiles.
+
+This patch makes all the IO connecters are configured in profile 1.
+
+Signed-off-by: Anil Kumar Ch <anilkumar@ti.com>
+---
+ arch/arm/mach-omap2/board-am335xevm.c |    7 +++++--
+ 1 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
+index 590c4ca..ac64fc7 100644
+--- a/arch/arm/mach-omap2/board-am335xevm.c
++++ b/arch/arm/mach-omap2/board-am335xevm.c
+@@ -340,6 +340,9 @@ static u32 am335x_get_profile_selection(void)
+ {
+       int val = 0;
++      /* FIXME: temporary fix */
++      return 1;
++
+       if (!cpld_client)
+               /* error checking is not done in func's calling this routine.
+               so return profile 0 on error */
+@@ -1721,8 +1724,8 @@ out:
+        */
+       pr_err("Could not detect any board, falling back to: "
+               "Beaglebone (< Rev A3) with no daughter card connected\n");
+-      daughter_brd_detected = false;
+-      setup_beaglebone_old();
++      daughter_brd_detected = true;
++      setup_general_purpose_evm();
+       /* Initialize cpsw after board detection is completed as board
+        * information is required for configuring phy address and hence
+-- 
+1.7.2.5
+
index 836c5f82ad3b45a691a658ab5748ce98505f6512..c4cdfea9394744bf9f605fc86eecb367519ffddf 100644 (file)
@@ -35,6 +35,12 @@ PATCHES_OVER_PSP = " \
        file://0003-arm-omap-mcspi-correct-memory-range-when-requesting-.patch \
        file://0004-arm-omap-mcspi-follow-proper-pm_runtime-enable-disab.patch \
        file://0005-arm-omap-mcspi-follow-proper-probe-remove-steps.patch \
+       file://can/0001-can-d_can-Added-support-for-Bosch-D_CAN-controller.patch \
+       file://can/0002-can-d_can-Added-platform-data-for-am33xx-device.patch \
+       file://can/0003-can-d_can-DCAN-config-added-to-am335x_evm_defconfig.patch \
+       file://can/0004-can-d_can-fix-for-cansend-loop-issue.patch \
+       file://can/0005-can-d_can-fixes-the-rmmod-crash.patch \
+       file://can/0007-can-d_can-am335x-profile-modification-for-dcan0.patch \
        "
 
 SRC_URI += "${@base_contains('DISTRO_FEATURES', 'tipspkernel', "", "${PATCHES_OVER_PSP}", d)}"