On 04/03/2012 02:32 PM, AnilKumar Ch wrote:
> This patch adds the support for Bosch D_CAN controller.
> 
> Bosch D_CAN controller is a full-CAN implementation 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
> 
> D_CAN device is used on many SoCs like AM335x, DM8148 and DM813x
> EVMs from TI, D_CAN details on AM335x can be accessed from:
> http://www.ti.com/lit/ug/spruh73c/spruh73c.pdf
> 
> D_CAN can be configurable for 16, 32, 64 and 128 message objects.
> The driver implementation is based on 64 message objects.
> 
> Following are the design choices made while writing the controller
> driver:
> 1. Interface Register set IF0 has be used for receive and IF1 is
>    used for transmit 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.
> 
> Signed-off-by: AnilKumar Ch <anilku...@ti.com>

Please explain why this CAN controller cannot be handled by the existing
C_CAN driver, eventually with some extensions. The register layout seems
almost identical, at least.

Wolfgang.




> ---
>  drivers/net/can/Kconfig            |   14 +
>  drivers/net/can/Makefile           |    1 +
>  drivers/net/can/d_can.c            | 1487 
> ++++++++++++++++++++++++++++++++++++
>  include/linux/can/platform/d_can.h |   40 +
>  4 files changed, 1542 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/d_can.c
>  create mode 100644 include/linux/can/platform/d_can.h
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index bb709fd..2529cba 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -68,6 +68,20 @@ config CAN_TI_HECC
>         Driver for TI HECC (High End CAN Controller) module found on many
>         TI devices. The device specifications are available from www.ti.com
>  
> +config CAN_D_CAN
> +     tristate "Bosch D_CAN Controller"
> +     depends on CAN_DEV
> +     ---help---
> +       This driver adds support for the D_CAN device found in
> +       many SoCs like am335x, dm814x and dm813x boards from TI.
> +
> +       The device user guide can be accessed from
> +       http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/
> +       can/d_can_users_manual_111.pdf
> +
> +       To compile this driver as a module, choose M here: the
> +       module will be called d_can.
> +
>  config CAN_MCP251X
>       tristate "Microchip MCP251x SPI CAN controllers"
>       depends on CAN_DEV && SPI && HAS_DMA
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 938be37..4bd3a87 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -17,6 +17,7 @@ obj-$(CONFIG_CAN_C_CAN)             += c_can/
>  obj-$(CONFIG_CAN_CC770)              += cc770/
>  obj-$(CONFIG_CAN_AT91)               += at91_can.o
>  obj-$(CONFIG_CAN_TI_HECC)    += ti_hecc.o
> +obj-$(CONFIG_CAN_D_CAN)              += d_can.o
>  obj-$(CONFIG_CAN_MCP251X)    += mcp251x.o
>  obj-$(CONFIG_CAN_BFIN)               += bfin_can.o
>  obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
> diff --git a/drivers/net/can/d_can.c b/drivers/net/can/d_can.c
> new file mode 100644
> index 0000000..51e2986
> --- /dev/null
> +++ b/drivers/net/can/d_can.c
> @@ -0,0 +1,1487 @@
> +/*
> + * CAN bus driver for Bosch D_CAN controller
> + *
> + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * Borrowed from C_CAN driver
> + * Copyright (C) 2010 ST Microelectronics
> + * - Bhupesh Sharma <bhupesh.sha...@st.com>
> + *
> + * Borrowed heavily from the C_CAN driver originally written by:
> + * Copyright (C) 2007
> + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.ha...@pengutronix.de>
> + * - Simon Kallweit, intefo AG <simon.kallw...@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/netdevice.h>
> +#include <linux/errno.h>
> +#include <linux/skbuff.h>
> +#include <linux/jiffies.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +#include <linux/can/platform/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
> +
> +/* TI D_CAN module registers */
> +#define D_CAN_CTL            0x0     /* CAN control register */
> +#define D_CAN_ES             0x4     /* Error and status */
> +#define D_CAN_PARITYERR_EOI  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_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 */
> +
> +/* Error counter reg bit fields */
> +#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_MASK  (0xFF << 0)     /* Transmit err counter */
> +
> +/* Bit timing reg bit fields */
> +#define D_CAN_BTR_BRPE_SHIFT 16              /* Baud rate prescaler ext */
> +#define D_CAN_BTR_TSEG2_SHIFT        12              /* Time seg after smpl 
> point */
> +#define D_CAN_BTR_TSEG1_SHIFT        8               /* Time seg before smpl 
> point */
> +#define D_CAN_BTR_SJW_SHIFT  6               /* Syncronization jump width */
> +#define D_CAN_BTR_BRP_SHIFT  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 IF command reg bit fields */
> +#define D_CAN_IF_CMD_WR              BIT(23) /* Write/read */
> +#define D_CAN_IF_CMD_MASK    BIT(22) /* Access to mask bits */
> +#define D_CAN_IF_CMD_ARB     BIT(21) /* Access to arbitration bits */
> +#define D_CAN_IF_CMD_CONTROL BIT(20) /* Acess to 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 to Data Bytes 0-3 */
> +#define D_CAN_IF_CMD_DATAB   BIT(16) /* Access to 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_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_RIOC_IN                BIT(0)  /* CAN_RX data in */
> +
> +/* 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 objects split */
> +#define D_CAN_NUM_MSG_OBJECTS                64
> +#define D_CAN_NUM_RX_MSG_OBJECTS     32
> +#define D_CAN_NUM_TX_MSG_OBJECTS     32
> +
> +#define D_CAN_MSG_OBJ_RX_FIRST               1
> +#define D_CAN_MSG_OBJ_RX_LAST                (D_CAN_MSG_OBJ_RX_FIRST + \
> +                                     D_CAN_NUM_RX_MSG_OBJECTS - 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_NUM_TX_MSG_OBJECTS - 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_NUM_TX_MSG_OBJECTS - 1)
> +
> +/* global interrupt masks */
> +#define D_CAN_ENABLE_ALL_INTERRUPTS  1
> +#define D_CAN_DISABLE_ALL_INTERRUPTS 0
> +
> +/* status interrupt */
> +#define D_CAN_STATUS_INTERRUPT               0x8000
> +
> +#define D_CAN_BUSY_TIMEOUT           14
> +#define D_CAN_TIMEOUT_MS             1000
> +
> +/* Interface register bank number */
> +#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)) 
> >> 2)
> +
> +/* 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;
> +     struct platform_device *pdev;
> +     unsigned int tx_next;
> +     unsigned int tx_echo;
> +     u32 current_status;
> +     u32 last_status;
> +     u32 irqstatus;
> +     bool is_opened;
> +     void __iomem *base;
> +     void (*ram_init) (unsigned int, unsigned int);
> +};
> +
> +/* 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 last error code (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 */
> +enum d_can_bus_error_types {
> +     NO_ERROR = 0,
> +     BUS_OFF,
> +     ERROR_WARNING,
> +     ERROR_PASSIVE,
> +};
> +
> +static inline void d_can_write(struct d_can_priv *priv, u32 reg, u32 val)
> +{
> +     writel(val, priv->base + reg);
> +}
> +
> +static inline u32 d_can_read(struct d_can_priv *priv, u32 reg)
> +{
> +     return readl(priv->base + reg);
> +}
> +
> +static inline void d_can_set_bit(struct d_can_priv *priv, u32 reg, u32 
> bitmask)
> +{
> +     d_can_write(priv, reg, d_can_read(priv, reg) | bitmask);
> +}
> +
> +static inline u32 d_can_get_bit(struct d_can_priv *priv, u32 reg, u32 
> bitmask)
> +{
> +     return (d_can_read(priv, reg) & bitmask) ? 1 : 0;
> +}
> +
> +static inline void d_can_clear_bit(struct d_can_priv *priv, u32 reg,
> +                                                     u32 bitmask)
> +{
> +     d_can_write(priv, reg, d_can_read(priv, reg) & ~bitmask);
> +}
> +
> +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, unsigned 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_SIE | D_CAN_CTL_IE0);
> +     else
> +             cntrl_save &= ~(D_CAN_CTL_IE1 | D_CAN_CTL_EIE |
> +                             D_CAN_CTL_SIE | 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, u32 iface)
> +{
> +     unsigned long time_out = jiffies + msecs_to_jiffies(D_CAN_BUSY_TIMEOUT);
> +
> +     /* Check the status of busy bit */
> +     while (d_can_get_bit(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_BUSY) &&
> +                                     time_after(time_out, jiffies))
> +             cpu_relax();
> +
> +     if (time_after(jiffies, time_out))
> +             return -ETIMEDOUT;
> +
> +     return 0;
> +}
> +
> +static inline void d_can_object_get(struct net_device *dev,
> +                             u32 iface, u32 objno, u32 mask)
> +{
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     d_can_write(priv, D_CAN_IFCMD(iface), IFX_CMD_BITS(mask) |
> +                                     IFX_CMD_MSG_NUMBER(objno));
> +
> +     /*
> +      * As per specs, after writing the message object number in the
> +      * IF command register the transfer b/w interface register and
> +      * message RAM must be complete in 4 - 14 CAN-CLK period.
> +      */
> +     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,
> +                             u32 iface, u32 objno, u32 mask)
> +{
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     d_can_write(priv, D_CAN_IFCMD(iface), D_CAN_IF_CMD_WR |
> +             IFX_CMD_BITS(mask) | IFX_CMD_MSG_NUMBER(objno));
> +
> +     /*
> +      * As per specs, after writing the message object number in the
> +      * IF command register the transfer b/w interface register and
> +      * message RAM must be complete in 4 - 14 CAN-CLK period.
> +      */
> +     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, u32 iface,
> +                             struct can_frame *frame, u32 objno)
> +{
> +     struct d_can_priv *priv = netdev_priv(dev);
> +     unsigned int id;
> +     u32 flags = 0;
> +
> +     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);
> +
> +     /* Writing lower 4bytes to DATAA IF register */
> +     d_can_write(priv, D_CAN_IFDATA(iface),
> +                             le32_to_cpu(*(u32 *)(frame->data)));
> +
> +     /* Writing higher 4bytes to DATAB IF register */
> +     if (frame->can_dlc > 4)
> +             d_can_write(priv, D_CAN_IFDATB(iface),
> +                             le32_to_cpu(*(u32 *)(frame->data + 4)));
> +
> +     /* enable TX 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);
> +}
> +
> +/*
> + * Mark that this particular message object is received and clearing
> + * the interrupt pending register value.
> + */
> +static inline void d_can_mark_rx_msg_obj(struct net_device *dev,
> +                     u32 iface, u32 ctrl_mask, u32 objno)
> +{
> +     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, objno, D_CAN_IF_CMD_CONTROL);
> +}
> +
> +static inline void d_can_activate_all_lower_rx_msg_objs(struct net_device 
> *dev,
> +                                             u32 iface, u32 ctrl_mask)
> +{
> +     unsigned 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,
> +                             u32 iface, u32 ctrl_mask, u32 objno)
> +{
> +     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, objno, D_CAN_IF_CMD_CONTROL);
> +}
> +
> +static void d_can_handle_lost_msg_obj(struct net_device *dev,
> +                                     u32 iface, u32 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_clear_bit(priv, D_CAN_IFMCTL(iface), D_CAN_IF_MCTL_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, u32 iface, u32 ctrl)
> +{
> +     unsigned int arb_val, mctl_val;
> +     struct d_can_priv *priv = netdev_priv(dev);
> +     struct net_device_stats *stats = &dev->stats;
> +     struct can_frame *frame;
> +     struct sk_buff *skb;
> +     u32 data = 0;
> +
> +     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 {
> +             data = d_can_read(priv, D_CAN_IFDATA(iface));
> +             /* Writing MO lower 4 data bytes to skb */
> +             *(u32 *)(frame->data) = cpu_to_le32(data);
> +
> +             /* Writing MO higher 4 data bytes to skb */
> +             if (frame->can_dlc > 4) {
> +                     data = d_can_read(priv, D_CAN_IFDATB(iface));
> +                     *(u32 *)(frame->data + 4) = cpu_to_le32(data);
> +             } else
> +                     *(u32 *)(frame->data + 4) = 0;
> +     }
> +
> +     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, u32 iface,
> +                             u32 objno, u32 mask, u32 id, u32 mcont)
> +{
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     d_can_write(priv, D_CAN_IFMCTL(iface), mcont);
> +     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_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, u32 iface, u32 
> 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, u32 
> objno)
> +{
> +     u32 txrq_x_reg_val = D_CAN_GET_XREG_NUM(priv, D_CAN_TXRQ_X);
> +
> +     /* 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 - D_CAN_MSG_OBJ_TX_FIRST)))
> +             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 void 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);
> +}
> +
> +/*
> + * 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_MSG_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);
> +     unsigned long time_out;
> +
> +     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_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_DISABLE_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 */
> +     time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> +     while (!d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) &&
> +                                     time_after(time_out, jiffies))
> +             cpu_relax();
> +
> +     if (time_after(jiffies, time_out)) {
> +             netdev_err(dev, "timedout, D_CAN INIT bit is not set\n");
> +             return;
> +     }
> +
> +     /* 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 */
> +     time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> +     while (d_can_get_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT) &&
> +                                     time_after(time_out, jiffies))
> +             cpu_relax();
> +
> +     if (time_after(jiffies, time_out)) {
> +             netdev_err(dev, "timedout, D_CAN INIT bit is not cleared\n");
> +             return;
> +     }
> +
> +     if (priv->can.ctrlmode & (CAN_CTRLMODE_LOOPBACK |
> +                             CAN_CTRLMODE_LISTENONLY))
> +             d_can_test_mode(dev);
> +     else
> +             d_can_write(priv, D_CAN_CTL, D_CAN_CTL_EIE | D_CAN_CTL_IE1 |
> +                                     D_CAN_CTL_SIE | D_CAN_CTL_IE0);
> +
> +     /* 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, D_CAN_ENABLE_ALL_INTERRUPTS);
> +}
> +
> +static void d_can_stop(struct net_device *dev)
> +{
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     d_can_interrupts(priv, D_CAN_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 err_cnt;
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     err_cnt = d_can_read(priv, D_CAN_ERRC);
> +     bec->rxerr = (err_cnt & D_CAN_ERRC_REC_MASK) >> D_CAN_ERRC_REC_SHIFT;
> +     bec->txerr = err_cnt & D_CAN_ERRC_TEC_MASK;
> +
> +     return 0;
> +}
> +
> +/*
> + * 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 packet, 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 -
> +                                             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,
> +                                     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);
> +}
> +
> +/*
> + * 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_objs(dev,
> +                                             D_CAN_IF_RX_NUM, mctrl_reg_val);
> +
> +                     num_rx_pkts++;
> +                     quota--;
> +             }
> +     }
> +     return num_rx_pkts;
> +}
> +
> +static inline int d_can_has_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 err_cnt;
> +     unsigned int rx_epass;
> +     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);
> +     err_cnt = d_can_read(priv, D_CAN_ERRC);
> +     rx_epass = err_cnt & D_CAN_ERRC_RP_MASK;
> +
> +     switch (error_type) {
> +     case 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 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_epass)
> +                     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 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, D_CAN_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;
> +
> +     /* 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 work_done = 0;
> +     int lec_type = 0;
> +     struct net_device *dev = napi->dev;
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     if (!priv->irqstatus)
> +             goto end;
> +
> +     /* status events have the highest priority */
> +     if (priv->irqstatus == D_CAN_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,
> +                                             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,
> +                                             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, 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_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);
> +             d_can_interrupts(priv, D_CAN_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, D_CAN_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;
> +     }
> +
> +     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;
> +     }
> +
> +     /* start the d_can controller */
> +     d_can_start(ndev);
> +     napi_enable(&priv->napi);
> +     netif_start_queue(ndev);
> +     priv->is_opened = true;
> +
> +     return 0;
> +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);
> +     close_candev(ndev);
> +     priv->is_opened = false;
> +
> +     return 0;
> +}
> +
> +static void d_can_reset_ram(struct d_can_priv *d_can, unsigned int instance,
> +                                     unsigned int enable)
> +{
> +     if (d_can->ram_init)
> +             d_can->ram_init(instance, enable);
> +     /* Give some time delay for DCAN RAM initialization */
> +     udelay(1);
> +}
> +
> +static struct net_device *alloc_d_can_dev(unsigned 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;
> +}
> +
> +static void free_d_can_dev(struct net_device *dev)
> +{
> +     free_candev(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,
> +};
> +
> +static 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);
> +}
> +
> +static void unregister_d_can_dev(struct net_device *dev)
> +{
> +     struct d_can_priv *priv = netdev_priv(dev);
> +
> +     d_can_interrupts(priv, D_CAN_DISABLE_ALL_INTERRUPTS);
> +     unregister_candev(dev);
> +}
> +
> +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, *irq;
> +     struct d_can_platform_data *pdata;
> +     struct clk *fck;
> +
> +     pdata = pdev->dev.platform_data;
> +     if (!pdata) {
> +             dev_err(&pdev->dev, "No platform data\n");
> +             goto exit;
> +     }
> +
> +     /* 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;
> +     }
> +     irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "d_can_ms");
> +     if (!irq) {
> +             dev_err(&pdev->dev, "No irq resource\n");
> +             goto exit;
> +     }
> +     if (!request_mem_region(mem->start, resource_size(mem),
> +                             D_CAN_DRV_NAME)) {
> +             dev_err(&pdev->dev, "resource unavailable\n");
> +             ret = -EBUSY;
> +             goto exit;
> +     }
> +     addr = ioremap(mem->start, resource_size(mem));
> +     if (!addr) {
> +             dev_err(&pdev->dev, "ioremap failed\n");
> +             ret = -ENOMEM;
> +             goto exit_release_mem;
> +     }
> +
> +     /* allocate the d_can device */
> +     ndev = alloc_d_can_dev(pdata->num_of_msg_objs);
> +     if (!ndev) {
> +             dev_err(&pdev->dev, "alloc_d_can_dev failed\n");
> +             ret = -ENOMEM;
> +             goto exit_iounmap;
> +     }
> +     fck = clk_get(&pdev->dev, "fck");
> +     if (IS_ERR(fck)) {
> +             dev_err(&pdev->dev, "fck is not found\n");
> +             ret = -ENODEV;
> +             goto exit_free_ndev;
> +     }
> +
> +     priv = netdev_priv(ndev);
> +     priv->base = addr;
> +     priv->can.clock.freq = clk_get_rate(fck);
> +     priv->ram_init = pdata->ram_init;
> +     priv->is_opened = false;
> +
> +     ndev->irq = irq->start;
> +     platform_set_drvdata(pdev, ndev);
> +     SET_NETDEV_DEV(ndev, &pdev->dev);
> +
> +     pm_runtime_enable(&pdev->dev);
> +     pm_runtime_get_sync(&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;
> +     }
> +
> +     /* Initialize DCAN RAM */
> +     d_can_reset_ram(priv, pdev->id, 1);
> +
> +     dev_info(&pdev->dev, "device registered (irq = %d)\n", ndev->irq);
> +     return 0;
> +exit_free_device:
> +     platform_set_drvdata(pdev, NULL);
> +     pm_runtime_disable(&pdev->dev);
> +     clk_put(fck);
> +exit_free_ndev:
> +     free_d_can_dev(ndev);
> +exit_iounmap:
> +     iounmap(addr);
> +exit_release_mem:
> +     release_mem_region(mem->start, resource_size(mem));
> +exit:
> +     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;
> +
> +     d_can_reset_ram(priv, pdev->id, 0);
> +
> +     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));
> +
> +     pm_runtime_put_sync(&pdev->dev);
> +     pm_runtime_disable(&pdev->dev);
> +
> +     return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int d_can_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +     unsigned long time_out;
> +     struct net_device *ndev = platform_get_drvdata(pdev);
> +     struct d_can_priv *priv = netdev_priv(ndev);
> +
> +     if (netif_running(ndev)) {
> +             netif_stop_queue(ndev);
> +             netif_device_detach(ndev);
> +     }
> +
> +     d_can_set_bit(priv, D_CAN_CTL, D_CAN_CTL_PDR);
> +
> +     /* PDA bit will become high only when all the pending
> +      * transfers are completed */
> +     time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> +     while (!d_can_get_bit(priv, D_CAN_ES, D_CAN_ES_PDA) &&
> +                             time_after(time_out, jiffies))
> +             cpu_relax();
> +
> +     if (time_after(jiffies, time_out)) {
> +             netdev_err(ndev, "Not entered power down mode\n");
> +             return -ETIMEDOUT;
> +     }
> +
> +     if (priv->is_opened)
> +             d_can_stop(ndev);
> +
> +     priv->can.state = CAN_STATE_SLEEPING;
> +     /* De-initialize DCAN RAM */
> +     d_can_reset_ram(priv, pdev->id, 0);
> +     /* Disable the module */
> +     pm_runtime_put_sync(&pdev->dev);
> +     return 0;
> +}
> +
> +static int d_can_resume(struct platform_device *pdev)
> +{
> +     unsigned long time_out;
> +     struct net_device *ndev = platform_get_drvdata(pdev);
> +     struct d_can_priv *priv = netdev_priv(ndev);
> +
> +     /* Enable the module */
> +     pm_runtime_get_sync(&pdev->dev);
> +     /* Initialize DCAN RAM */
> +     d_can_reset_ram(priv, pdev->id, 1);
> +
> +     /* Brought back from power down mode */
> +     d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_PDR);
> +     d_can_clear_bit(priv, D_CAN_CTL, D_CAN_CTL_INIT);
> +
> +     /* Wait for the PDA bit to get clear */
> +     time_out = jiffies + msecs_to_jiffies(D_CAN_TIMEOUT_MS);
> +     while (d_can_get_bit(priv, D_CAN_ES, D_CAN_ES_PDA) &&
> +                             time_after(time_out, jiffies))
> +             cpu_relax();
> +
> +     if (time_after(jiffies, time_out)) {
> +             netdev_err(ndev, "Not came out from power down mode\n");
> +             return -ETIMEDOUT;
> +     }
> +
> +     if (priv->is_opened)
> +             d_can_start(ndev);
> +
> +     priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> +     if (netif_running(ndev)) {
> +             netif_device_attach(ndev);
> +             netif_start_queue(ndev);
> +     }
> +     return 0;
> +}
> +#else
> +#define d_can_suspend NULL
> +#define d_can_resume NULL
> +#endif
> +
> +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),
> +     .suspend        = d_can_suspend,
> +     .resume         = d_can_resume,
> +};
> +
> +static int __init d_can_plat_init(void)
> +{
> +     return platform_driver_register(&d_can_plat_driver);
> +}
> +module_init(d_can_plat_init);
> +
> +static void __exit d_can_plat_exit(void)
> +{
> +     platform_driver_unregister(&d_can_plat_driver);
> +}
> +module_exit(d_can_plat_exit);
> +
> +MODULE_AUTHOR("AnilKumar Ch <anilku...@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..b6f2a3f
> --- /dev/null
> +++ b/include/linux/can/platform/d_can.h
> @@ -0,0 +1,40 @@
> +/*
> + * D_CAN controller driver platform header
> + *
> + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.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.
> + */
> +
> +#ifndef __CAN_PLATFORM_TI_D_CAN_H__
> +#define __CAN_PLATFORM_TI_D_CAN_H__
> +
> +/**
> + * struct d_can_platform_data - DCAN Platform Data
> + *
> + * @num_of_msg_objs: Number of message objects
> + * @dma_support:     DMA support is required/not
> + * @ram_init:                DCAN RAM initialization
> + *
> + * 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 {
> +     unsigned int num_of_msg_objs;
> +     bool dma_support;
> +     void (*ram_init) (unsigned int instance, unsigned int eanble);
> +};
> +#endif

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to