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 <anilkumar@xxxxxx> 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.sharma@xxxxxx> > + * > + * Borrowed heavily from the C_CAN driver originally written by: > + * Copyright (C) 2007 > + * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@xxxxxxxxxxxxxx> > + * - Simon Kallweit, intefo AG <simon.kallweit@xxxxxxxxx> > + * > + * 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 <anilkumar@xxxxxx>"); > +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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html