All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai] RT-CAN driver for C_CAN,D_CAN cores ready
@ 2015-04-28 15:47 Michael Haberler
  2015-04-28 16:02 ` Gilles Chanteperdrix
  2015-04-29  7:05 ` Wolfgang Grandegger
  0 siblings, 2 replies; 10+ messages in thread
From: Michael Haberler @ 2015-04-28 15:47 UTC (permalink / raw)
  To: xenomai

as requested:


>From 84badf976ed149a352cbb34edc329685aaacb531 Mon Sep 17 00:00:00 2001
From: Michael Haberler <git@mah.priv.at>
Date: Tue, 7 Apr 2015 08:04:36 +0200
Subject: [PATCH 1/3] as from 3.8

---
 c_can/Kconfig          |   23 +
 c_can/Makefile         |    9 +
 c_can/c_can.c          | 1292
++++++++++++++++++++++++++++++++++++++++++++++++
 c_can/c_can.h          |  187 +++++++
 c_can/c_can_pci.c      |  221 +++++++++
 c_can/c_can_platform.c |  347 +++++++++++++
 6 files changed, 2079 insertions(+)
 create mode 100644 c_can/Kconfig
 create mode 100644 c_can/Makefile
 create mode 100644 c_can/c_can.c
 create mode 100644 c_can/c_can.h
 create mode 100644 c_can/c_can_pci.c
 create mode 100644 c_can/c_can_platform.c

diff --git a/c_can/Kconfig b/c_can/Kconfig
new file mode 100644
index 0000000..3b83baf
--- /dev/null
+++ b/c_can/Kconfig
@@ -0,0 +1,23 @@
+menuconfig CAN_C_CAN
+ tristate "Bosch C_CAN/D_CAN devices"
+ depends on CAN_DEV && HAS_IOMEM
+
+if CAN_C_CAN
+
+config CAN_C_CAN_PLATFORM
+ tristate "Generic Platform Bus based C_CAN/D_CAN driver"
+ ---help---
+  This driver adds support for the C_CAN/D_CAN chips connected
+  to the "platform bus" (Linux abstraction for directly to the
+  processor attached devices) which can be found on various
+  boards from ST Microelectronics (http://www.st.com) like the
+  SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com)
+  boards like am335x, dm814x, dm813x and dm811x.
+
+config CAN_C_CAN_PCI
+ tristate "Generic PCI Bus based C_CAN/D_CAN driver"
+ depends on PCI
+ ---help---
+  This driver adds support for the C_CAN/D_CAN chips connected
+  to the PCI bus.
+endif
diff --git a/c_can/Makefile b/c_can/Makefile
new file mode 100644
index 0000000..ad1cc84
--- /dev/null
+++ b/c_can/Makefile
@@ -0,0 +1,9 @@
+#
+#  Makefile for the Bosch C_CAN controller drivers.
+#
+
+obj-$(CONFIG_CAN_C_CAN) += c_can.o
+obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
+obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/c_can/c_can.c b/c_can/c_can.c
new file mode 100644
index 0000000..2282b1a
--- /dev/null
+++ b/c_can/c_can.c
@@ -0,0 +1,1292 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * TX and RX NAPI implementation has been borrowed from at91 CAN driver
+ * written by:
+ * Copyright
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
+ * (C) 2008, 2009 by Marc Kleine-Budde <kernel@pengutronix.de>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "c_can.h"
+
+/* Number of interface registers */
+#define IF_ENUM_REG_LEN 11
+#define C_CAN_IFACE(reg, iface) (C_CAN_IF1_##reg + (iface) *
IF_ENUM_REG_LEN)
+
+/* control extension register D_CAN specific */
+#define CONTROL_EX_PDR BIT(8)
+
+/* control register */
+#define CONTROL_TEST BIT(7)
+#define CONTROL_CCE BIT(6)
+#define CONTROL_DISABLE_AR BIT(5)
+#define CONTROL_ENABLE_AR (0 << 5)
+#define CONTROL_EIE BIT(3)
+#define CONTROL_SIE BIT(2)
+#define CONTROL_IE BIT(1)
+#define CONTROL_INIT BIT(0)
+
+/* test register */
+#define TEST_RX BIT(7)
+#define TEST_TX1 BIT(6)
+#define TEST_TX2 BIT(5)
+#define TEST_LBACK BIT(4)
+#define TEST_SILENT BIT(3)
+#define TEST_BASIC BIT(2)
+
+/* status register */
+#define STATUS_PDA BIT(10)
+#define STATUS_BOFF BIT(7)
+#define STATUS_EWARN BIT(6)
+#define STATUS_EPASS BIT(5)
+#define STATUS_RXOK BIT(4)
+#define STATUS_TXOK BIT(3)
+
+/* error counter register */
+#define ERR_CNT_TEC_MASK 0xff
+#define ERR_CNT_TEC_SHIFT 0
+#define ERR_CNT_REC_SHIFT 8
+#define ERR_CNT_REC_MASK (0x7f << ERR_CNT_REC_SHIFT)
+#define ERR_CNT_RP_SHIFT 15
+#define ERR_CNT_RP_MASK (0x1 << ERR_CNT_RP_SHIFT)
+
+/* bit-timing register */
+#define BTR_BRP_MASK 0x3f
+#define BTR_BRP_SHIFT 0
+#define BTR_SJW_SHIFT 6
+#define BTR_SJW_MASK (0x3 << BTR_SJW_SHIFT)
+#define BTR_TSEG1_SHIFT 8
+#define BTR_TSEG1_MASK (0xf << BTR_TSEG1_SHIFT)
+#define BTR_TSEG2_SHIFT 12
+#define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT)
+
+/* brp extension register */
+#define BRP_EXT_BRPE_MASK 0x0f
+#define BRP_EXT_BRPE_SHIFT 0
+
+/* IFx command request */
+#define IF_COMR_BUSY BIT(15)
+
+/* IFx command mask */
+#define IF_COMM_WR BIT(7)
+#define IF_COMM_MASK BIT(6)
+#define IF_COMM_ARB BIT(5)
+#define IF_COMM_CONTROL BIT(4)
+#define IF_COMM_CLR_INT_PND BIT(3)
+#define IF_COMM_TXRQST BIT(2)
+#define IF_COMM_DATAA BIT(1)
+#define IF_COMM_DATAB BIT(0)
+#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \
+ IF_COMM_CONTROL | IF_COMM_TXRQST | \
+ IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* IFx arbitration */
+#define IF_ARB_MSGVAL BIT(15)
+#define IF_ARB_MSGXTD BIT(14)
+#define IF_ARB_TRANSMIT BIT(13)
+
+/* IFx message control */
+#define IF_MCONT_NEWDAT BIT(15)
+#define IF_MCONT_MSGLST BIT(14)
+#define IF_MCONT_CLR_MSGLST (0 << 14)
+#define IF_MCONT_INTPND BIT(13)
+#define IF_MCONT_UMASK BIT(12)
+#define IF_MCONT_TXIE BIT(11)
+#define IF_MCONT_RXIE BIT(10)
+#define IF_MCONT_RMTEN BIT(9)
+#define IF_MCONT_TXRQST BIT(8)
+#define IF_MCONT_EOB BIT(7)
+#define IF_MCONT_DLC_MASK 0xf
+
+/*
+ * IFx register masks:
+ * allow easy operation on 16-bit registers when the
+ * argument is 32-bit instead
+ */
+#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
+#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
+
+/* message object split */
+#define C_CAN_NO_OF_OBJECTS 32
+#define C_CAN_MSG_OBJ_RX_NUM 16
+#define C_CAN_MSG_OBJ_TX_NUM 16
+
+#define C_CAN_MSG_OBJ_RX_FIRST 1
+#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
+ C_CAN_MSG_OBJ_RX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
+#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
+ C_CAN_MSG_OBJ_TX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_RX_SPLIT 9
+#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
+
+#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
+#define RECEIVE_OBJECT_BITS 0x0000ffff
+
+/* status interrupt */
+#define STATUS_INTERRUPT 0x8000
+
+/* global interrupt masks */
+#define ENABLE_ALL_INTERRUPTS 1
+#define DISABLE_ALL_INTERRUPTS 0
+
+/* minimum timeout for checking BUSY status */
+#define MIN_TIMEOUT_VALUE 6
+
+/* Wait for ~1 sec for INIT bit */
+#define INIT_WAIT_MS 1000
+
+/* napi related */
+#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
+
+/* c_can lec values */
+enum c_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,
+};
+
+/*
+ * c_can error types:
+ * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
+ */
+enum c_can_bus_error_types {
+ C_CAN_NO_ERROR = 0,
+ C_CAN_BUS_OFF,
+ C_CAN_ERROR_WARNING,
+ C_CAN_ERROR_PASSIVE,
+};
+
+static const struct can_bittiming_const c_can_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* 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,
+};
+
+static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_enable(priv->device);
+}
+
+static inline void c_can_pm_runtime_disable(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_disable(priv->device);
+}
+
+static inline void c_can_pm_runtime_get_sync(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_get_sync(priv->device);
+}
+
+static inline void c_can_pm_runtime_put_sync(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_put_sync(priv->device);
+}
+
+static inline void c_can_reset_ram(const struct c_can_priv *priv, bool
enable)
+{
+ if (priv->raminit)
+ priv->raminit(priv, enable);
+}
+
+static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
+{
+ return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
+ C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
+{
+ return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
+ C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
+{
+ u32 val = priv->read_reg(priv, index);
+ val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
+ return val;
+}
+
+static void c_can_enable_all_interrupts(struct c_can_priv *priv,
+ int enable)
+{
+ unsigned int cntrl_save = priv->read_reg(priv,
+ C_CAN_CTRL_REG);
+
+ if (enable)
+ cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
+ else
+ cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
+
+ priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save);
+}
+
+static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
+{
+ int count = MIN_TIMEOUT_VALUE;
+
+ while (count && priv->read_reg(priv,
+ C_CAN_IFACE(COMREQ_REG, iface)) &
+ IF_COMR_BUSY) {
+ count--;
+ udelay(1);
+ }
+
+ if (!count)
+ return 1;
+
+ return 0;
+}
+
+static inline void c_can_object_get(struct net_device *dev,
+ int iface, int objno, int mask)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /*
+ * As per specs, after writting the message object number in the
+ * IF command request register the transfer b/w interface
+ * register and message RAM must be complete in 6 CAN-CLK
+ * period.
+ */
+ priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
+ IFX_WRITE_LOW_16BIT(mask));
+ priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
+ IFX_WRITE_LOW_16BIT(objno));
+
+ if (c_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object get\n");
+}
+
+static inline void c_can_object_put(struct net_device *dev,
+ int iface, int objno, int mask)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /*
+ * As per specs, after writting the message object number in the
+ * IF command request register the transfer b/w interface
+ * register and message RAM must be complete in 6 CAN-CLK
+ * period.
+ */
+ priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
+ (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
+ priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
+ IFX_WRITE_LOW_16BIT(objno));
+
+ if (c_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object put\n");
+}
+
+static void c_can_write_msg_object(struct net_device *dev,
+ int iface, struct can_frame *frame, int objno)
+{
+ int i;
+ u16 flags = 0;
+ unsigned int id;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(frame->can_id & CAN_RTR_FLAG))
+ flags |= IF_ARB_TRANSMIT;
+
+ if (frame->can_id & CAN_EFF_FLAG) {
+ id = frame->can_id & CAN_EFF_MASK;
+ flags |= IF_ARB_MSGXTD;
+ } else
+ id = ((frame->can_id & CAN_SFF_MASK) << 18);
+
+ flags |= IF_ARB_MSGVAL;
+
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
+ IFX_WRITE_LOW_16BIT(id));
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags |
+ IFX_WRITE_HIGH_16BIT(id));
+
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
+ frame->data[i] | (frame->data[i + 1] << 8));
+ }
+
+ /* enable interrupt for this message object */
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
+ frame->can_dlc);
+ c_can_object_put(dev, iface, objno, IF_COMM_ALL);
+}
+
+static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
+ int iface, int ctrl_mask,
+ int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
+ c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+
+}
+
+static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device
*dev,
+ int iface,
+ int ctrl_mask)
+{
+ int i;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ ctrl_mask & ~(IF_MCONT_MSGLST |
+ IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
+ }
+}
+
+static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
+ int iface, int ctrl_mask,
+ int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ ctrl_mask & ~(IF_MCONT_MSGLST |
+ IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+}
+
+static void c_can_handle_lost_msg_obj(struct net_device *dev,
+ int iface, int objno)
+{
+ struct c_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);
+
+ c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ IF_MCONT_CLR_MSGLST);
+
+ c_can_object_put(dev, 0, objno, IF_COMM_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 c_can_read_msg_object(struct net_device *dev, int iface, int
ctrl)
+{
+ u16 flags, data;
+ int i;
+ unsigned int val;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ skb = alloc_can_skb(dev, &frame);
+ if (!skb) {
+ stats->rx_dropped++;
+ return -ENOMEM;
+ }
+
+ frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+
+ flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
+ val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
+ (flags << 16);
+
+ if (flags & IF_ARB_MSGXTD)
+ frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ frame->can_id = (val >> 18) & CAN_SFF_MASK;
+
+ if (flags & IF_ARB_TRANSMIT)
+ frame->can_id |= CAN_RTR_FLAG;
+ else {
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ data = priv->read_reg(priv,
+ C_CAN_IFACE(DATA1_REG, iface) + i / 2);
+ frame->data[i] = data;
+ frame->data[i + 1] = data >> 8;
+ }
+ }
+
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += frame->can_dlc;
+
+ return 0;
+}
+
+static void c_can_setup_receive_object(struct net_device *dev, int iface,
+ int objno, unsigned int mask,
+ unsigned int id, unsigned int mcont)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
+ IFX_WRITE_LOW_16BIT(mask));
+
+ /* According to C_CAN documentation, the reserved bit
+ * in IFx_MASK2 register is fixed 1
+ */
+ priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
+ IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
+
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
+ IFX_WRITE_LOW_16BIT(id));
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface),
+ (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
+ c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
+ c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
+}
+
+static void c_can_inval_msg_object(struct net_device *dev, int iface, int
objno)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
+
+ c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
+ c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
+}
+
+static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int
objno)
+{
+ int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
+
+ /*
+ * as transmission request register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (val & (1 << (objno - 1)))
+ return 1;
+
+ return 0;
+}
+
+static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ u32 msg_obj_no;
+ struct c_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 */
+ c_can_write_msg_object(dev, 0, frame, msg_obj_no);
+ can_put_echo_skb(skb, dev, msg_obj_no - C_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 (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
+ (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
+ netif_stop_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static int c_can_set_bittiming(struct net_device *dev)
+{
+ unsigned int reg_btr, reg_brpe, ctrl_save;
+ u8 brp, brpe, sjw, tseg1, tseg2;
+ u32 ten_bit_brp;
+ struct c_can_priv *priv = netdev_priv(dev);
+ const struct can_bittiming *bt = &priv->can.bittiming;
+
+ /* c_can provides a 6-bit brp and 4-bit brpe fields */
+ ten_bit_brp = bt->brp - 1;
+ brp = ten_bit_brp & BTR_BRP_MASK;
+ brpe = ten_bit_brp >> 6;
+
+ sjw = bt->sjw - 1;
+ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+ reg_btr = brp | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
+ (tseg2 << BTR_TSEG2_SHIFT);
+ reg_brpe = brpe & BRP_EXT_BRPE_MASK;
+
+ netdev_info(dev,
+ "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
+
+ ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
+ priv->write_reg(priv, C_CAN_CTRL_REG,
+ ctrl_save | CONTROL_CCE | CONTROL_INIT);
+ priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
+ priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
+ priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
+
+ return 0;
+}
+
+/*
+ * Configure C_CAN message objects for Tx and Rx purposes:
+ * C_CAN provides a total of 32 message objects that can be configured
+ * either for Tx or Rx purposes. Here the first 16 message objects are
used as
+ * a reception FIFO. The end of reception FIFO is signified by the EoB bit
+ * being SET. The remaining 16 message objects are kept aside for Tx
purposes.
+ * See user guide document for further details on configuring message
+ * objects.
+ */
+static void c_can_configure_msg_objects(struct net_device *dev)
+{
+ int i;
+
+ /* first invalidate all message objects */
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
+ c_can_inval_msg_object(dev, 0, i);
+
+ /* setup receive message objects */
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
+ c_can_setup_receive_object(dev, 0, i, 0, 0,
+ (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
+
+ c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
+ IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
+}
+
+/*
+ * Configure C_CAN chip:
+ * - enable/disable auto-retransmission
+ * - set operating mode
+ * - configure message objects
+ */
+static void c_can_chip_config(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* enable automatic retransmission */
+ priv->write_reg(priv, C_CAN_CTRL_REG,
+ CONTROL_ENABLE_AR);
+
+ if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
+    (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
+ /* loopback + silent mode : useful for hot self-test */
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG,
+ TEST_LBACK | TEST_SILENT);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ /* loopback mode : useful for self-test function */
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ /* silent mode : bus-monitoring mode */
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
+ } else
+ /* normal mode*/
+ priv->write_reg(priv, C_CAN_CTRL_REG,
+ CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
+
+ /* configure message objects */
+ c_can_configure_msg_objects(dev);
+
+ /* set a `lec` value so that we can check for updates later */
+ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+
+ /* set bittiming params */
+ c_can_set_bittiming(dev);
+}
+
+static void c_can_start(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* basic c_can configuration */
+ c_can_chip_config(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 */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+}
+
+static void c_can_stop(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* disable all interrupts */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+ /* set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ c_can_start(dev);
+ netif_wake_queue(dev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int c_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ unsigned int reg_err_counter;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ c_can_pm_runtime_get_sync(priv);
+
+ reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
+ bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
+ ERR_CNT_REC_SHIFT;
+ bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
+
+ c_can_pm_runtime_put_sync(priv);
+
+ return 0;
+}
+
+/*
+ * theory of operation:
+ *
+ * priv->tx_echo holds the number of the oldest can_frame put for
+ * transmission into the hardware, but not yet ACKed by the CAN tx
+ * complete IRQ.
+ *
+ * We iterate from priv->tx_echo to priv->tx_next and check if the
+ * packet has been transmitted, echo it back to the CAN framework.
+ * If we discover a not yet transmitted packet, stop looking for more.
+ */
+static void c_can_do_tx(struct net_device *dev)
+{
+ u32 val;
+ u32 msg_obj_no;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+
+ for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+ msg_obj_no = get_tx_echo_msg_obj(priv);
+ val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
+ if (!(val & (1 << (msg_obj_no - 1)))) {
+ can_get_echo_skb(dev,
+ msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+ stats->tx_bytes += priv->read_reg(priv,
+ C_CAN_IFACE(MSGCTRL_REG, 0))
+ & IF_MCONT_DLC_MASK;
+ stats->tx_packets++;
+ c_can_inval_msg_object(dev, 0, msg_obj_no);
+ } else {
+ break;
+ }
+ }
+
+ /* restart queue if wrap-up or if queue stalled on last pkt */
+ if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
+ ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
+ netif_wake_queue(dev);
+}
+
+/*
+ * theory of operation:
+ *
+ * c_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 C_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
+ *   C_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
+ *   C_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
+ *   C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
+ *   only this message object.
+ */
+static int c_can_do_rx_poll(struct net_device *dev, int quota)
+{
+ u32 num_rx_pkts = 0;
+ unsigned int msg_obj, msg_ctrl_save;
+ struct c_can_priv *priv = netdev_priv(dev);
+ u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG);
+
+ for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
+ msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
+ val = c_can_read_reg32(priv, C_CAN_INTPND1_REG),
+ msg_obj++) {
+ /*
+ * as interrupt pending register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (val & (1 << (msg_obj - 1))) {
+ c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
+ ~IF_COMM_TXRQST);
+ msg_ctrl_save = priv->read_reg(priv,
+ C_CAN_IFACE(MSGCTRL_REG, 0));
+
+ if (msg_ctrl_save & IF_MCONT_EOB)
+ return num_rx_pkts;
+
+ if (msg_ctrl_save & IF_MCONT_MSGLST) {
+ c_can_handle_lost_msg_obj(dev, 0, msg_obj);
+ num_rx_pkts++;
+ quota--;
+ continue;
+ }
+
+ if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
+ continue;
+
+ /* read the data from the message object */
+ c_can_read_msg_object(dev, 0, msg_ctrl_save);
+
+ if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
+ c_can_mark_rx_msg_obj(dev, 0,
+ msg_ctrl_save, msg_obj);
+ else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
+ /* activate this msg obj */
+ c_can_activate_rx_msg_obj(dev, 0,
+ msg_ctrl_save, msg_obj);
+ else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
+ /* activate all lower message objects */
+ c_can_activate_all_lower_rx_msg_obj(dev,
+ 0, msg_ctrl_save);
+
+ num_rx_pkts++;
+ quota--;
+ }
+ }
+
+ return num_rx_pkts;
+}
+
+static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
+{
+ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+ (priv->current_status & LEC_UNUSED);
+}
+
+static int c_can_handle_state_change(struct net_device *dev,
+ enum c_can_bus_error_types error_type)
+{
+ unsigned int reg_err_counter;
+ unsigned int rx_err_passive;
+ struct c_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;
+
+ c_can_get_berr_counter(dev, &bec);
+ reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
+ rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
+ ERR_CNT_RP_SHIFT;
+
+ switch (error_type) {
+ case C_CAN_ERROR_WARNING:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+
+ break;
+ case C_CAN_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (rx_err_passive)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case C_CAN_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ /*
+ * disable all interrupts in bus-off mode to ensure that
+ * the CPU is not hogged down
+ */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int c_can_handle_bus_err(struct net_device *dev,
+ enum c_can_lec_type lec_type)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /*
+ * early exit if no lec update or no error.
+ * no lec update means that no CAN bus event has been detected
+ * since CPU wrote 0x7 value to status reg.
+ */
+ if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
+ return 0;
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ /*
+ * check for 'last error code' which tells us the
+ * type of the last error to occur on the CAN bus
+ */
+
+ /* common for all type of bus errors */
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+ switch (lec_type) {
+ case LEC_STUFF_ERROR:
+ netdev_dbg(dev, "stuff error\n");
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ case LEC_FORM_ERROR:
+ netdev_dbg(dev, "form error\n");
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case LEC_ACK_ERROR:
+ netdev_dbg(dev, "ack error\n");
+ cf->data[3] |= (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[3] |= (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 */
+ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int c_can_poll(struct napi_struct *napi, int quota)
+{
+ u16 irqstatus;
+ int lec_type = 0;
+ int work_done = 0;
+ struct net_device *dev = napi->dev;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ irqstatus = priv->irqstatus;
+ if (!irqstatus)
+ goto end;
+
+ /* status events have the highest priority */
+ if (irqstatus == STATUS_INTERRUPT) {
+ priv->current_status = priv->read_reg(priv,
+ C_CAN_STS_REG);
+
+ /* handle Tx/Rx events */
+ if (priv->current_status & STATUS_TXOK)
+ priv->write_reg(priv, C_CAN_STS_REG,
+ priv->current_status & ~STATUS_TXOK);
+
+ if (priv->current_status & STATUS_RXOK)
+ priv->write_reg(priv, C_CAN_STS_REG,
+ priv->current_status & ~STATUS_RXOK);
+
+ /* handle state changes */
+ if ((priv->current_status & STATUS_EWARN) &&
+ (!(priv->last_status & STATUS_EWARN))) {
+ netdev_dbg(dev, "entered error warning state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_ERROR_WARNING);
+ }
+ if ((priv->current_status & STATUS_EPASS) &&
+ (!(priv->last_status & STATUS_EPASS))) {
+ netdev_dbg(dev, "entered error passive state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_ERROR_PASSIVE);
+ }
+ if ((priv->current_status & STATUS_BOFF) &&
+ (!(priv->last_status & STATUS_BOFF))) {
+ netdev_dbg(dev, "entered bus off state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_BUS_OFF);
+ }
+
+ /* handle bus recovery events */
+ if ((!(priv->current_status & STATUS_BOFF)) &&
+ (priv->last_status & STATUS_BOFF)) {
+ netdev_dbg(dev, "left bus off state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ if ((!(priv->current_status & STATUS_EPASS)) &&
+ (priv->last_status & STATUS_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 = c_can_has_and_handle_berr(priv);
+ if (lec_type)
+ work_done += c_can_handle_bus_err(dev, lec_type);
+ } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
+ (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
+ /* handle events corresponding to receive message objects */
+ work_done += c_can_do_rx_poll(dev, (quota - work_done));
+ } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
+ (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
+ /* handle events corresponding to transmit message objects */
+ c_can_do_tx(dev);
+ }
+
+end:
+ if (work_done < quota) {
+ napi_complete(napi);
+ /* enable all IRQs */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t c_can_isr(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
+ if (!priv->irqstatus)
+ return IRQ_NONE;
+
+ /* disable all interrupts and schedule the NAPI */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int c_can_open(struct net_device *dev)
+{
+ int err;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
+
+ /* open the can device */
+ err = open_candev(dev);
+ if (err) {
+ netdev_err(dev, "failed to open can device\n");
+ goto exit_open_fail;
+ }
+
+ /* register interrupt handler */
+ err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
+ dev);
+ if (err < 0) {
+ netdev_err(dev, "failed to request interrupt\n");
+ goto exit_irq_fail;
+ }
+
+ napi_enable(&priv->napi);
+
+ /* start the c_can controller */
+ c_can_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+exit_irq_fail:
+ close_candev(dev);
+exit_open_fail:
+ c_can_reset_ram(priv, false);
+ c_can_pm_runtime_put_sync(priv);
+ return err;
+}
+
+static int c_can_close(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+ c_can_stop(dev);
+ free_irq(dev->irq, dev);
+ close_candev(dev);
+
+ c_can_reset_ram(priv, false);
+ c_can_pm_runtime_put_sync(priv);
+
+ return 0;
+}
+
+struct net_device *alloc_c_can_dev(void)
+{
+ struct net_device *dev;
+ struct c_can_priv *priv;
+
+ dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
+ if (!dev)
+ return NULL;
+
+ priv = netdev_priv(dev);
+ netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
+
+ priv->dev = dev;
+ priv->can.bittiming_const = &c_can_bittiming_const;
+ priv->can.do_set_mode = c_can_set_mode;
+ priv->can.do_get_berr_counter = c_can_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_BERR_REPORTING;
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_c_can_dev);
+
+#ifdef CONFIG_PM
+int c_can_power_down(struct net_device *dev)
+{
+ u32 val;
+ unsigned long time_out;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(dev->flags & IFF_UP))
+ return 0;
+
+ WARN_ON(priv->type != BOSCH_D_CAN);
+
+ /* set PDR value so the device goes to power down mode */
+ val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
+ val |= CONTROL_EX_PDR;
+ priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
+
+ /* Wait for the PDA bit to get set */
+ time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
+ while (!(priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out))
+ return -ETIMEDOUT;
+
+ c_can_stop(dev);
+
+ c_can_reset_ram(priv, false);
+ c_can_pm_runtime_put_sync(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(c_can_power_down);
+
+int c_can_power_up(struct net_device *dev)
+{
+ u32 val;
+ unsigned long time_out;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(dev->flags & IFF_UP))
+ return 0;
+
+ WARN_ON(priv->type != BOSCH_D_CAN);
+
+ c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
+
+ /* Clear PDR and INIT bits */
+ val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
+ val &= ~CONTROL_EX_PDR;
+ priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
+ val = priv->read_reg(priv, C_CAN_CTRL_REG);
+ val &= ~CONTROL_INIT;
+ priv->write_reg(priv, C_CAN_CTRL_REG, val);
+
+ /* Wait for the PDA bit to get clear */
+ time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
+ while ((priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out))
+ return -ETIMEDOUT;
+
+ c_can_start(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(c_can_power_up);
+#endif
+
+void free_c_can_dev(struct net_device *dev)
+{
+ free_candev(dev);
+}
+EXPORT_SYMBOL_GPL(free_c_can_dev);
+
+static const struct net_device_ops c_can_netdev_ops = {
+ .ndo_open = c_can_open,
+ .ndo_stop = c_can_close,
+ .ndo_start_xmit = c_can_start_xmit,
+};
+
+int register_c_can_dev(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ int err;
+
+ c_can_pm_runtime_enable(priv);
+
+ dev->flags |= IFF_ECHO; /* we support local echo */
+ dev->netdev_ops = &c_can_netdev_ops;
+
+ err = register_candev(dev);
+ if (err)
+ c_can_pm_runtime_disable(priv);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_c_can_dev);
+
+void unregister_c_can_dev(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ unregister_candev(dev);
+
+ c_can_pm_runtime_disable(priv);
+}
+EXPORT_SYMBOL_GPL(unregister_c_can_dev);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
diff --git a/c_can/c_can.h b/c_can/c_can.h
new file mode 100644
index 0000000..d2e1c21
--- /dev/null
+++ b/c_can/c_can.h
@@ -0,0 +1,187 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef C_CAN_H
+#define C_CAN_H
+
+enum reg {
+ C_CAN_CTRL_REG = 0,
+ C_CAN_CTRL_EX_REG,
+ C_CAN_STS_REG,
+ C_CAN_ERR_CNT_REG,
+ C_CAN_BTR_REG,
+ C_CAN_INT_REG,
+ C_CAN_TEST_REG,
+ C_CAN_BRPEXT_REG,
+ C_CAN_IF1_COMREQ_REG,
+ C_CAN_IF1_COMMSK_REG,
+ C_CAN_IF1_MASK1_REG,
+ C_CAN_IF1_MASK2_REG,
+ C_CAN_IF1_ARB1_REG,
+ C_CAN_IF1_ARB2_REG,
+ C_CAN_IF1_MSGCTRL_REG,
+ C_CAN_IF1_DATA1_REG,
+ C_CAN_IF1_DATA2_REG,
+ C_CAN_IF1_DATA3_REG,
+ C_CAN_IF1_DATA4_REG,
+ C_CAN_IF2_COMREQ_REG,
+ C_CAN_IF2_COMMSK_REG,
+ C_CAN_IF2_MASK1_REG,
+ C_CAN_IF2_MASK2_REG,
+ C_CAN_IF2_ARB1_REG,
+ C_CAN_IF2_ARB2_REG,
+ C_CAN_IF2_MSGCTRL_REG,
+ C_CAN_IF2_DATA1_REG,
+ C_CAN_IF2_DATA2_REG,
+ C_CAN_IF2_DATA3_REG,
+ C_CAN_IF2_DATA4_REG,
+ C_CAN_TXRQST1_REG,
+ C_CAN_TXRQST2_REG,
+ C_CAN_NEWDAT1_REG,
+ C_CAN_NEWDAT2_REG,
+ C_CAN_INTPND1_REG,
+ C_CAN_INTPND2_REG,
+ C_CAN_MSGVAL1_REG,
+ C_CAN_MSGVAL2_REG,
+};
+
+static const u16 reg_map_c_can[] = {
+ [C_CAN_CTRL_REG] = 0x00,
+ [C_CAN_STS_REG] = 0x02,
+ [C_CAN_ERR_CNT_REG] = 0x04,
+ [C_CAN_BTR_REG] = 0x06,
+ [C_CAN_INT_REG] = 0x08,
+ [C_CAN_TEST_REG] = 0x0A,
+ [C_CAN_BRPEXT_REG] = 0x0C,
+ [C_CAN_IF1_COMREQ_REG] = 0x10,
+ [C_CAN_IF1_COMMSK_REG] = 0x12,
+ [C_CAN_IF1_MASK1_REG] = 0x14,
+ [C_CAN_IF1_MASK2_REG] = 0x16,
+ [C_CAN_IF1_ARB1_REG] = 0x18,
+ [C_CAN_IF1_ARB2_REG] = 0x1A,
+ [C_CAN_IF1_MSGCTRL_REG] = 0x1C,
+ [C_CAN_IF1_DATA1_REG] = 0x1E,
+ [C_CAN_IF1_DATA2_REG] = 0x20,
+ [C_CAN_IF1_DATA3_REG] = 0x22,
+ [C_CAN_IF1_DATA4_REG] = 0x24,
+ [C_CAN_IF2_COMREQ_REG] = 0x40,
+ [C_CAN_IF2_COMMSK_REG] = 0x42,
+ [C_CAN_IF2_MASK1_REG] = 0x44,
+ [C_CAN_IF2_MASK2_REG] = 0x46,
+ [C_CAN_IF2_ARB1_REG] = 0x48,
+ [C_CAN_IF2_ARB2_REG] = 0x4A,
+ [C_CAN_IF2_MSGCTRL_REG] = 0x4C,
+ [C_CAN_IF2_DATA1_REG] = 0x4E,
+ [C_CAN_IF2_DATA2_REG] = 0x50,
+ [C_CAN_IF2_DATA3_REG] = 0x52,
+ [C_CAN_IF2_DATA4_REG] = 0x54,
+ [C_CAN_TXRQST1_REG] = 0x80,
+ [C_CAN_TXRQST2_REG] = 0x82,
+ [C_CAN_NEWDAT1_REG] = 0x90,
+ [C_CAN_NEWDAT2_REG] = 0x92,
+ [C_CAN_INTPND1_REG] = 0xA0,
+ [C_CAN_INTPND2_REG] = 0xA2,
+ [C_CAN_MSGVAL1_REG] = 0xB0,
+ [C_CAN_MSGVAL2_REG] = 0xB2,
+};
+
+static const u16 reg_map_d_can[] = {
+ [C_CAN_CTRL_REG] = 0x00,
+ [C_CAN_CTRL_EX_REG] = 0x02,
+ [C_CAN_STS_REG] = 0x04,
+ [C_CAN_ERR_CNT_REG] = 0x08,
+ [C_CAN_BTR_REG] = 0x0C,
+ [C_CAN_BRPEXT_REG] = 0x0E,
+ [C_CAN_INT_REG] = 0x10,
+ [C_CAN_TEST_REG] = 0x14,
+ [C_CAN_TXRQST1_REG] = 0x88,
+ [C_CAN_TXRQST2_REG] = 0x8A,
+ [C_CAN_NEWDAT1_REG] = 0x9C,
+ [C_CAN_NEWDAT2_REG] = 0x9E,
+ [C_CAN_INTPND1_REG] = 0xB0,
+ [C_CAN_INTPND2_REG] = 0xB2,
+ [C_CAN_MSGVAL1_REG] = 0xC4,
+ [C_CAN_MSGVAL2_REG] = 0xC6,
+ [C_CAN_IF1_COMREQ_REG] = 0x100,
+ [C_CAN_IF1_COMMSK_REG] = 0x102,
+ [C_CAN_IF1_MASK1_REG] = 0x104,
+ [C_CAN_IF1_MASK2_REG] = 0x106,
+ [C_CAN_IF1_ARB1_REG] = 0x108,
+ [C_CAN_IF1_ARB2_REG] = 0x10A,
+ [C_CAN_IF1_MSGCTRL_REG] = 0x10C,
+ [C_CAN_IF1_DATA1_REG] = 0x110,
+ [C_CAN_IF1_DATA2_REG] = 0x112,
+ [C_CAN_IF1_DATA3_REG] = 0x114,
+ [C_CAN_IF1_DATA4_REG] = 0x116,
+ [C_CAN_IF2_COMREQ_REG] = 0x120,
+ [C_CAN_IF2_COMMSK_REG] = 0x122,
+ [C_CAN_IF2_MASK1_REG] = 0x124,
+ [C_CAN_IF2_MASK2_REG] = 0x126,
+ [C_CAN_IF2_ARB1_REG] = 0x128,
+ [C_CAN_IF2_ARB2_REG] = 0x12A,
+ [C_CAN_IF2_MSGCTRL_REG] = 0x12C,
+ [C_CAN_IF2_DATA1_REG] = 0x130,
+ [C_CAN_IF2_DATA2_REG] = 0x132,
+ [C_CAN_IF2_DATA3_REG] = 0x134,
+ [C_CAN_IF2_DATA4_REG] = 0x136,
+};
+
+enum c_can_dev_id {
+ BOSCH_C_CAN_PLATFORM,
+ BOSCH_C_CAN,
+ BOSCH_D_CAN,
+};
+
+/* c_can private data structure */
+struct c_can_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *dev;
+ struct device *device;
+ int tx_object;
+ int current_status;
+ int last_status;
+ u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
+ void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
+ void __iomem *base;
+ const u16 *regs;
+ unsigned long irq_flags; /* for request_irq() */
+ unsigned int tx_next;
+ unsigned int tx_echo;
+ void *priv; /* for board-specific data */
+ u16 irqstatus;
+ enum c_can_dev_id type;
+ u32 __iomem *raminit_ctrlreg;
+ unsigned int instance;
+ void (*raminit) (const struct c_can_priv *priv, bool enable);
+};
+
+struct net_device *alloc_c_can_dev(void);
+void free_c_can_dev(struct net_device *dev);
+int register_c_can_dev(struct net_device *dev);
+void unregister_c_can_dev(struct net_device *dev);
+
+#ifdef CONFIG_PM
+int c_can_power_up(struct net_device *dev);
+int c_can_power_down(struct net_device *dev);
+#endif
+
+#endif /* C_CAN_H */
diff --git a/c_can/c_can_pci.c b/c_can/c_can_pci.c
new file mode 100644
index 0000000..b374be7
--- /dev/null
+++ b/c_can/c_can_pci.c
@@ -0,0 +1,221 @@
+/*
+ * PCI bus driver for Bosch C_CAN/D_CAN controller
+ *
+ * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
+ *
+ * Borrowed from c_can_platform.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+enum c_can_pci_reg_align {
+ C_CAN_REG_ALIGN_16,
+ C_CAN_REG_ALIGN_32,
+};
+
+struct c_can_pci_data {
+ /* Specify if is C_CAN or D_CAN */
+ enum c_can_dev_id type;
+ /* Set the register alignment in the memory */
+ enum c_can_pci_reg_align reg_align;
+ /* Set the frequency */
+ unsigned int freq;
+};
+
+/*
+ * 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + priv->regs[index]);
+}
+
+static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + 2 * priv->regs[index]);
+}
+
+static int c_can_pci_probe(struct pci_dev *pdev,
+   const struct pci_device_id *ent)
+{
+ struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
+ struct c_can_priv *priv;
+ struct net_device *dev;
+ void __iomem *addr;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device FAILED\n");
+ goto out;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_request_regions FAILED\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+ pci_enable_msi(pdev);
+
+ addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!addr) {
+ dev_err(&pdev->dev,
+ "device has no PCI memory resources, "
+ "failing adapter\n");
+ ret = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ /* allocate the c_can device */
+ dev = alloc_c_can_dev();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out_iounmap;
+ }
+
+ priv = netdev_priv(dev);
+ pci_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ dev->irq = pdev->irq;
+ priv->base = addr;
+
+ if (!c_can_pci_data->freq) {
+ dev_err(&pdev->dev, "no clock frequency defined\n");
+ ret = -ENODEV;
+ goto out_free_c_can;
+ } else {
+ priv->can.clock.freq = c_can_pci_data->freq;
+ }
+
+ /* Configure CAN type */
+ switch (c_can_pci_data->type) {
+ case BOSCH_C_CAN:
+ priv->regs = reg_map_c_can;
+ break;
+ case BOSCH_D_CAN:
+ priv->regs = reg_map_d_can;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_free_c_can;
+ }
+
+ /* Configure access to registers */
+ switch (c_can_pci_data->reg_align) {
+ case C_CAN_REG_ALIGN_32:
+ priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
+ priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
+ break;
+ case C_CAN_REG_ALIGN_16:
+ priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_free_c_can;
+ }
+
+ ret = register_c_can_dev(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, ret);
+ goto out_free_c_can;
+ }
+
+ dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+ KBUILD_MODNAME, priv->regs, dev->irq);
+
+ return 0;
+
+out_free_c_can:
+ pci_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+out_iounmap:
+ pci_iounmap(pdev, addr);
+out_release_regions:
+ pci_disable_msi(pdev);
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+out_disable_device:
+ pci_disable_device(pdev);
+out:
+ return ret;
+}
+
+static void c_can_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ unregister_c_can_dev(dev);
+
+ pci_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+
+ pci_iounmap(pdev, priv->base);
+ pci_disable_msi(pdev);
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct c_can_pci_data c_can_sta2x11= {
+ .type = BOSCH_C_CAN,
+ .reg_align = C_CAN_REG_ALIGN_32,
+ .freq = 52000000, /* 52 Mhz */
+};
+
+#define C_CAN_ID(_vend, _dev, _driverdata) { \
+ PCI_DEVICE(_vend, _dev), \
+ .driver_data = (unsigned long)&_driverdata, \
+}
+static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
+ C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
+ c_can_sta2x11),
+ {},
+};
+static struct pci_driver c_can_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = c_can_pci_tbl,
+ .probe = c_can_pci_probe,
+ .remove = c_can_pci_remove,
+};
+
+module_pci_driver(c_can_pci_driver);
+
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
+MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
diff --git a/c_can/c_can_platform.c b/c_can/c_can_platform.c
new file mode 100644
index 0000000..d63b919
--- /dev/null
+++ b/c_can/c_can_platform.c
@@ -0,0 +1,347 @@
+/*
+ * Platform CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+#define CAN_RAMINIT_START_MASK(i) (1 << (i))
+
+/*
+ * 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + priv->regs[index]);
+}
+
+static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + priv->regs[index]);
+}
+
+static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
+{
+ u32 val;
+
+ val = readl(priv->raminit_ctrlreg);
+ if (enable)
+ val |= CAN_RAMINIT_START_MASK(priv->instance);
+ else
+ val &= ~CAN_RAMINIT_START_MASK(priv->instance);
+ writel(val, priv->raminit_ctrlreg);
+}
+
+static struct platform_device_id c_can_id_table[] = {
+ [BOSCH_C_CAN_PLATFORM] = {
+ .name = KBUILD_MODNAME,
+ .driver_data = BOSCH_C_CAN,
+ },
+ [BOSCH_C_CAN] = {
+ .name = "c_can",
+ .driver_data = BOSCH_C_CAN,
+ },
+ [BOSCH_D_CAN] = {
+ .name = "d_can",
+ .driver_data = BOSCH_D_CAN,
+ }, {
+ }
+};
+MODULE_DEVICE_TABLE(platform, c_can_id_table);
+
+static const struct of_device_id c_can_of_table[] = {
+ { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
+ { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, c_can_of_table);
+
+static int c_can_plat_probe(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *addr;
+ struct net_device *dev;
+ struct c_can_priv *priv;
+ const struct of_device_id *match;
+ const struct platform_device_id *id;
+ struct pinctrl *pinctrl;
+ struct resource *mem, *res;
+ int irq;
+ struct clk *clk;
+
+ if (pdev->dev.of_node) {
+ match = of_match_device(c_can_of_table, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Failed to find matching dt id\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ id = match->data;
+ } else {
+ id = platform_get_device_id(pdev);
+ }
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev,
+ "failed to configure pins from driver\n");
+
+ /* get the appropriate clk */
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ /* get the platform data */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!mem || irq <= 0) {
+ ret = -ENODEV;
+ goto exit_free_clk;
+ }
+
+ if (!request_mem_region(mem->start, resource_size(mem),
+ KBUILD_MODNAME)) {
+ dev_err(&pdev->dev, "resource unavailable\n");
+ ret = -ENODEV;
+ goto exit_free_clk;
+ }
+
+ addr = ioremap(mem->start, resource_size(mem));
+ if (!addr) {
+ dev_err(&pdev->dev, "failed to map can port\n");
+ ret = -ENOMEM;
+ goto exit_release_mem;
+ }
+
+ /* allocate the c_can device */
+ dev = alloc_c_can_dev();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto exit_iounmap;
+ }
+
+ priv = netdev_priv(dev);
+ switch (id->driver_data) {
+ case BOSCH_C_CAN:
+ priv->regs = reg_map_c_can;
+ switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+ case IORESOURCE_MEM_32BIT:
+ priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
+ break;
+ case IORESOURCE_MEM_16BIT:
+ default:
+ priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+ break;
+ }
+ break;
+ case BOSCH_D_CAN:
+ priv->regs = reg_map_d_can;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+
+ if (pdev->dev.of_node)
+ priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
+ else
+ priv->instance = pdev->id;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->raminit_ctrlreg = devm_request_and_ioremap(&pdev->dev, res);
+ if (!priv->raminit_ctrlreg || priv->instance < 0)
+ dev_info(&pdev->dev, "control memory is not used for raminit\n");
+ else
+ priv->raminit = c_can_hw_raminit;
+ break;
+ default:
+ ret = -EINVAL;
+ goto exit_free_device;
+ }
+
+ dev->irq = irq;
+ priv->base = addr;
+ priv->device = &pdev->dev;
+ priv->can.clock.freq = clk_get_rate(clk);
+ priv->priv = clk;
+ priv->type = id->driver_data;
+
+ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ ret = register_c_can_dev(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, ret);
+ goto exit_free_device;
+ }
+
+ dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+ KBUILD_MODNAME, priv->base, dev->irq);
+ return 0;
+
+exit_free_device:
+ platform_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+exit_iounmap:
+ iounmap(addr);
+exit_release_mem:
+ release_mem_region(mem->start, resource_size(mem));
+exit_free_clk:
+ clk_put(clk);
+exit:
+ dev_err(&pdev->dev, "probe failed\n");
+
+ return ret;
+}
+
+static int c_can_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+
+ unregister_c_can_dev(dev);
+ platform_set_drvdata(pdev, NULL);
+
+ free_c_can_dev(dev);
+ iounmap(priv->base);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+ clk_put(priv->priv);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(ndev);
+
+ if (priv->type != BOSCH_D_CAN) {
+ dev_warn(&pdev->dev, "Not supported\n");
+ return 0;
+ }
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ }
+
+ ret = c_can_power_down(ndev);
+ if (ret) {
+ netdev_err(ndev, "failed to enter power down mode\n");
+ return ret;
+ }
+
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ return 0;
+}
+
+static int c_can_resume(struct platform_device *pdev)
+{
+ int ret;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(ndev);
+
+ if (priv->type != BOSCH_D_CAN) {
+ dev_warn(&pdev->dev, "Not supported\n");
+ return 0;
+ }
+
+ ret = c_can_power_up(ndev);
+ if (ret) {
+ netdev_err(ndev, "Still in power down mode\n");
+ return ret;
+ }
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+
+ return 0;
+}
+#else
+#define c_can_suspend NULL
+#define c_can_resume NULL
+#endif
+
+static struct platform_driver c_can_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(c_can_of_table),
+ },
+ .probe = c_can_plat_probe,
+ .remove = c_can_plat_remove,
+ .suspend = c_can_suspend,
+ .resume = c_can_resume,
+ .id_table = c_can_id_table,
+};
+
+module_platform_driver(c_can_plat_driver);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
-- 
1.9.1


>From fbe3b224501e091d26275b45e2cf0881d94997dd Mon Sep 17 00:00:00 2001
From: Michael Haberler <git@mah.priv.at>
Date: Tue, 7 Apr 2015 08:05:49 +0200
Subject: [PATCH 2/3] rename original files to match Steve's naming

---
 c_can/c_can.c                | 1292
------------------------------------------
 c_can/c_can.h                |  187 ------
 c_can/c_can_pci.c            |  221 --------
 c_can/c_can_platform.c       |  347 ------------
 c_can/rtcan_c_can.c          | 1292
++++++++++++++++++++++++++++++++++++++++++
 c_can/rtcan_c_can.h          |  187 ++++++
 c_can/rtcan_c_can_pci.c      |  221 ++++++++
 c_can/rtcan_c_can_platform.c |  347 ++++++++++++
 8 files changed, 2047 insertions(+), 2047 deletions(-)
 delete mode 100644 c_can/c_can.c
 delete mode 100644 c_can/c_can.h
 delete mode 100644 c_can/c_can_pci.c
 delete mode 100644 c_can/c_can_platform.c
 create mode 100644 c_can/rtcan_c_can.c
 create mode 100644 c_can/rtcan_c_can.h
 create mode 100644 c_can/rtcan_c_can_pci.c
 create mode 100644 c_can/rtcan_c_can_platform.c

diff --git a/c_can/c_can.c b/c_can/c_can.c
deleted file mode 100644
index 2282b1a..0000000
--- a/c_can/c_can.c
+++ /dev/null
@@ -1,1292 +0,0 @@
-/*
- * CAN bus driver for Bosch C_CAN controller
- *
- * Copyright (C) 2010 ST Microelectronics
- * Bhupesh Sharma <bhupesh.sharma@st.com>
- *
- * Borrowed heavily from the C_CAN driver originally written by:
- * Copyright (C) 2007
- * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
- * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
- *
- * TX and RX NAPI implementation has been borrowed from at91 CAN driver
- * written by:
- * Copyright
- * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
- * (C) 2008, 2009 by Marc Kleine-Budde <kernel@pengutronix.de>
- *
- * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
- * Bosch C_CAN user manual can be obtained from:
- * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
- * users_manual_c_can.pdf
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/list.h>
-#include <linux/io.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
-
-#include "c_can.h"
-
-/* Number of interface registers */
-#define IF_ENUM_REG_LEN 11
-#define C_CAN_IFACE(reg, iface) (C_CAN_IF1_##reg + (iface) *
IF_ENUM_REG_LEN)
-
-/* control extension register D_CAN specific */
-#define CONTROL_EX_PDR BIT(8)
-
-/* control register */
-#define CONTROL_TEST BIT(7)
-#define CONTROL_CCE BIT(6)
-#define CONTROL_DISABLE_AR BIT(5)
-#define CONTROL_ENABLE_AR (0 << 5)
-#define CONTROL_EIE BIT(3)
-#define CONTROL_SIE BIT(2)
-#define CONTROL_IE BIT(1)
-#define CONTROL_INIT BIT(0)
-
-/* test register */
-#define TEST_RX BIT(7)
-#define TEST_TX1 BIT(6)
-#define TEST_TX2 BIT(5)
-#define TEST_LBACK BIT(4)
-#define TEST_SILENT BIT(3)
-#define TEST_BASIC BIT(2)
-
-/* status register */
-#define STATUS_PDA BIT(10)
-#define STATUS_BOFF BIT(7)
-#define STATUS_EWARN BIT(6)
-#define STATUS_EPASS BIT(5)
-#define STATUS_RXOK BIT(4)
-#define STATUS_TXOK BIT(3)
-
-/* error counter register */
-#define ERR_CNT_TEC_MASK 0xff
-#define ERR_CNT_TEC_SHIFT 0
-#define ERR_CNT_REC_SHIFT 8
-#define ERR_CNT_REC_MASK (0x7f << ERR_CNT_REC_SHIFT)
-#define ERR_CNT_RP_SHIFT 15
-#define ERR_CNT_RP_MASK (0x1 << ERR_CNT_RP_SHIFT)
-
-/* bit-timing register */
-#define BTR_BRP_MASK 0x3f
-#define BTR_BRP_SHIFT 0
-#define BTR_SJW_SHIFT 6
-#define BTR_SJW_MASK (0x3 << BTR_SJW_SHIFT)
-#define BTR_TSEG1_SHIFT 8
-#define BTR_TSEG1_MASK (0xf << BTR_TSEG1_SHIFT)
-#define BTR_TSEG2_SHIFT 12
-#define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT)
-
-/* brp extension register */
-#define BRP_EXT_BRPE_MASK 0x0f
-#define BRP_EXT_BRPE_SHIFT 0
-
-/* IFx command request */
-#define IF_COMR_BUSY BIT(15)
-
-/* IFx command mask */
-#define IF_COMM_WR BIT(7)
-#define IF_COMM_MASK BIT(6)
-#define IF_COMM_ARB BIT(5)
-#define IF_COMM_CONTROL BIT(4)
-#define IF_COMM_CLR_INT_PND BIT(3)
-#define IF_COMM_TXRQST BIT(2)
-#define IF_COMM_DATAA BIT(1)
-#define IF_COMM_DATAB BIT(0)
-#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \
- IF_COMM_CONTROL | IF_COMM_TXRQST | \
- IF_COMM_DATAA | IF_COMM_DATAB)
-
-/* IFx arbitration */
-#define IF_ARB_MSGVAL BIT(15)
-#define IF_ARB_MSGXTD BIT(14)
-#define IF_ARB_TRANSMIT BIT(13)
-
-/* IFx message control */
-#define IF_MCONT_NEWDAT BIT(15)
-#define IF_MCONT_MSGLST BIT(14)
-#define IF_MCONT_CLR_MSGLST (0 << 14)
-#define IF_MCONT_INTPND BIT(13)
-#define IF_MCONT_UMASK BIT(12)
-#define IF_MCONT_TXIE BIT(11)
-#define IF_MCONT_RXIE BIT(10)
-#define IF_MCONT_RMTEN BIT(9)
-#define IF_MCONT_TXRQST BIT(8)
-#define IF_MCONT_EOB BIT(7)
-#define IF_MCONT_DLC_MASK 0xf
-
-/*
- * IFx register masks:
- * allow easy operation on 16-bit registers when the
- * argument is 32-bit instead
- */
-#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
-#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
-
-/* message object split */
-#define C_CAN_NO_OF_OBJECTS 32
-#define C_CAN_MSG_OBJ_RX_NUM 16
-#define C_CAN_MSG_OBJ_TX_NUM 16
-
-#define C_CAN_MSG_OBJ_RX_FIRST 1
-#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
- C_CAN_MSG_OBJ_RX_NUM - 1)
-
-#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
-#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
- C_CAN_MSG_OBJ_TX_NUM - 1)
-
-#define C_CAN_MSG_OBJ_RX_SPLIT 9
-#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
-
-#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
-#define RECEIVE_OBJECT_BITS 0x0000ffff
-
-/* status interrupt */
-#define STATUS_INTERRUPT 0x8000
-
-/* global interrupt masks */
-#define ENABLE_ALL_INTERRUPTS 1
-#define DISABLE_ALL_INTERRUPTS 0
-
-/* minimum timeout for checking BUSY status */
-#define MIN_TIMEOUT_VALUE 6
-
-/* Wait for ~1 sec for INIT bit */
-#define INIT_WAIT_MS 1000
-
-/* napi related */
-#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
-
-/* c_can lec values */
-enum c_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,
-};
-
-/*
- * c_can error types:
- * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
- */
-enum c_can_bus_error_types {
- C_CAN_NO_ERROR = 0,
- C_CAN_BUS_OFF,
- C_CAN_ERROR_WARNING,
- C_CAN_ERROR_PASSIVE,
-};
-
-static const struct can_bittiming_const c_can_bittiming_const = {
- .name = KBUILD_MODNAME,
- .tseg1_min = 2, /* 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,
-};
-
-static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
-{
- if (priv->device)
- pm_runtime_enable(priv->device);
-}
-
-static inline void c_can_pm_runtime_disable(const struct c_can_priv *priv)
-{
- if (priv->device)
- pm_runtime_disable(priv->device);
-}
-
-static inline void c_can_pm_runtime_get_sync(const struct c_can_priv *priv)
-{
- if (priv->device)
- pm_runtime_get_sync(priv->device);
-}
-
-static inline void c_can_pm_runtime_put_sync(const struct c_can_priv *priv)
-{
- if (priv->device)
- pm_runtime_put_sync(priv->device);
-}
-
-static inline void c_can_reset_ram(const struct c_can_priv *priv, bool
enable)
-{
- if (priv->raminit)
- priv->raminit(priv, enable);
-}
-
-static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
-{
- return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
- C_CAN_MSG_OBJ_TX_FIRST;
-}
-
-static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
-{
- return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
- C_CAN_MSG_OBJ_TX_FIRST;
-}
-
-static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
-{
- u32 val = priv->read_reg(priv, index);
- val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
- return val;
-}
-
-static void c_can_enable_all_interrupts(struct c_can_priv *priv,
- int enable)
-{
- unsigned int cntrl_save = priv->read_reg(priv,
- C_CAN_CTRL_REG);
-
- if (enable)
- cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
- else
- cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
-
- priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save);
-}
-
-static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
-{
- int count = MIN_TIMEOUT_VALUE;
-
- while (count && priv->read_reg(priv,
- C_CAN_IFACE(COMREQ_REG, iface)) &
- IF_COMR_BUSY) {
- count--;
- udelay(1);
- }
-
- if (!count)
- return 1;
-
- return 0;
-}
-
-static inline void c_can_object_get(struct net_device *dev,
- int iface, int objno, int mask)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- /*
- * As per specs, after writting the message object number in the
- * IF command request register the transfer b/w interface
- * register and message RAM must be complete in 6 CAN-CLK
- * period.
- */
- priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
- IFX_WRITE_LOW_16BIT(mask));
- priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
- IFX_WRITE_LOW_16BIT(objno));
-
- if (c_can_msg_obj_is_busy(priv, iface))
- netdev_err(dev, "timed out in object get\n");
-}
-
-static inline void c_can_object_put(struct net_device *dev,
- int iface, int objno, int mask)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- /*
- * As per specs, after writting the message object number in the
- * IF command request register the transfer b/w interface
- * register and message RAM must be complete in 6 CAN-CLK
- * period.
- */
- priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
- (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
- priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
- IFX_WRITE_LOW_16BIT(objno));
-
- if (c_can_msg_obj_is_busy(priv, iface))
- netdev_err(dev, "timed out in object put\n");
-}
-
-static void c_can_write_msg_object(struct net_device *dev,
- int iface, struct can_frame *frame, int objno)
-{
- int i;
- u16 flags = 0;
- unsigned int id;
- struct c_can_priv *priv = netdev_priv(dev);
-
- if (!(frame->can_id & CAN_RTR_FLAG))
- flags |= IF_ARB_TRANSMIT;
-
- if (frame->can_id & CAN_EFF_FLAG) {
- id = frame->can_id & CAN_EFF_MASK;
- flags |= IF_ARB_MSGXTD;
- } else
- id = ((frame->can_id & CAN_SFF_MASK) << 18);
-
- flags |= IF_ARB_MSGVAL;
-
- priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
- IFX_WRITE_LOW_16BIT(id));
- priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags |
- IFX_WRITE_HIGH_16BIT(id));
-
- for (i = 0; i < frame->can_dlc; i += 2) {
- priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
- frame->data[i] | (frame->data[i + 1] << 8));
- }
-
- /* enable interrupt for this message object */
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
- frame->can_dlc);
- c_can_object_put(dev, iface, objno, IF_COMM_ALL);
-}
-
-static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
- int iface, int ctrl_mask,
- int obj)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
- c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
-
-}
-
-static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device
*dev,
- int iface,
- int ctrl_mask)
-{
- int i;
- struct c_can_priv *priv = netdev_priv(dev);
-
- for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST |
- IF_MCONT_INTPND | IF_MCONT_NEWDAT));
- c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
- }
-}
-
-static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
- int iface, int ctrl_mask,
- int obj)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- ctrl_mask & ~(IF_MCONT_MSGLST |
- IF_MCONT_INTPND | IF_MCONT_NEWDAT));
- c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
-}
-
-static void c_can_handle_lost_msg_obj(struct net_device *dev,
- int iface, int objno)
-{
- struct c_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);
-
- c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
- IF_MCONT_CLR_MSGLST);
-
- c_can_object_put(dev, 0, objno, IF_COMM_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 c_can_read_msg_object(struct net_device *dev, int iface, int
ctrl)
-{
- u16 flags, data;
- int i;
- unsigned int val;
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
- struct can_frame *frame;
-
- skb = alloc_can_skb(dev, &frame);
- if (!skb) {
- stats->rx_dropped++;
- return -ENOMEM;
- }
-
- frame->can_dlc = get_can_dlc(ctrl & 0x0F);
-
- flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
- val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
- (flags << 16);
-
- if (flags & IF_ARB_MSGXTD)
- frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
- else
- frame->can_id = (val >> 18) & CAN_SFF_MASK;
-
- if (flags & IF_ARB_TRANSMIT)
- frame->can_id |= CAN_RTR_FLAG;
- else {
- for (i = 0; i < frame->can_dlc; i += 2) {
- data = priv->read_reg(priv,
- C_CAN_IFACE(DATA1_REG, iface) + i / 2);
- frame->data[i] = data;
- frame->data[i + 1] = data >> 8;
- }
- }
-
- netif_receive_skb(skb);
-
- stats->rx_packets++;
- stats->rx_bytes += frame->can_dlc;
-
- return 0;
-}
-
-static void c_can_setup_receive_object(struct net_device *dev, int iface,
- int objno, unsigned int mask,
- unsigned int id, unsigned int mcont)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
- IFX_WRITE_LOW_16BIT(mask));
-
- /* According to C_CAN documentation, the reserved bit
- * in IFx_MASK2 register is fixed 1
- */
- priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
- IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
-
- priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
- IFX_WRITE_LOW_16BIT(id));
- priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface),
- (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
-
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
- c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
-
- netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
- c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
-}
-
-static void c_can_inval_msg_object(struct net_device *dev, int iface, int
objno)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
- priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
- priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
-
- c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
-
- netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
- c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
-}
-
-static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int
objno)
-{
- int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
-
- /*
- * as transmission request register's bit n-1 corresponds to
- * message object n, we need to handle the same properly.
- */
- if (val & (1 << (objno - 1)))
- return 1;
-
- return 0;
-}
-
-static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- u32 msg_obj_no;
- struct c_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 */
- c_can_write_msg_object(dev, 0, frame, msg_obj_no);
- can_put_echo_skb(skb, dev, msg_obj_no - C_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 (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
- (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
- netif_stop_queue(dev);
-
- return NETDEV_TX_OK;
-}
-
-static int c_can_set_bittiming(struct net_device *dev)
-{
- unsigned int reg_btr, reg_brpe, ctrl_save;
- u8 brp, brpe, sjw, tseg1, tseg2;
- u32 ten_bit_brp;
- struct c_can_priv *priv = netdev_priv(dev);
- const struct can_bittiming *bt = &priv->can.bittiming;
-
- /* c_can provides a 6-bit brp and 4-bit brpe fields */
- ten_bit_brp = bt->brp - 1;
- brp = ten_bit_brp & BTR_BRP_MASK;
- brpe = ten_bit_brp >> 6;
-
- sjw = bt->sjw - 1;
- tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
- tseg2 = bt->phase_seg2 - 1;
- reg_btr = brp | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
- (tseg2 << BTR_TSEG2_SHIFT);
- reg_brpe = brpe & BRP_EXT_BRPE_MASK;
-
- netdev_info(dev,
- "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
-
- ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
- priv->write_reg(priv, C_CAN_CTRL_REG,
- ctrl_save | CONTROL_CCE | CONTROL_INIT);
- priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
- priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
- priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
-
- return 0;
-}
-
-/*
- * Configure C_CAN message objects for Tx and Rx purposes:
- * C_CAN provides a total of 32 message objects that can be configured
- * either for Tx or Rx purposes. Here the first 16 message objects are
used as
- * a reception FIFO. The end of reception FIFO is signified by the EoB bit
- * being SET. The remaining 16 message objects are kept aside for Tx
purposes.
- * See user guide document for further details on configuring message
- * objects.
- */
-static void c_can_configure_msg_objects(struct net_device *dev)
-{
- int i;
-
- /* first invalidate all message objects */
- for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
- c_can_inval_msg_object(dev, 0, i);
-
- /* setup receive message objects */
- for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
- c_can_setup_receive_object(dev, 0, i, 0, 0,
- (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
-
- c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
- IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
-}
-
-/*
- * Configure C_CAN chip:
- * - enable/disable auto-retransmission
- * - set operating mode
- * - configure message objects
- */
-static void c_can_chip_config(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- /* enable automatic retransmission */
- priv->write_reg(priv, C_CAN_CTRL_REG,
- CONTROL_ENABLE_AR);
-
- if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
-    (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
- /* loopback + silent mode : useful for hot self-test */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
- CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
- priv->write_reg(priv, C_CAN_TEST_REG,
- TEST_LBACK | TEST_SILENT);
- } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
- /* loopback mode : useful for self-test function */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
- CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
- priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
- } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
- /* silent mode : bus-monitoring mode */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
- CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
- priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
- } else
- /* normal mode*/
- priv->write_reg(priv, C_CAN_CTRL_REG,
- CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
-
- /* configure message objects */
- c_can_configure_msg_objects(dev);
-
- /* set a `lec` value so that we can check for updates later */
- priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
-
- /* set bittiming params */
- c_can_set_bittiming(dev);
-}
-
-static void c_can_start(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- /* basic c_can configuration */
- c_can_chip_config(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 */
- c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
-}
-
-static void c_can_stop(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- /* disable all interrupts */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
-
- /* set the state as STOPPED */
- priv->can.state = CAN_STATE_STOPPED;
-}
-
-static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
-{
- switch (mode) {
- case CAN_MODE_START:
- c_can_start(dev);
- netif_wake_queue(dev);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static int c_can_get_berr_counter(const struct net_device *dev,
- struct can_berr_counter *bec)
-{
- unsigned int reg_err_counter;
- struct c_can_priv *priv = netdev_priv(dev);
-
- c_can_pm_runtime_get_sync(priv);
-
- reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
- bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
- ERR_CNT_REC_SHIFT;
- bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
-
- c_can_pm_runtime_put_sync(priv);
-
- return 0;
-}
-
-/*
- * theory of operation:
- *
- * priv->tx_echo holds the number of the oldest can_frame put for
- * transmission into the hardware, but not yet ACKed by the CAN tx
- * complete IRQ.
- *
- * We iterate from priv->tx_echo to priv->tx_next and check if the
- * packet has been transmitted, echo it back to the CAN framework.
- * If we discover a not yet transmitted packet, stop looking for more.
- */
-static void c_can_do_tx(struct net_device *dev)
-{
- u32 val;
- u32 msg_obj_no;
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
-
- for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
- msg_obj_no = get_tx_echo_msg_obj(priv);
- val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
- if (!(val & (1 << (msg_obj_no - 1)))) {
- can_get_echo_skb(dev,
- msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
- stats->tx_bytes += priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0))
- & IF_MCONT_DLC_MASK;
- stats->tx_packets++;
- c_can_inval_msg_object(dev, 0, msg_obj_no);
- } else {
- break;
- }
- }
-
- /* restart queue if wrap-up or if queue stalled on last pkt */
- if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
- ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
- netif_wake_queue(dev);
-}
-
-/*
- * theory of operation:
- *
- * c_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 C_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
- *   C_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
- *   C_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
- *   C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
- *   only this message object.
- */
-static int c_can_do_rx_poll(struct net_device *dev, int quota)
-{
- u32 num_rx_pkts = 0;
- unsigned int msg_obj, msg_ctrl_save;
- struct c_can_priv *priv = netdev_priv(dev);
- u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG);
-
- for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
- msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
- val = c_can_read_reg32(priv, C_CAN_INTPND1_REG),
- msg_obj++) {
- /*
- * as interrupt pending register's bit n-1 corresponds to
- * message object n, we need to handle the same properly.
- */
- if (val & (1 << (msg_obj - 1))) {
- c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
- ~IF_COMM_TXRQST);
- msg_ctrl_save = priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0));
-
- if (msg_ctrl_save & IF_MCONT_EOB)
- return num_rx_pkts;
-
- if (msg_ctrl_save & IF_MCONT_MSGLST) {
- c_can_handle_lost_msg_obj(dev, 0, msg_obj);
- num_rx_pkts++;
- quota--;
- continue;
- }
-
- if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
- continue;
-
- /* read the data from the message object */
- c_can_read_msg_object(dev, 0, msg_ctrl_save);
-
- if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
- c_can_mark_rx_msg_obj(dev, 0,
- msg_ctrl_save, msg_obj);
- else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
- /* activate this msg obj */
- c_can_activate_rx_msg_obj(dev, 0,
- msg_ctrl_save, msg_obj);
- else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
- /* activate all lower message objects */
- c_can_activate_all_lower_rx_msg_obj(dev,
- 0, msg_ctrl_save);
-
- num_rx_pkts++;
- quota--;
- }
- }
-
- return num_rx_pkts;
-}
-
-static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
-{
- return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
- (priv->current_status & LEC_UNUSED);
-}
-
-static int c_can_handle_state_change(struct net_device *dev,
- enum c_can_bus_error_types error_type)
-{
- unsigned int reg_err_counter;
- unsigned int rx_err_passive;
- struct c_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;
-
- c_can_get_berr_counter(dev, &bec);
- reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
- rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
- ERR_CNT_RP_SHIFT;
-
- switch (error_type) {
- case C_CAN_ERROR_WARNING:
- /* error warning state */
- priv->can.can_stats.error_warning++;
- priv->can.state = CAN_STATE_ERROR_WARNING;
- cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] = (bec.txerr > bec.rxerr) ?
- CAN_ERR_CRTL_TX_WARNING :
- CAN_ERR_CRTL_RX_WARNING;
- cf->data[6] = bec.txerr;
- cf->data[7] = bec.rxerr;
-
- break;
- case C_CAN_ERROR_PASSIVE:
- /* error passive state */
- priv->can.can_stats.error_passive++;
- priv->can.state = CAN_STATE_ERROR_PASSIVE;
- cf->can_id |= CAN_ERR_CRTL;
- if (rx_err_passive)
- cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
- if (bec.txerr > 127)
- cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
-
- cf->data[6] = bec.txerr;
- cf->data[7] = bec.rxerr;
- break;
- case C_CAN_BUS_OFF:
- /* bus-off state */
- priv->can.state = CAN_STATE_BUS_OFF;
- cf->can_id |= CAN_ERR_BUSOFF;
- /*
- * disable all interrupts in bus-off mode to ensure that
- * the CPU is not hogged down
- */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
- can_bus_off(dev);
- break;
- default:
- break;
- }
-
- netif_receive_skb(skb);
- stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
-
- return 1;
-}
-
-static int c_can_handle_bus_err(struct net_device *dev,
- enum c_can_lec_type lec_type)
-{
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct can_frame *cf;
- struct sk_buff *skb;
-
- /*
- * early exit if no lec update or no error.
- * no lec update means that no CAN bus event has been detected
- * since CPU wrote 0x7 value to status reg.
- */
- if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
- return 0;
-
- /* propagate the error condition to the CAN stack */
- skb = alloc_can_err_skb(dev, &cf);
- if (unlikely(!skb))
- return 0;
-
- /*
- * check for 'last error code' which tells us the
- * type of the last error to occur on the CAN bus
- */
-
- /* common for all type of bus errors */
- priv->can.can_stats.bus_error++;
- stats->rx_errors++;
- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
-
- switch (lec_type) {
- case LEC_STUFF_ERROR:
- netdev_dbg(dev, "stuff error\n");
- cf->data[2] |= CAN_ERR_PROT_STUFF;
- break;
- case LEC_FORM_ERROR:
- netdev_dbg(dev, "form error\n");
- cf->data[2] |= CAN_ERR_PROT_FORM;
- break;
- case LEC_ACK_ERROR:
- netdev_dbg(dev, "ack error\n");
- cf->data[3] |= (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[3] |= (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 */
- priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
-
- netif_receive_skb(skb);
- stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
-
- return 1;
-}
-
-static int c_can_poll(struct napi_struct *napi, int quota)
-{
- u16 irqstatus;
- int lec_type = 0;
- int work_done = 0;
- struct net_device *dev = napi->dev;
- struct c_can_priv *priv = netdev_priv(dev);
-
- irqstatus = priv->irqstatus;
- if (!irqstatus)
- goto end;
-
- /* status events have the highest priority */
- if (irqstatus == STATUS_INTERRUPT) {
- priv->current_status = priv->read_reg(priv,
- C_CAN_STS_REG);
-
- /* handle Tx/Rx events */
- if (priv->current_status & STATUS_TXOK)
- priv->write_reg(priv, C_CAN_STS_REG,
- priv->current_status & ~STATUS_TXOK);
-
- if (priv->current_status & STATUS_RXOK)
- priv->write_reg(priv, C_CAN_STS_REG,
- priv->current_status & ~STATUS_RXOK);
-
- /* handle state changes */
- if ((priv->current_status & STATUS_EWARN) &&
- (!(priv->last_status & STATUS_EWARN))) {
- netdev_dbg(dev, "entered error warning state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_WARNING);
- }
- if ((priv->current_status & STATUS_EPASS) &&
- (!(priv->last_status & STATUS_EPASS))) {
- netdev_dbg(dev, "entered error passive state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_PASSIVE);
- }
- if ((priv->current_status & STATUS_BOFF) &&
- (!(priv->last_status & STATUS_BOFF))) {
- netdev_dbg(dev, "entered bus off state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_BUS_OFF);
- }
-
- /* handle bus recovery events */
- if ((!(priv->current_status & STATUS_BOFF)) &&
- (priv->last_status & STATUS_BOFF)) {
- netdev_dbg(dev, "left bus off state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- }
- if ((!(priv->current_status & STATUS_EPASS)) &&
- (priv->last_status & STATUS_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 = c_can_has_and_handle_berr(priv);
- if (lec_type)
- work_done += c_can_handle_bus_err(dev, lec_type);
- } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
- /* handle events corresponding to receive message objects */
- work_done += c_can_do_rx_poll(dev, (quota - work_done));
- } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
- /* handle events corresponding to transmit message objects */
- c_can_do_tx(dev);
- }
-
-end:
- if (work_done < quota) {
- napi_complete(napi);
- /* enable all IRQs */
- c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
- }
-
- return work_done;
-}
-
-static irqreturn_t c_can_isr(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
- if (!priv->irqstatus)
- return IRQ_NONE;
-
- /* disable all interrupts and schedule the NAPI */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
- napi_schedule(&priv->napi);
-
- return IRQ_HANDLED;
-}
-
-static int c_can_open(struct net_device *dev)
-{
- int err;
- struct c_can_priv *priv = netdev_priv(dev);
-
- c_can_pm_runtime_get_sync(priv);
- c_can_reset_ram(priv, true);
-
- /* open the can device */
- err = open_candev(dev);
- if (err) {
- netdev_err(dev, "failed to open can device\n");
- goto exit_open_fail;
- }
-
- /* register interrupt handler */
- err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
- dev);
- if (err < 0) {
- netdev_err(dev, "failed to request interrupt\n");
- goto exit_irq_fail;
- }
-
- napi_enable(&priv->napi);
-
- /* start the c_can controller */
- c_can_start(dev);
-
- netif_start_queue(dev);
-
- return 0;
-
-exit_irq_fail:
- close_candev(dev);
-exit_open_fail:
- c_can_reset_ram(priv, false);
- c_can_pm_runtime_put_sync(priv);
- return err;
-}
-
-static int c_can_close(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- netif_stop_queue(dev);
- napi_disable(&priv->napi);
- c_can_stop(dev);
- free_irq(dev->irq, dev);
- close_candev(dev);
-
- c_can_reset_ram(priv, false);
- c_can_pm_runtime_put_sync(priv);
-
- return 0;
-}
-
-struct net_device *alloc_c_can_dev(void)
-{
- struct net_device *dev;
- struct c_can_priv *priv;
-
- dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
- if (!dev)
- return NULL;
-
- priv = netdev_priv(dev);
- netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
-
- priv->dev = dev;
- priv->can.bittiming_const = &c_can_bittiming_const;
- priv->can.do_set_mode = c_can_set_mode;
- priv->can.do_get_berr_counter = c_can_get_berr_counter;
- priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
- CAN_CTRLMODE_LISTENONLY |
- CAN_CTRLMODE_BERR_REPORTING;
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(alloc_c_can_dev);
-
-#ifdef CONFIG_PM
-int c_can_power_down(struct net_device *dev)
-{
- u32 val;
- unsigned long time_out;
- struct c_can_priv *priv = netdev_priv(dev);
-
- if (!(dev->flags & IFF_UP))
- return 0;
-
- WARN_ON(priv->type != BOSCH_D_CAN);
-
- /* set PDR value so the device goes to power down mode */
- val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
- val |= CONTROL_EX_PDR;
- priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
-
- /* Wait for the PDA bit to get set */
- time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
- while (!(priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
- time_after(time_out, jiffies))
- cpu_relax();
-
- if (time_after(jiffies, time_out))
- return -ETIMEDOUT;
-
- c_can_stop(dev);
-
- c_can_reset_ram(priv, false);
- c_can_pm_runtime_put_sync(priv);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(c_can_power_down);
-
-int c_can_power_up(struct net_device *dev)
-{
- u32 val;
- unsigned long time_out;
- struct c_can_priv *priv = netdev_priv(dev);
-
- if (!(dev->flags & IFF_UP))
- return 0;
-
- WARN_ON(priv->type != BOSCH_D_CAN);
-
- c_can_pm_runtime_get_sync(priv);
- c_can_reset_ram(priv, true);
-
- /* Clear PDR and INIT bits */
- val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
- val &= ~CONTROL_EX_PDR;
- priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
- val = priv->read_reg(priv, C_CAN_CTRL_REG);
- val &= ~CONTROL_INIT;
- priv->write_reg(priv, C_CAN_CTRL_REG, val);
-
- /* Wait for the PDA bit to get clear */
- time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
- while ((priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
- time_after(time_out, jiffies))
- cpu_relax();
-
- if (time_after(jiffies, time_out))
- return -ETIMEDOUT;
-
- c_can_start(dev);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(c_can_power_up);
-#endif
-
-void free_c_can_dev(struct net_device *dev)
-{
- free_candev(dev);
-}
-EXPORT_SYMBOL_GPL(free_c_can_dev);
-
-static const struct net_device_ops c_can_netdev_ops = {
- .ndo_open = c_can_open,
- .ndo_stop = c_can_close,
- .ndo_start_xmit = c_can_start_xmit,
-};
-
-int register_c_can_dev(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
- int err;
-
- c_can_pm_runtime_enable(priv);
-
- dev->flags |= IFF_ECHO; /* we support local echo */
- dev->netdev_ops = &c_can_netdev_ops;
-
- err = register_candev(dev);
- if (err)
- c_can_pm_runtime_disable(priv);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(register_c_can_dev);
-
-void unregister_c_can_dev(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- unregister_candev(dev);
-
- c_can_pm_runtime_disable(priv);
-}
-EXPORT_SYMBOL_GPL(unregister_c_can_dev);
-
-MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
diff --git a/c_can/c_can.h b/c_can/c_can.h
deleted file mode 100644
index d2e1c21..0000000
--- a/c_can/c_can.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * CAN bus driver for Bosch C_CAN controller
- *
- * Copyright (C) 2010 ST Microelectronics
- * Bhupesh Sharma <bhupesh.sharma@st.com>
- *
- * Borrowed heavily from the C_CAN driver originally written by:
- * Copyright (C) 2007
- * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
- * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
- *
- * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
- * Bosch C_CAN user manual can be obtained from:
- * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
- * users_manual_c_can.pdf
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef C_CAN_H
-#define C_CAN_H
-
-enum reg {
- C_CAN_CTRL_REG = 0,
- C_CAN_CTRL_EX_REG,
- C_CAN_STS_REG,
- C_CAN_ERR_CNT_REG,
- C_CAN_BTR_REG,
- C_CAN_INT_REG,
- C_CAN_TEST_REG,
- C_CAN_BRPEXT_REG,
- C_CAN_IF1_COMREQ_REG,
- C_CAN_IF1_COMMSK_REG,
- C_CAN_IF1_MASK1_REG,
- C_CAN_IF1_MASK2_REG,
- C_CAN_IF1_ARB1_REG,
- C_CAN_IF1_ARB2_REG,
- C_CAN_IF1_MSGCTRL_REG,
- C_CAN_IF1_DATA1_REG,
- C_CAN_IF1_DATA2_REG,
- C_CAN_IF1_DATA3_REG,
- C_CAN_IF1_DATA4_REG,
- C_CAN_IF2_COMREQ_REG,
- C_CAN_IF2_COMMSK_REG,
- C_CAN_IF2_MASK1_REG,
- C_CAN_IF2_MASK2_REG,
- C_CAN_IF2_ARB1_REG,
- C_CAN_IF2_ARB2_REG,
- C_CAN_IF2_MSGCTRL_REG,
- C_CAN_IF2_DATA1_REG,
- C_CAN_IF2_DATA2_REG,
- C_CAN_IF2_DATA3_REG,
- C_CAN_IF2_DATA4_REG,
- C_CAN_TXRQST1_REG,
- C_CAN_TXRQST2_REG,
- C_CAN_NEWDAT1_REG,
- C_CAN_NEWDAT2_REG,
- C_CAN_INTPND1_REG,
- C_CAN_INTPND2_REG,
- C_CAN_MSGVAL1_REG,
- C_CAN_MSGVAL2_REG,
-};
-
-static const u16 reg_map_c_can[] = {
- [C_CAN_CTRL_REG] = 0x00,
- [C_CAN_STS_REG] = 0x02,
- [C_CAN_ERR_CNT_REG] = 0x04,
- [C_CAN_BTR_REG] = 0x06,
- [C_CAN_INT_REG] = 0x08,
- [C_CAN_TEST_REG] = 0x0A,
- [C_CAN_BRPEXT_REG] = 0x0C,
- [C_CAN_IF1_COMREQ_REG] = 0x10,
- [C_CAN_IF1_COMMSK_REG] = 0x12,
- [C_CAN_IF1_MASK1_REG] = 0x14,
- [C_CAN_IF1_MASK2_REG] = 0x16,
- [C_CAN_IF1_ARB1_REG] = 0x18,
- [C_CAN_IF1_ARB2_REG] = 0x1A,
- [C_CAN_IF1_MSGCTRL_REG] = 0x1C,
- [C_CAN_IF1_DATA1_REG] = 0x1E,
- [C_CAN_IF1_DATA2_REG] = 0x20,
- [C_CAN_IF1_DATA3_REG] = 0x22,
- [C_CAN_IF1_DATA4_REG] = 0x24,
- [C_CAN_IF2_COMREQ_REG] = 0x40,
- [C_CAN_IF2_COMMSK_REG] = 0x42,
- [C_CAN_IF2_MASK1_REG] = 0x44,
- [C_CAN_IF2_MASK2_REG] = 0x46,
- [C_CAN_IF2_ARB1_REG] = 0x48,
- [C_CAN_IF2_ARB2_REG] = 0x4A,
- [C_CAN_IF2_MSGCTRL_REG] = 0x4C,
- [C_CAN_IF2_DATA1_REG] = 0x4E,
- [C_CAN_IF2_DATA2_REG] = 0x50,
- [C_CAN_IF2_DATA3_REG] = 0x52,
- [C_CAN_IF2_DATA4_REG] = 0x54,
- [C_CAN_TXRQST1_REG] = 0x80,
- [C_CAN_TXRQST2_REG] = 0x82,
- [C_CAN_NEWDAT1_REG] = 0x90,
- [C_CAN_NEWDAT2_REG] = 0x92,
- [C_CAN_INTPND1_REG] = 0xA0,
- [C_CAN_INTPND2_REG] = 0xA2,
- [C_CAN_MSGVAL1_REG] = 0xB0,
- [C_CAN_MSGVAL2_REG] = 0xB2,
-};
-
-static const u16 reg_map_d_can[] = {
- [C_CAN_CTRL_REG] = 0x00,
- [C_CAN_CTRL_EX_REG] = 0x02,
- [C_CAN_STS_REG] = 0x04,
- [C_CAN_ERR_CNT_REG] = 0x08,
- [C_CAN_BTR_REG] = 0x0C,
- [C_CAN_BRPEXT_REG] = 0x0E,
- [C_CAN_INT_REG] = 0x10,
- [C_CAN_TEST_REG] = 0x14,
- [C_CAN_TXRQST1_REG] = 0x88,
- [C_CAN_TXRQST2_REG] = 0x8A,
- [C_CAN_NEWDAT1_REG] = 0x9C,
- [C_CAN_NEWDAT2_REG] = 0x9E,
- [C_CAN_INTPND1_REG] = 0xB0,
- [C_CAN_INTPND2_REG] = 0xB2,
- [C_CAN_MSGVAL1_REG] = 0xC4,
- [C_CAN_MSGVAL2_REG] = 0xC6,
- [C_CAN_IF1_COMREQ_REG] = 0x100,
- [C_CAN_IF1_COMMSK_REG] = 0x102,
- [C_CAN_IF1_MASK1_REG] = 0x104,
- [C_CAN_IF1_MASK2_REG] = 0x106,
- [C_CAN_IF1_ARB1_REG] = 0x108,
- [C_CAN_IF1_ARB2_REG] = 0x10A,
- [C_CAN_IF1_MSGCTRL_REG] = 0x10C,
- [C_CAN_IF1_DATA1_REG] = 0x110,
- [C_CAN_IF1_DATA2_REG] = 0x112,
- [C_CAN_IF1_DATA3_REG] = 0x114,
- [C_CAN_IF1_DATA4_REG] = 0x116,
- [C_CAN_IF2_COMREQ_REG] = 0x120,
- [C_CAN_IF2_COMMSK_REG] = 0x122,
- [C_CAN_IF2_MASK1_REG] = 0x124,
- [C_CAN_IF2_MASK2_REG] = 0x126,
- [C_CAN_IF2_ARB1_REG] = 0x128,
- [C_CAN_IF2_ARB2_REG] = 0x12A,
- [C_CAN_IF2_MSGCTRL_REG] = 0x12C,
- [C_CAN_IF2_DATA1_REG] = 0x130,
- [C_CAN_IF2_DATA2_REG] = 0x132,
- [C_CAN_IF2_DATA3_REG] = 0x134,
- [C_CAN_IF2_DATA4_REG] = 0x136,
-};
-
-enum c_can_dev_id {
- BOSCH_C_CAN_PLATFORM,
- BOSCH_C_CAN,
- BOSCH_D_CAN,
-};
-
-/* c_can private data structure */
-struct c_can_priv {
- struct can_priv can; /* must be the first member */
- struct napi_struct napi;
- struct net_device *dev;
- struct device *device;
- int tx_object;
- int current_status;
- int last_status;
- u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
- void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
- void __iomem *base;
- const u16 *regs;
- unsigned long irq_flags; /* for request_irq() */
- unsigned int tx_next;
- unsigned int tx_echo;
- void *priv; /* for board-specific data */
- u16 irqstatus;
- enum c_can_dev_id type;
- u32 __iomem *raminit_ctrlreg;
- unsigned int instance;
- void (*raminit) (const struct c_can_priv *priv, bool enable);
-};
-
-struct net_device *alloc_c_can_dev(void);
-void free_c_can_dev(struct net_device *dev);
-int register_c_can_dev(struct net_device *dev);
-void unregister_c_can_dev(struct net_device *dev);
-
-#ifdef CONFIG_PM
-int c_can_power_up(struct net_device *dev);
-int c_can_power_down(struct net_device *dev);
-#endif
-
-#endif /* C_CAN_H */
diff --git a/c_can/c_can_pci.c b/c_can/c_can_pci.c
deleted file mode 100644
index b374be7..0000000
--- a/c_can/c_can_pci.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * PCI bus driver for Bosch C_CAN/D_CAN controller
- *
- * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
- *
- * Borrowed from c_can_platform.c
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/pci.h>
-
-#include <linux/can/dev.h>
-
-#include "c_can.h"
-
-enum c_can_pci_reg_align {
- C_CAN_REG_ALIGN_16,
- C_CAN_REG_ALIGN_32,
-};
-
-struct c_can_pci_data {
- /* Specify if is C_CAN or D_CAN */
- enum c_can_dev_id type;
- /* Set the register alignment in the memory */
- enum c_can_pci_reg_align reg_align;
- /* Set the frequency */
- unsigned int freq;
-};
-
-/*
- * 16-bit c_can registers can be arranged differently in the memory
- * architecture of different implementations. For example: 16-bit
- * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
- * Handle the same by providing a common read/write interface.
- */
-static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
- enum reg index)
-{
- return readw(priv->base + priv->regs[index]);
-}
-
-static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
- enum reg index, u16 val)
-{
- writew(val, priv->base + priv->regs[index]);
-}
-
-static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
- enum reg index)
-{
- return readw(priv->base + 2 * priv->regs[index]);
-}
-
-static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
- enum reg index, u16 val)
-{
- writew(val, priv->base + 2 * priv->regs[index]);
-}
-
-static int c_can_pci_probe(struct pci_dev *pdev,
-   const struct pci_device_id *ent)
-{
- struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
- struct c_can_priv *priv;
- struct net_device *dev;
- void __iomem *addr;
- int ret;
-
- ret = pci_enable_device(pdev);
- if (ret) {
- dev_err(&pdev->dev, "pci_enable_device FAILED\n");
- goto out;
- }
-
- ret = pci_request_regions(pdev, KBUILD_MODNAME);
- if (ret) {
- dev_err(&pdev->dev, "pci_request_regions FAILED\n");
- goto out_disable_device;
- }
-
- pci_set_master(pdev);
- pci_enable_msi(pdev);
-
- addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
- if (!addr) {
- dev_err(&pdev->dev,
- "device has no PCI memory resources, "
- "failing adapter\n");
- ret = -ENOMEM;
- goto out_release_regions;
- }
-
- /* allocate the c_can device */
- dev = alloc_c_can_dev();
- if (!dev) {
- ret = -ENOMEM;
- goto out_iounmap;
- }
-
- priv = netdev_priv(dev);
- pci_set_drvdata(pdev, dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- dev->irq = pdev->irq;
- priv->base = addr;
-
- if (!c_can_pci_data->freq) {
- dev_err(&pdev->dev, "no clock frequency defined\n");
- ret = -ENODEV;
- goto out_free_c_can;
- } else {
- priv->can.clock.freq = c_can_pci_data->freq;
- }
-
- /* Configure CAN type */
- switch (c_can_pci_data->type) {
- case BOSCH_C_CAN:
- priv->regs = reg_map_c_can;
- break;
- case BOSCH_D_CAN:
- priv->regs = reg_map_d_can;
- priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
- break;
- default:
- ret = -EINVAL;
- goto out_free_c_can;
- }
-
- /* Configure access to registers */
- switch (c_can_pci_data->reg_align) {
- case C_CAN_REG_ALIGN_32:
- priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
- priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
- break;
- case C_CAN_REG_ALIGN_16:
- priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
- priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
- break;
- default:
- ret = -EINVAL;
- goto out_free_c_can;
- }
-
- ret = register_c_can_dev(dev);
- if (ret) {
- dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
- KBUILD_MODNAME, ret);
- goto out_free_c_can;
- }
-
- dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
- KBUILD_MODNAME, priv->regs, dev->irq);
-
- return 0;
-
-out_free_c_can:
- pci_set_drvdata(pdev, NULL);
- free_c_can_dev(dev);
-out_iounmap:
- pci_iounmap(pdev, addr);
-out_release_regions:
- pci_disable_msi(pdev);
- pci_clear_master(pdev);
- pci_release_regions(pdev);
-out_disable_device:
- pci_disable_device(pdev);
-out:
- return ret;
-}
-
-static void c_can_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(dev);
-
- unregister_c_can_dev(dev);
-
- pci_set_drvdata(pdev, NULL);
- free_c_can_dev(dev);
-
- pci_iounmap(pdev, priv->base);
- pci_disable_msi(pdev);
- pci_clear_master(pdev);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static struct c_can_pci_data c_can_sta2x11= {
- .type = BOSCH_C_CAN,
- .reg_align = C_CAN_REG_ALIGN_32,
- .freq = 52000000, /* 52 Mhz */
-};
-
-#define C_CAN_ID(_vend, _dev, _driverdata) { \
- PCI_DEVICE(_vend, _dev), \
- .driver_data = (unsigned long)&_driverdata, \
-}
-static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
- C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
- c_can_sta2x11),
- {},
-};
-static struct pci_driver c_can_pci_driver = {
- .name = KBUILD_MODNAME,
- .id_table = c_can_pci_tbl,
- .probe = c_can_pci_probe,
- .remove = c_can_pci_remove,
-};
-
-module_pci_driver(c_can_pci_driver);
-
-MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
-MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
diff --git a/c_can/c_can_platform.c b/c_can/c_can_platform.c
deleted file mode 100644
index d63b919..0000000
--- a/c_can/c_can_platform.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Platform CAN bus driver for Bosch C_CAN controller
- *
- * Copyright (C) 2010 ST Microelectronics
- * Bhupesh Sharma <bhupesh.sharma@st.com>
- *
- * Borrowed heavily from the C_CAN driver originally written by:
- * Copyright (C) 2007
- * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
- * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
- *
- * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
- * Bosch C_CAN user manual can be obtained from:
- * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
- * users_manual_c_can.pdf
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/list.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
-
-#include <linux/can/dev.h>
-
-#include "c_can.h"
-
-#define CAN_RAMINIT_START_MASK(i) (1 << (i))
-
-/*
- * 16-bit c_can registers can be arranged differently in the memory
- * architecture of different implementations. For example: 16-bit
- * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
- * Handle the same by providing a common read/write interface.
- */
-static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
- enum reg index)
-{
- return readw(priv->base + priv->regs[index]);
-}
-
-static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
- enum reg index, u16 val)
-{
- writew(val, priv->base + priv->regs[index]);
-}
-
-static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
- enum reg index)
-{
- return readw(priv->base + 2 * priv->regs[index]);
-}
-
-static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
- enum reg index, u16 val)
-{
- writew(val, priv->base + 2 * priv->regs[index]);
-}
-
-static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
-{
- u32 val;
-
- val = readl(priv->raminit_ctrlreg);
- if (enable)
- val |= CAN_RAMINIT_START_MASK(priv->instance);
- else
- val &= ~CAN_RAMINIT_START_MASK(priv->instance);
- writel(val, priv->raminit_ctrlreg);
-}
-
-static struct platform_device_id c_can_id_table[] = {
- [BOSCH_C_CAN_PLATFORM] = {
- .name = KBUILD_MODNAME,
- .driver_data = BOSCH_C_CAN,
- },
- [BOSCH_C_CAN] = {
- .name = "c_can",
- .driver_data = BOSCH_C_CAN,
- },
- [BOSCH_D_CAN] = {
- .name = "d_can",
- .driver_data = BOSCH_D_CAN,
- }, {
- }
-};
-MODULE_DEVICE_TABLE(platform, c_can_id_table);
-
-static const struct of_device_id c_can_of_table[] = {
- { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
- { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
- { /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, c_can_of_table);
-
-static int c_can_plat_probe(struct platform_device *pdev)
-{
- int ret;
- void __iomem *addr;
- struct net_device *dev;
- struct c_can_priv *priv;
- const struct of_device_id *match;
- const struct platform_device_id *id;
- struct pinctrl *pinctrl;
- struct resource *mem, *res;
- int irq;
- struct clk *clk;
-
- if (pdev->dev.of_node) {
- match = of_match_device(c_can_of_table, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Failed to find matching dt id\n");
- ret = -EINVAL;
- goto exit;
- }
- id = match->data;
- } else {
- id = platform_get_device_id(pdev);
- }
-
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&pdev->dev,
- "failed to configure pins from driver\n");
-
- /* get the appropriate clk */
- clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "no clock defined\n");
- ret = -ENODEV;
- goto exit;
- }
-
- /* get the platform data */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!mem || irq <= 0) {
- ret = -ENODEV;
- goto exit_free_clk;
- }
-
- if (!request_mem_region(mem->start, resource_size(mem),
- KBUILD_MODNAME)) {
- dev_err(&pdev->dev, "resource unavailable\n");
- ret = -ENODEV;
- goto exit_free_clk;
- }
-
- addr = ioremap(mem->start, resource_size(mem));
- if (!addr) {
- dev_err(&pdev->dev, "failed to map can port\n");
- ret = -ENOMEM;
- goto exit_release_mem;
- }
-
- /* allocate the c_can device */
- dev = alloc_c_can_dev();
- if (!dev) {
- ret = -ENOMEM;
- goto exit_iounmap;
- }
-
- priv = netdev_priv(dev);
- switch (id->driver_data) {
- case BOSCH_C_CAN:
- priv->regs = reg_map_c_can;
- switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
- case IORESOURCE_MEM_32BIT:
- priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
- priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
- break;
- case IORESOURCE_MEM_16BIT:
- default:
- priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
- priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
- break;
- }
- break;
- case BOSCH_D_CAN:
- priv->regs = reg_map_d_can;
- priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
- priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
- priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
-
- if (pdev->dev.of_node)
- priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
- else
- priv->instance = pdev->id;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->raminit_ctrlreg = devm_request_and_ioremap(&pdev->dev, res);
- if (!priv->raminit_ctrlreg || priv->instance < 0)
- dev_info(&pdev->dev, "control memory is not used for raminit\n");
- else
- priv->raminit = c_can_hw_raminit;
- break;
- default:
- ret = -EINVAL;
- goto exit_free_device;
- }
-
- dev->irq = irq;
- priv->base = addr;
- priv->device = &pdev->dev;
- priv->can.clock.freq = clk_get_rate(clk);
- priv->priv = clk;
- priv->type = id->driver_data;
-
- platform_set_drvdata(pdev, dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- ret = register_c_can_dev(dev);
- if (ret) {
- dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
- KBUILD_MODNAME, ret);
- goto exit_free_device;
- }
-
- dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
- KBUILD_MODNAME, priv->base, dev->irq);
- return 0;
-
-exit_free_device:
- platform_set_drvdata(pdev, NULL);
- free_c_can_dev(dev);
-exit_iounmap:
- iounmap(addr);
-exit_release_mem:
- release_mem_region(mem->start, resource_size(mem));
-exit_free_clk:
- clk_put(clk);
-exit:
- dev_err(&pdev->dev, "probe failed\n");
-
- return ret;
-}
-
-static int c_can_plat_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(dev);
- struct resource *mem;
-
- unregister_c_can_dev(dev);
- platform_set_drvdata(pdev, NULL);
-
- free_c_can_dev(dev);
- iounmap(priv->base);
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, resource_size(mem));
-
- clk_put(priv->priv);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
-{
- int ret;
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(ndev);
-
- if (priv->type != BOSCH_D_CAN) {
- dev_warn(&pdev->dev, "Not supported\n");
- return 0;
- }
-
- if (netif_running(ndev)) {
- netif_stop_queue(ndev);
- netif_device_detach(ndev);
- }
-
- ret = c_can_power_down(ndev);
- if (ret) {
- netdev_err(ndev, "failed to enter power down mode\n");
- return ret;
- }
-
- priv->can.state = CAN_STATE_SLEEPING;
-
- return 0;
-}
-
-static int c_can_resume(struct platform_device *pdev)
-{
- int ret;
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(ndev);
-
- if (priv->type != BOSCH_D_CAN) {
- dev_warn(&pdev->dev, "Not supported\n");
- return 0;
- }
-
- ret = c_can_power_up(ndev);
- if (ret) {
- netdev_err(ndev, "Still in power down mode\n");
- return ret;
- }
-
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
-
- if (netif_running(ndev)) {
- netif_device_attach(ndev);
- netif_start_queue(ndev);
- }
-
- return 0;
-}
-#else
-#define c_can_suspend NULL
-#define c_can_resume NULL
-#endif
-
-static struct platform_driver c_can_plat_driver = {
- .driver = {
- .name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(c_can_of_table),
- },
- .probe = c_can_plat_probe,
- .remove = c_can_plat_remove,
- .suspend = c_can_suspend,
- .resume = c_can_resume,
- .id_table = c_can_id_table,
-};
-
-module_platform_driver(c_can_plat_driver);
-
-MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
diff --git a/c_can/rtcan_c_can.c b/c_can/rtcan_c_can.c
new file mode 100644
index 0000000..2282b1a
--- /dev/null
+++ b/c_can/rtcan_c_can.c
@@ -0,0 +1,1292 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * TX and RX NAPI implementation has been borrowed from at91 CAN driver
+ * written by:
+ * Copyright
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
+ * (C) 2008, 2009 by Marc Kleine-Budde <kernel@pengutronix.de>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "c_can.h"
+
+/* Number of interface registers */
+#define IF_ENUM_REG_LEN 11
+#define C_CAN_IFACE(reg, iface) (C_CAN_IF1_##reg + (iface) *
IF_ENUM_REG_LEN)
+
+/* control extension register D_CAN specific */
+#define CONTROL_EX_PDR BIT(8)
+
+/* control register */
+#define CONTROL_TEST BIT(7)
+#define CONTROL_CCE BIT(6)
+#define CONTROL_DISABLE_AR BIT(5)
+#define CONTROL_ENABLE_AR (0 << 5)
+#define CONTROL_EIE BIT(3)
+#define CONTROL_SIE BIT(2)
+#define CONTROL_IE BIT(1)
+#define CONTROL_INIT BIT(0)
+
+/* test register */
+#define TEST_RX BIT(7)
+#define TEST_TX1 BIT(6)
+#define TEST_TX2 BIT(5)
+#define TEST_LBACK BIT(4)
+#define TEST_SILENT BIT(3)
+#define TEST_BASIC BIT(2)
+
+/* status register */
+#define STATUS_PDA BIT(10)
+#define STATUS_BOFF BIT(7)
+#define STATUS_EWARN BIT(6)
+#define STATUS_EPASS BIT(5)
+#define STATUS_RXOK BIT(4)
+#define STATUS_TXOK BIT(3)
+
+/* error counter register */
+#define ERR_CNT_TEC_MASK 0xff
+#define ERR_CNT_TEC_SHIFT 0
+#define ERR_CNT_REC_SHIFT 8
+#define ERR_CNT_REC_MASK (0x7f << ERR_CNT_REC_SHIFT)
+#define ERR_CNT_RP_SHIFT 15
+#define ERR_CNT_RP_MASK (0x1 << ERR_CNT_RP_SHIFT)
+
+/* bit-timing register */
+#define BTR_BRP_MASK 0x3f
+#define BTR_BRP_SHIFT 0
+#define BTR_SJW_SHIFT 6
+#define BTR_SJW_MASK (0x3 << BTR_SJW_SHIFT)
+#define BTR_TSEG1_SHIFT 8
+#define BTR_TSEG1_MASK (0xf << BTR_TSEG1_SHIFT)
+#define BTR_TSEG2_SHIFT 12
+#define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT)
+
+/* brp extension register */
+#define BRP_EXT_BRPE_MASK 0x0f
+#define BRP_EXT_BRPE_SHIFT 0
+
+/* IFx command request */
+#define IF_COMR_BUSY BIT(15)
+
+/* IFx command mask */
+#define IF_COMM_WR BIT(7)
+#define IF_COMM_MASK BIT(6)
+#define IF_COMM_ARB BIT(5)
+#define IF_COMM_CONTROL BIT(4)
+#define IF_COMM_CLR_INT_PND BIT(3)
+#define IF_COMM_TXRQST BIT(2)
+#define IF_COMM_DATAA BIT(1)
+#define IF_COMM_DATAB BIT(0)
+#define IF_COMM_ALL (IF_COMM_MASK | IF_COMM_ARB | \
+ IF_COMM_CONTROL | IF_COMM_TXRQST | \
+ IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* IFx arbitration */
+#define IF_ARB_MSGVAL BIT(15)
+#define IF_ARB_MSGXTD BIT(14)
+#define IF_ARB_TRANSMIT BIT(13)
+
+/* IFx message control */
+#define IF_MCONT_NEWDAT BIT(15)
+#define IF_MCONT_MSGLST BIT(14)
+#define IF_MCONT_CLR_MSGLST (0 << 14)
+#define IF_MCONT_INTPND BIT(13)
+#define IF_MCONT_UMASK BIT(12)
+#define IF_MCONT_TXIE BIT(11)
+#define IF_MCONT_RXIE BIT(10)
+#define IF_MCONT_RMTEN BIT(9)
+#define IF_MCONT_TXRQST BIT(8)
+#define IF_MCONT_EOB BIT(7)
+#define IF_MCONT_DLC_MASK 0xf
+
+/*
+ * IFx register masks:
+ * allow easy operation on 16-bit registers when the
+ * argument is 32-bit instead
+ */
+#define IFX_WRITE_LOW_16BIT(x) ((x) & 0xFFFF)
+#define IFX_WRITE_HIGH_16BIT(x) (((x) & 0xFFFF0000) >> 16)
+
+/* message object split */
+#define C_CAN_NO_OF_OBJECTS 32
+#define C_CAN_MSG_OBJ_RX_NUM 16
+#define C_CAN_MSG_OBJ_TX_NUM 16
+
+#define C_CAN_MSG_OBJ_RX_FIRST 1
+#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
+ C_CAN_MSG_OBJ_RX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
+#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
+ C_CAN_MSG_OBJ_TX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_RX_SPLIT 9
+#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
+
+#define C_CAN_NEXT_MSG_OBJ_MASK (C_CAN_MSG_OBJ_TX_NUM - 1)
+#define RECEIVE_OBJECT_BITS 0x0000ffff
+
+/* status interrupt */
+#define STATUS_INTERRUPT 0x8000
+
+/* global interrupt masks */
+#define ENABLE_ALL_INTERRUPTS 1
+#define DISABLE_ALL_INTERRUPTS 0
+
+/* minimum timeout for checking BUSY status */
+#define MIN_TIMEOUT_VALUE 6
+
+/* Wait for ~1 sec for INIT bit */
+#define INIT_WAIT_MS 1000
+
+/* napi related */
+#define C_CAN_NAPI_WEIGHT C_CAN_MSG_OBJ_RX_NUM
+
+/* c_can lec values */
+enum c_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,
+};
+
+/*
+ * c_can error types:
+ * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
+ */
+enum c_can_bus_error_types {
+ C_CAN_NO_ERROR = 0,
+ C_CAN_BUS_OFF,
+ C_CAN_ERROR_WARNING,
+ C_CAN_ERROR_PASSIVE,
+};
+
+static const struct can_bittiming_const c_can_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2, /* 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,
+};
+
+static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_enable(priv->device);
+}
+
+static inline void c_can_pm_runtime_disable(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_disable(priv->device);
+}
+
+static inline void c_can_pm_runtime_get_sync(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_get_sync(priv->device);
+}
+
+static inline void c_can_pm_runtime_put_sync(const struct c_can_priv *priv)
+{
+ if (priv->device)
+ pm_runtime_put_sync(priv->device);
+}
+
+static inline void c_can_reset_ram(const struct c_can_priv *priv, bool
enable)
+{
+ if (priv->raminit)
+ priv->raminit(priv, enable);
+}
+
+static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
+{
+ return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
+ C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
+{
+ return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
+ C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static u32 c_can_read_reg32(struct c_can_priv *priv, enum reg index)
+{
+ u32 val = priv->read_reg(priv, index);
+ val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
+ return val;
+}
+
+static void c_can_enable_all_interrupts(struct c_can_priv *priv,
+ int enable)
+{
+ unsigned int cntrl_save = priv->read_reg(priv,
+ C_CAN_CTRL_REG);
+
+ if (enable)
+ cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
+ else
+ cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
+
+ priv->write_reg(priv, C_CAN_CTRL_REG, cntrl_save);
+}
+
+static inline int c_can_msg_obj_is_busy(struct c_can_priv *priv, int iface)
+{
+ int count = MIN_TIMEOUT_VALUE;
+
+ while (count && priv->read_reg(priv,
+ C_CAN_IFACE(COMREQ_REG, iface)) &
+ IF_COMR_BUSY) {
+ count--;
+ udelay(1);
+ }
+
+ if (!count)
+ return 1;
+
+ return 0;
+}
+
+static inline void c_can_object_get(struct net_device *dev,
+ int iface, int objno, int mask)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /*
+ * As per specs, after writting the message object number in the
+ * IF command request register the transfer b/w interface
+ * register and message RAM must be complete in 6 CAN-CLK
+ * period.
+ */
+ priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
+ IFX_WRITE_LOW_16BIT(mask));
+ priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
+ IFX_WRITE_LOW_16BIT(objno));
+
+ if (c_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object get\n");
+}
+
+static inline void c_can_object_put(struct net_device *dev,
+ int iface, int objno, int mask)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /*
+ * As per specs, after writting the message object number in the
+ * IF command request register the transfer b/w interface
+ * register and message RAM must be complete in 6 CAN-CLK
+ * period.
+ */
+ priv->write_reg(priv, C_CAN_IFACE(COMMSK_REG, iface),
+ (IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
+ priv->write_reg(priv, C_CAN_IFACE(COMREQ_REG, iface),
+ IFX_WRITE_LOW_16BIT(objno));
+
+ if (c_can_msg_obj_is_busy(priv, iface))
+ netdev_err(dev, "timed out in object put\n");
+}
+
+static void c_can_write_msg_object(struct net_device *dev,
+ int iface, struct can_frame *frame, int objno)
+{
+ int i;
+ u16 flags = 0;
+ unsigned int id;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(frame->can_id & CAN_RTR_FLAG))
+ flags |= IF_ARB_TRANSMIT;
+
+ if (frame->can_id & CAN_EFF_FLAG) {
+ id = frame->can_id & CAN_EFF_MASK;
+ flags |= IF_ARB_MSGXTD;
+ } else
+ id = ((frame->can_id & CAN_SFF_MASK) << 18);
+
+ flags |= IF_ARB_MSGVAL;
+
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
+ IFX_WRITE_LOW_16BIT(id));
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), flags |
+ IFX_WRITE_HIGH_16BIT(id));
+
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ priv->write_reg(priv, C_CAN_IFACE(DATA1_REG, iface) + i / 2,
+ frame->data[i] | (frame->data[i + 1] << 8));
+ }
+
+ /* enable interrupt for this message object */
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
+ frame->can_dlc);
+ c_can_object_put(dev, iface, objno, IF_COMM_ALL);
+}
+
+static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
+ int iface, int ctrl_mask,
+ int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
+ c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+
+}
+
+static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device
*dev,
+ int iface,
+ int ctrl_mask)
+{
+ int i;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ ctrl_mask & ~(IF_MCONT_MSGLST |
+ IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ c_can_object_put(dev, iface, i, IF_COMM_CONTROL);
+ }
+}
+
+static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
+ int iface, int ctrl_mask,
+ int obj)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ ctrl_mask & ~(IF_MCONT_MSGLST |
+ IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+ c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
+}
+
+static void c_can_handle_lost_msg_obj(struct net_device *dev,
+ int iface, int objno)
+{
+ struct c_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);
+
+ c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
+ IF_MCONT_CLR_MSGLST);
+
+ c_can_object_put(dev, 0, objno, IF_COMM_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 c_can_read_msg_object(struct net_device *dev, int iface, int
ctrl)
+{
+ u16 flags, data;
+ int i;
+ unsigned int val;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ skb = alloc_can_skb(dev, &frame);
+ if (!skb) {
+ stats->rx_dropped++;
+ return -ENOMEM;
+ }
+
+ frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+
+ flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
+ val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
+ (flags << 16);
+
+ if (flags & IF_ARB_MSGXTD)
+ frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ frame->can_id = (val >> 18) & CAN_SFF_MASK;
+
+ if (flags & IF_ARB_TRANSMIT)
+ frame->can_id |= CAN_RTR_FLAG;
+ else {
+ for (i = 0; i < frame->can_dlc; i += 2) {
+ data = priv->read_reg(priv,
+ C_CAN_IFACE(DATA1_REG, iface) + i / 2);
+ frame->data[i] = data;
+ frame->data[i + 1] = data >> 8;
+ }
+ }
+
+ netif_receive_skb(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += frame->can_dlc;
+
+ return 0;
+}
+
+static void c_can_setup_receive_object(struct net_device *dev, int iface,
+ int objno, unsigned int mask,
+ unsigned int id, unsigned int mcont)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
+ IFX_WRITE_LOW_16BIT(mask));
+
+ /* According to C_CAN documentation, the reserved bit
+ * in IFx_MASK2 register is fixed 1
+ */
+ priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
+ IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
+
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
+ IFX_WRITE_LOW_16BIT(id));
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface),
+ (IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
+
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
+ c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
+ c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
+}
+
+static void c_can_inval_msg_object(struct net_device *dev, int iface, int
objno)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
+ priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
+ priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), 0);
+
+ c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);
+
+ netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
+ c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
+}
+
+static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int
objno)
+{
+ int val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
+
+ /*
+ * as transmission request register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (val & (1 << (objno - 1)))
+ return 1;
+
+ return 0;
+}
+
+static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ u32 msg_obj_no;
+ struct c_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 */
+ c_can_write_msg_object(dev, 0, frame, msg_obj_no);
+ can_put_echo_skb(skb, dev, msg_obj_no - C_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 (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
+ (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
+ netif_stop_queue(dev);
+
+ return NETDEV_TX_OK;
+}
+
+static int c_can_set_bittiming(struct net_device *dev)
+{
+ unsigned int reg_btr, reg_brpe, ctrl_save;
+ u8 brp, brpe, sjw, tseg1, tseg2;
+ u32 ten_bit_brp;
+ struct c_can_priv *priv = netdev_priv(dev);
+ const struct can_bittiming *bt = &priv->can.bittiming;
+
+ /* c_can provides a 6-bit brp and 4-bit brpe fields */
+ ten_bit_brp = bt->brp - 1;
+ brp = ten_bit_brp & BTR_BRP_MASK;
+ brpe = ten_bit_brp >> 6;
+
+ sjw = bt->sjw - 1;
+ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+ reg_btr = brp | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
+ (tseg2 << BTR_TSEG2_SHIFT);
+ reg_brpe = brpe & BRP_EXT_BRPE_MASK;
+
+ netdev_info(dev,
+ "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
+
+ ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
+ priv->write_reg(priv, C_CAN_CTRL_REG,
+ ctrl_save | CONTROL_CCE | CONTROL_INIT);
+ priv->write_reg(priv, C_CAN_BTR_REG, reg_btr);
+ priv->write_reg(priv, C_CAN_BRPEXT_REG, reg_brpe);
+ priv->write_reg(priv, C_CAN_CTRL_REG, ctrl_save);
+
+ return 0;
+}
+
+/*
+ * Configure C_CAN message objects for Tx and Rx purposes:
+ * C_CAN provides a total of 32 message objects that can be configured
+ * either for Tx or Rx purposes. Here the first 16 message objects are
used as
+ * a reception FIFO. The end of reception FIFO is signified by the EoB bit
+ * being SET. The remaining 16 message objects are kept aside for Tx
purposes.
+ * See user guide document for further details on configuring message
+ * objects.
+ */
+static void c_can_configure_msg_objects(struct net_device *dev)
+{
+ int i;
+
+ /* first invalidate all message objects */
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_NO_OF_OBJECTS; i++)
+ c_can_inval_msg_object(dev, 0, i);
+
+ /* setup receive message objects */
+ for (i = C_CAN_MSG_OBJ_RX_FIRST; i < C_CAN_MSG_OBJ_RX_LAST; i++)
+ c_can_setup_receive_object(dev, 0, i, 0, 0,
+ (IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB);
+
+ c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
+ IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
+}
+
+/*
+ * Configure C_CAN chip:
+ * - enable/disable auto-retransmission
+ * - set operating mode
+ * - configure message objects
+ */
+static void c_can_chip_config(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* enable automatic retransmission */
+ priv->write_reg(priv, C_CAN_CTRL_REG,
+ CONTROL_ENABLE_AR);
+
+ if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
+    (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
+ /* loopback + silent mode : useful for hot self-test */
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG,
+ TEST_LBACK | TEST_SILENT);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ /* loopback mode : useful for self-test function */
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
+ } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ /* silent mode : bus-monitoring mode */
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
+ CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
+ } else
+ /* normal mode*/
+ priv->write_reg(priv, C_CAN_CTRL_REG,
+ CONTROL_EIE | CONTROL_SIE | CONTROL_IE);
+
+ /* configure message objects */
+ c_can_configure_msg_objects(dev);
+
+ /* set a `lec` value so that we can check for updates later */
+ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+
+ /* set bittiming params */
+ c_can_set_bittiming(dev);
+}
+
+static void c_can_start(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* basic c_can configuration */
+ c_can_chip_config(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 */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+}
+
+static void c_can_stop(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ /* disable all interrupts */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+ /* set the state as STOPPED */
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ switch (mode) {
+ case CAN_MODE_START:
+ c_can_start(dev);
+ netif_wake_queue(dev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int c_can_get_berr_counter(const struct net_device *dev,
+ struct can_berr_counter *bec)
+{
+ unsigned int reg_err_counter;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ c_can_pm_runtime_get_sync(priv);
+
+ reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
+ bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
+ ERR_CNT_REC_SHIFT;
+ bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
+
+ c_can_pm_runtime_put_sync(priv);
+
+ return 0;
+}
+
+/*
+ * theory of operation:
+ *
+ * priv->tx_echo holds the number of the oldest can_frame put for
+ * transmission into the hardware, but not yet ACKed by the CAN tx
+ * complete IRQ.
+ *
+ * We iterate from priv->tx_echo to priv->tx_next and check if the
+ * packet has been transmitted, echo it back to the CAN framework.
+ * If we discover a not yet transmitted packet, stop looking for more.
+ */
+static void c_can_do_tx(struct net_device *dev)
+{
+ u32 val;
+ u32 msg_obj_no;
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+
+ for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+ msg_obj_no = get_tx_echo_msg_obj(priv);
+ val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
+ if (!(val & (1 << (msg_obj_no - 1)))) {
+ can_get_echo_skb(dev,
+ msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+ stats->tx_bytes += priv->read_reg(priv,
+ C_CAN_IFACE(MSGCTRL_REG, 0))
+ & IF_MCONT_DLC_MASK;
+ stats->tx_packets++;
+ c_can_inval_msg_object(dev, 0, msg_obj_no);
+ } else {
+ break;
+ }
+ }
+
+ /* restart queue if wrap-up or if queue stalled on last pkt */
+ if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
+ ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
+ netif_wake_queue(dev);
+}
+
+/*
+ * theory of operation:
+ *
+ * c_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 C_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
+ *   C_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
+ *   C_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
+ *   C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
+ *   only this message object.
+ */
+static int c_can_do_rx_poll(struct net_device *dev, int quota)
+{
+ u32 num_rx_pkts = 0;
+ unsigned int msg_obj, msg_ctrl_save;
+ struct c_can_priv *priv = netdev_priv(dev);
+ u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG);
+
+ for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
+ msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
+ val = c_can_read_reg32(priv, C_CAN_INTPND1_REG),
+ msg_obj++) {
+ /*
+ * as interrupt pending register's bit n-1 corresponds to
+ * message object n, we need to handle the same properly.
+ */
+ if (val & (1 << (msg_obj - 1))) {
+ c_can_object_get(dev, 0, msg_obj, IF_COMM_ALL &
+ ~IF_COMM_TXRQST);
+ msg_ctrl_save = priv->read_reg(priv,
+ C_CAN_IFACE(MSGCTRL_REG, 0));
+
+ if (msg_ctrl_save & IF_MCONT_EOB)
+ return num_rx_pkts;
+
+ if (msg_ctrl_save & IF_MCONT_MSGLST) {
+ c_can_handle_lost_msg_obj(dev, 0, msg_obj);
+ num_rx_pkts++;
+ quota--;
+ continue;
+ }
+
+ if (!(msg_ctrl_save & IF_MCONT_NEWDAT))
+ continue;
+
+ /* read the data from the message object */
+ c_can_read_msg_object(dev, 0, msg_ctrl_save);
+
+ if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
+ c_can_mark_rx_msg_obj(dev, 0,
+ msg_ctrl_save, msg_obj);
+ else if (msg_obj > C_CAN_MSG_RX_LOW_LAST)
+ /* activate this msg obj */
+ c_can_activate_rx_msg_obj(dev, 0,
+ msg_ctrl_save, msg_obj);
+ else if (msg_obj == C_CAN_MSG_RX_LOW_LAST)
+ /* activate all lower message objects */
+ c_can_activate_all_lower_rx_msg_obj(dev,
+ 0, msg_ctrl_save);
+
+ num_rx_pkts++;
+ quota--;
+ }
+ }
+
+ return num_rx_pkts;
+}
+
+static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
+{
+ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+ (priv->current_status & LEC_UNUSED);
+}
+
+static int c_can_handle_state_change(struct net_device *dev,
+ enum c_can_bus_error_types error_type)
+{
+ unsigned int reg_err_counter;
+ unsigned int rx_err_passive;
+ struct c_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;
+
+ c_can_get_berr_counter(dev, &bec);
+ reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
+ rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
+ ERR_CNT_RP_SHIFT;
+
+ switch (error_type) {
+ case C_CAN_ERROR_WARNING:
+ /* error warning state */
+ priv->can.can_stats.error_warning++;
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = (bec.txerr > bec.rxerr) ?
+ CAN_ERR_CRTL_TX_WARNING :
+ CAN_ERR_CRTL_RX_WARNING;
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+
+ break;
+ case C_CAN_ERROR_PASSIVE:
+ /* error passive state */
+ priv->can.can_stats.error_passive++;
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (rx_err_passive)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ if (bec.txerr > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+
+ cf->data[6] = bec.txerr;
+ cf->data[7] = bec.rxerr;
+ break;
+ case C_CAN_BUS_OFF:
+ /* bus-off state */
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ /*
+ * disable all interrupts in bus-off mode to ensure that
+ * the CPU is not hogged down
+ */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int c_can_handle_bus_err(struct net_device *dev,
+ enum c_can_lec_type lec_type)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /*
+ * early exit if no lec update or no error.
+ * no lec update means that no CAN bus event has been detected
+ * since CPU wrote 0x7 value to status reg.
+ */
+ if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR)
+ return 0;
+
+ /* propagate the error condition to the CAN stack */
+ skb = alloc_can_err_skb(dev, &cf);
+ if (unlikely(!skb))
+ return 0;
+
+ /*
+ * check for 'last error code' which tells us the
+ * type of the last error to occur on the CAN bus
+ */
+
+ /* common for all type of bus errors */
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+ switch (lec_type) {
+ case LEC_STUFF_ERROR:
+ netdev_dbg(dev, "stuff error\n");
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ case LEC_FORM_ERROR:
+ netdev_dbg(dev, "form error\n");
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case LEC_ACK_ERROR:
+ netdev_dbg(dev, "ack error\n");
+ cf->data[3] |= (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[3] |= (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 */
+ priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+
+ return 1;
+}
+
+static int c_can_poll(struct napi_struct *napi, int quota)
+{
+ u16 irqstatus;
+ int lec_type = 0;
+ int work_done = 0;
+ struct net_device *dev = napi->dev;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ irqstatus = priv->irqstatus;
+ if (!irqstatus)
+ goto end;
+
+ /* status events have the highest priority */
+ if (irqstatus == STATUS_INTERRUPT) {
+ priv->current_status = priv->read_reg(priv,
+ C_CAN_STS_REG);
+
+ /* handle Tx/Rx events */
+ if (priv->current_status & STATUS_TXOK)
+ priv->write_reg(priv, C_CAN_STS_REG,
+ priv->current_status & ~STATUS_TXOK);
+
+ if (priv->current_status & STATUS_RXOK)
+ priv->write_reg(priv, C_CAN_STS_REG,
+ priv->current_status & ~STATUS_RXOK);
+
+ /* handle state changes */
+ if ((priv->current_status & STATUS_EWARN) &&
+ (!(priv->last_status & STATUS_EWARN))) {
+ netdev_dbg(dev, "entered error warning state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_ERROR_WARNING);
+ }
+ if ((priv->current_status & STATUS_EPASS) &&
+ (!(priv->last_status & STATUS_EPASS))) {
+ netdev_dbg(dev, "entered error passive state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_ERROR_PASSIVE);
+ }
+ if ((priv->current_status & STATUS_BOFF) &&
+ (!(priv->last_status & STATUS_BOFF))) {
+ netdev_dbg(dev, "entered bus off state\n");
+ work_done += c_can_handle_state_change(dev,
+ C_CAN_BUS_OFF);
+ }
+
+ /* handle bus recovery events */
+ if ((!(priv->current_status & STATUS_BOFF)) &&
+ (priv->last_status & STATUS_BOFF)) {
+ netdev_dbg(dev, "left bus off state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ if ((!(priv->current_status & STATUS_EPASS)) &&
+ (priv->last_status & STATUS_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 = c_can_has_and_handle_berr(priv);
+ if (lec_type)
+ work_done += c_can_handle_bus_err(dev, lec_type);
+ } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
+ (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
+ /* handle events corresponding to receive message objects */
+ work_done += c_can_do_rx_poll(dev, (quota - work_done));
+ } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
+ (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
+ /* handle events corresponding to transmit message objects */
+ c_can_do_tx(dev);
+ }
+
+end:
+ if (work_done < quota) {
+ napi_complete(napi);
+ /* enable all IRQs */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+ }
+
+ return work_done;
+}
+
+static irqreturn_t c_can_isr(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
+ if (!priv->irqstatus)
+ return IRQ_NONE;
+
+ /* disable all interrupts and schedule the NAPI */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ napi_schedule(&priv->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int c_can_open(struct net_device *dev)
+{
+ int err;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
+
+ /* open the can device */
+ err = open_candev(dev);
+ if (err) {
+ netdev_err(dev, "failed to open can device\n");
+ goto exit_open_fail;
+ }
+
+ /* register interrupt handler */
+ err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
+ dev);
+ if (err < 0) {
+ netdev_err(dev, "failed to request interrupt\n");
+ goto exit_irq_fail;
+ }
+
+ napi_enable(&priv->napi);
+
+ /* start the c_can controller */
+ c_can_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+exit_irq_fail:
+ close_candev(dev);
+exit_open_fail:
+ c_can_reset_ram(priv, false);
+ c_can_pm_runtime_put_sync(priv);
+ return err;
+}
+
+static int c_can_close(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+ c_can_stop(dev);
+ free_irq(dev->irq, dev);
+ close_candev(dev);
+
+ c_can_reset_ram(priv, false);
+ c_can_pm_runtime_put_sync(priv);
+
+ return 0;
+}
+
+struct net_device *alloc_c_can_dev(void)
+{
+ struct net_device *dev;
+ struct c_can_priv *priv;
+
+ dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
+ if (!dev)
+ return NULL;
+
+ priv = netdev_priv(dev);
+ netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
+
+ priv->dev = dev;
+ priv->can.bittiming_const = &c_can_bittiming_const;
+ priv->can.do_set_mode = c_can_set_mode;
+ priv->can.do_get_berr_counter = c_can_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+ CAN_CTRLMODE_LISTENONLY |
+ CAN_CTRLMODE_BERR_REPORTING;
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_c_can_dev);
+
+#ifdef CONFIG_PM
+int c_can_power_down(struct net_device *dev)
+{
+ u32 val;
+ unsigned long time_out;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(dev->flags & IFF_UP))
+ return 0;
+
+ WARN_ON(priv->type != BOSCH_D_CAN);
+
+ /* set PDR value so the device goes to power down mode */
+ val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
+ val |= CONTROL_EX_PDR;
+ priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
+
+ /* Wait for the PDA bit to get set */
+ time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
+ while (!(priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out))
+ return -ETIMEDOUT;
+
+ c_can_stop(dev);
+
+ c_can_reset_ram(priv, false);
+ c_can_pm_runtime_put_sync(priv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(c_can_power_down);
+
+int c_can_power_up(struct net_device *dev)
+{
+ u32 val;
+ unsigned long time_out;
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ if (!(dev->flags & IFF_UP))
+ return 0;
+
+ WARN_ON(priv->type != BOSCH_D_CAN);
+
+ c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
+
+ /* Clear PDR and INIT bits */
+ val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
+ val &= ~CONTROL_EX_PDR;
+ priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
+ val = priv->read_reg(priv, C_CAN_CTRL_REG);
+ val &= ~CONTROL_INIT;
+ priv->write_reg(priv, C_CAN_CTRL_REG, val);
+
+ /* Wait for the PDA bit to get clear */
+ time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
+ while ((priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
+ time_after(time_out, jiffies))
+ cpu_relax();
+
+ if (time_after(jiffies, time_out))
+ return -ETIMEDOUT;
+
+ c_can_start(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(c_can_power_up);
+#endif
+
+void free_c_can_dev(struct net_device *dev)
+{
+ free_candev(dev);
+}
+EXPORT_SYMBOL_GPL(free_c_can_dev);
+
+static const struct net_device_ops c_can_netdev_ops = {
+ .ndo_open = c_can_open,
+ .ndo_stop = c_can_close,
+ .ndo_start_xmit = c_can_start_xmit,
+};
+
+int register_c_can_dev(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+ int err;
+
+ c_can_pm_runtime_enable(priv);
+
+ dev->flags |= IFF_ECHO; /* we support local echo */
+ dev->netdev_ops = &c_can_netdev_ops;
+
+ err = register_candev(dev);
+ if (err)
+ c_can_pm_runtime_disable(priv);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_c_can_dev);
+
+void unregister_c_can_dev(struct net_device *dev)
+{
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ unregister_candev(dev);
+
+ c_can_pm_runtime_disable(priv);
+}
+EXPORT_SYMBOL_GPL(unregister_c_can_dev);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
diff --git a/c_can/rtcan_c_can.h b/c_can/rtcan_c_can.h
new file mode 100644
index 0000000..d2e1c21
--- /dev/null
+++ b/c_can/rtcan_c_can.h
@@ -0,0 +1,187 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef C_CAN_H
+#define C_CAN_H
+
+enum reg {
+ C_CAN_CTRL_REG = 0,
+ C_CAN_CTRL_EX_REG,
+ C_CAN_STS_REG,
+ C_CAN_ERR_CNT_REG,
+ C_CAN_BTR_REG,
+ C_CAN_INT_REG,
+ C_CAN_TEST_REG,
+ C_CAN_BRPEXT_REG,
+ C_CAN_IF1_COMREQ_REG,
+ C_CAN_IF1_COMMSK_REG,
+ C_CAN_IF1_MASK1_REG,
+ C_CAN_IF1_MASK2_REG,
+ C_CAN_IF1_ARB1_REG,
+ C_CAN_IF1_ARB2_REG,
+ C_CAN_IF1_MSGCTRL_REG,
+ C_CAN_IF1_DATA1_REG,
+ C_CAN_IF1_DATA2_REG,
+ C_CAN_IF1_DATA3_REG,
+ C_CAN_IF1_DATA4_REG,
+ C_CAN_IF2_COMREQ_REG,
+ C_CAN_IF2_COMMSK_REG,
+ C_CAN_IF2_MASK1_REG,
+ C_CAN_IF2_MASK2_REG,
+ C_CAN_IF2_ARB1_REG,
+ C_CAN_IF2_ARB2_REG,
+ C_CAN_IF2_MSGCTRL_REG,
+ C_CAN_IF2_DATA1_REG,
+ C_CAN_IF2_DATA2_REG,
+ C_CAN_IF2_DATA3_REG,
+ C_CAN_IF2_DATA4_REG,
+ C_CAN_TXRQST1_REG,
+ C_CAN_TXRQST2_REG,
+ C_CAN_NEWDAT1_REG,
+ C_CAN_NEWDAT2_REG,
+ C_CAN_INTPND1_REG,
+ C_CAN_INTPND2_REG,
+ C_CAN_MSGVAL1_REG,
+ C_CAN_MSGVAL2_REG,
+};
+
+static const u16 reg_map_c_can[] = {
+ [C_CAN_CTRL_REG] = 0x00,
+ [C_CAN_STS_REG] = 0x02,
+ [C_CAN_ERR_CNT_REG] = 0x04,
+ [C_CAN_BTR_REG] = 0x06,
+ [C_CAN_INT_REG] = 0x08,
+ [C_CAN_TEST_REG] = 0x0A,
+ [C_CAN_BRPEXT_REG] = 0x0C,
+ [C_CAN_IF1_COMREQ_REG] = 0x10,
+ [C_CAN_IF1_COMMSK_REG] = 0x12,
+ [C_CAN_IF1_MASK1_REG] = 0x14,
+ [C_CAN_IF1_MASK2_REG] = 0x16,
+ [C_CAN_IF1_ARB1_REG] = 0x18,
+ [C_CAN_IF1_ARB2_REG] = 0x1A,
+ [C_CAN_IF1_MSGCTRL_REG] = 0x1C,
+ [C_CAN_IF1_DATA1_REG] = 0x1E,
+ [C_CAN_IF1_DATA2_REG] = 0x20,
+ [C_CAN_IF1_DATA3_REG] = 0x22,
+ [C_CAN_IF1_DATA4_REG] = 0x24,
+ [C_CAN_IF2_COMREQ_REG] = 0x40,
+ [C_CAN_IF2_COMMSK_REG] = 0x42,
+ [C_CAN_IF2_MASK1_REG] = 0x44,
+ [C_CAN_IF2_MASK2_REG] = 0x46,
+ [C_CAN_IF2_ARB1_REG] = 0x48,
+ [C_CAN_IF2_ARB2_REG] = 0x4A,
+ [C_CAN_IF2_MSGCTRL_REG] = 0x4C,
+ [C_CAN_IF2_DATA1_REG] = 0x4E,
+ [C_CAN_IF2_DATA2_REG] = 0x50,
+ [C_CAN_IF2_DATA3_REG] = 0x52,
+ [C_CAN_IF2_DATA4_REG] = 0x54,
+ [C_CAN_TXRQST1_REG] = 0x80,
+ [C_CAN_TXRQST2_REG] = 0x82,
+ [C_CAN_NEWDAT1_REG] = 0x90,
+ [C_CAN_NEWDAT2_REG] = 0x92,
+ [C_CAN_INTPND1_REG] = 0xA0,
+ [C_CAN_INTPND2_REG] = 0xA2,
+ [C_CAN_MSGVAL1_REG] = 0xB0,
+ [C_CAN_MSGVAL2_REG] = 0xB2,
+};
+
+static const u16 reg_map_d_can[] = {
+ [C_CAN_CTRL_REG] = 0x00,
+ [C_CAN_CTRL_EX_REG] = 0x02,
+ [C_CAN_STS_REG] = 0x04,
+ [C_CAN_ERR_CNT_REG] = 0x08,
+ [C_CAN_BTR_REG] = 0x0C,
+ [C_CAN_BRPEXT_REG] = 0x0E,
+ [C_CAN_INT_REG] = 0x10,
+ [C_CAN_TEST_REG] = 0x14,
+ [C_CAN_TXRQST1_REG] = 0x88,
+ [C_CAN_TXRQST2_REG] = 0x8A,
+ [C_CAN_NEWDAT1_REG] = 0x9C,
+ [C_CAN_NEWDAT2_REG] = 0x9E,
+ [C_CAN_INTPND1_REG] = 0xB0,
+ [C_CAN_INTPND2_REG] = 0xB2,
+ [C_CAN_MSGVAL1_REG] = 0xC4,
+ [C_CAN_MSGVAL2_REG] = 0xC6,
+ [C_CAN_IF1_COMREQ_REG] = 0x100,
+ [C_CAN_IF1_COMMSK_REG] = 0x102,
+ [C_CAN_IF1_MASK1_REG] = 0x104,
+ [C_CAN_IF1_MASK2_REG] = 0x106,
+ [C_CAN_IF1_ARB1_REG] = 0x108,
+ [C_CAN_IF1_ARB2_REG] = 0x10A,
+ [C_CAN_IF1_MSGCTRL_REG] = 0x10C,
+ [C_CAN_IF1_DATA1_REG] = 0x110,
+ [C_CAN_IF1_DATA2_REG] = 0x112,
+ [C_CAN_IF1_DATA3_REG] = 0x114,
+ [C_CAN_IF1_DATA4_REG] = 0x116,
+ [C_CAN_IF2_COMREQ_REG] = 0x120,
+ [C_CAN_IF2_COMMSK_REG] = 0x122,
+ [C_CAN_IF2_MASK1_REG] = 0x124,
+ [C_CAN_IF2_MASK2_REG] = 0x126,
+ [C_CAN_IF2_ARB1_REG] = 0x128,
+ [C_CAN_IF2_ARB2_REG] = 0x12A,
+ [C_CAN_IF2_MSGCTRL_REG] = 0x12C,
+ [C_CAN_IF2_DATA1_REG] = 0x130,
+ [C_CAN_IF2_DATA2_REG] = 0x132,
+ [C_CAN_IF2_DATA3_REG] = 0x134,
+ [C_CAN_IF2_DATA4_REG] = 0x136,
+};
+
+enum c_can_dev_id {
+ BOSCH_C_CAN_PLATFORM,
+ BOSCH_C_CAN,
+ BOSCH_D_CAN,
+};
+
+/* c_can private data structure */
+struct c_can_priv {
+ struct can_priv can; /* must be the first member */
+ struct napi_struct napi;
+ struct net_device *dev;
+ struct device *device;
+ int tx_object;
+ int current_status;
+ int last_status;
+ u16 (*read_reg) (struct c_can_priv *priv, enum reg index);
+ void (*write_reg) (struct c_can_priv *priv, enum reg index, u16 val);
+ void __iomem *base;
+ const u16 *regs;
+ unsigned long irq_flags; /* for request_irq() */
+ unsigned int tx_next;
+ unsigned int tx_echo;
+ void *priv; /* for board-specific data */
+ u16 irqstatus;
+ enum c_can_dev_id type;
+ u32 __iomem *raminit_ctrlreg;
+ unsigned int instance;
+ void (*raminit) (const struct c_can_priv *priv, bool enable);
+};
+
+struct net_device *alloc_c_can_dev(void);
+void free_c_can_dev(struct net_device *dev);
+int register_c_can_dev(struct net_device *dev);
+void unregister_c_can_dev(struct net_device *dev);
+
+#ifdef CONFIG_PM
+int c_can_power_up(struct net_device *dev);
+int c_can_power_down(struct net_device *dev);
+#endif
+
+#endif /* C_CAN_H */
diff --git a/c_can/rtcan_c_can_pci.c b/c_can/rtcan_c_can_pci.c
new file mode 100644
index 0000000..b374be7
--- /dev/null
+++ b/c_can/rtcan_c_can_pci.c
@@ -0,0 +1,221 @@
+/*
+ * PCI bus driver for Bosch C_CAN/D_CAN controller
+ *
+ * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
+ *
+ * Borrowed from c_can_platform.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+enum c_can_pci_reg_align {
+ C_CAN_REG_ALIGN_16,
+ C_CAN_REG_ALIGN_32,
+};
+
+struct c_can_pci_data {
+ /* Specify if is C_CAN or D_CAN */
+ enum c_can_dev_id type;
+ /* Set the register alignment in the memory */
+ enum c_can_pci_reg_align reg_align;
+ /* Set the frequency */
+ unsigned int freq;
+};
+
+/*
+ * 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_pci_read_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + priv->regs[index]);
+}
+
+static u16 c_can_pci_read_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + 2 * priv->regs[index]);
+}
+
+static int c_can_pci_probe(struct pci_dev *pdev,
+   const struct pci_device_id *ent)
+{
+ struct c_can_pci_data *c_can_pci_data = (void *)ent->driver_data;
+ struct c_can_priv *priv;
+ struct net_device *dev;
+ void __iomem *addr;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device FAILED\n");
+ goto out;
+ }
+
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_request_regions FAILED\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+ pci_enable_msi(pdev);
+
+ addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!addr) {
+ dev_err(&pdev->dev,
+ "device has no PCI memory resources, "
+ "failing adapter\n");
+ ret = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ /* allocate the c_can device */
+ dev = alloc_c_can_dev();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out_iounmap;
+ }
+
+ priv = netdev_priv(dev);
+ pci_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ dev->irq = pdev->irq;
+ priv->base = addr;
+
+ if (!c_can_pci_data->freq) {
+ dev_err(&pdev->dev, "no clock frequency defined\n");
+ ret = -ENODEV;
+ goto out_free_c_can;
+ } else {
+ priv->can.clock.freq = c_can_pci_data->freq;
+ }
+
+ /* Configure CAN type */
+ switch (c_can_pci_data->type) {
+ case BOSCH_C_CAN:
+ priv->regs = reg_map_c_can;
+ break;
+ case BOSCH_D_CAN:
+ priv->regs = reg_map_d_can;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_free_c_can;
+ }
+
+ /* Configure access to registers */
+ switch (c_can_pci_data->reg_align) {
+ case C_CAN_REG_ALIGN_32:
+ priv->read_reg = c_can_pci_read_reg_aligned_to_32bit;
+ priv->write_reg = c_can_pci_write_reg_aligned_to_32bit;
+ break;
+ case C_CAN_REG_ALIGN_16:
+ priv->read_reg = c_can_pci_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_pci_write_reg_aligned_to_16bit;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_free_c_can;
+ }
+
+ ret = register_c_can_dev(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, ret);
+ goto out_free_c_can;
+ }
+
+ dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+ KBUILD_MODNAME, priv->regs, dev->irq);
+
+ return 0;
+
+out_free_c_can:
+ pci_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+out_iounmap:
+ pci_iounmap(pdev, addr);
+out_release_regions:
+ pci_disable_msi(pdev);
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+out_disable_device:
+ pci_disable_device(pdev);
+out:
+ return ret;
+}
+
+static void c_can_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(dev);
+
+ unregister_c_can_dev(dev);
+
+ pci_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+
+ pci_iounmap(pdev, priv->base);
+ pci_disable_msi(pdev);
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct c_can_pci_data c_can_sta2x11= {
+ .type = BOSCH_C_CAN,
+ .reg_align = C_CAN_REG_ALIGN_32,
+ .freq = 52000000, /* 52 Mhz */
+};
+
+#define C_CAN_ID(_vend, _dev, _driverdata) { \
+ PCI_DEVICE(_vend, _dev), \
+ .driver_data = (unsigned long)&_driverdata, \
+}
+static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = {
+ C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN,
+ c_can_sta2x11),
+ {},
+};
+static struct pci_driver c_can_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = c_can_pci_tbl,
+ .probe = c_can_pci_probe,
+ .remove = c_can_pci_remove,
+};
+
+module_pci_driver(c_can_pci_driver);
+
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PCI CAN bus driver for Bosch C_CAN/D_CAN controller");
+MODULE_DEVICE_TABLE(pci, c_can_pci_tbl);
diff --git a/c_can/rtcan_c_can_platform.c b/c_can/rtcan_c_can_platform.c
new file mode 100644
index 0000000..d63b919
--- /dev/null
+++ b/c_can/rtcan_c_can_platform.c
@@ -0,0 +1,347 @@
+/*
+ * Platform CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
+ * users_manual_c_can.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/can/dev.h>
+
+#include "c_can.h"
+
+#define CAN_RAMINIT_START_MASK(i) (1 << (i))
+
+/*
+ * 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_plat_read_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + priv->regs[index]);
+}
+
+static void c_can_plat_write_reg_aligned_to_16bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + priv->regs[index]);
+}
+
+static u16 c_can_plat_read_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index)
+{
+ return readw(priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_plat_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+ enum reg index, u16 val)
+{
+ writew(val, priv->base + 2 * priv->regs[index]);
+}
+
+static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
+{
+ u32 val;
+
+ val = readl(priv->raminit_ctrlreg);
+ if (enable)
+ val |= CAN_RAMINIT_START_MASK(priv->instance);
+ else
+ val &= ~CAN_RAMINIT_START_MASK(priv->instance);
+ writel(val, priv->raminit_ctrlreg);
+}
+
+static struct platform_device_id c_can_id_table[] = {
+ [BOSCH_C_CAN_PLATFORM] = {
+ .name = KBUILD_MODNAME,
+ .driver_data = BOSCH_C_CAN,
+ },
+ [BOSCH_C_CAN] = {
+ .name = "c_can",
+ .driver_data = BOSCH_C_CAN,
+ },
+ [BOSCH_D_CAN] = {
+ .name = "d_can",
+ .driver_data = BOSCH_D_CAN,
+ }, {
+ }
+};
+MODULE_DEVICE_TABLE(platform, c_can_id_table);
+
+static const struct of_device_id c_can_of_table[] = {
+ { .compatible = "bosch,c_can", .data = &c_can_id_table[BOSCH_C_CAN] },
+ { .compatible = "bosch,d_can", .data = &c_can_id_table[BOSCH_D_CAN] },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, c_can_of_table);
+
+static int c_can_plat_probe(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *addr;
+ struct net_device *dev;
+ struct c_can_priv *priv;
+ const struct of_device_id *match;
+ const struct platform_device_id *id;
+ struct pinctrl *pinctrl;
+ struct resource *mem, *res;
+ int irq;
+ struct clk *clk;
+
+ if (pdev->dev.of_node) {
+ match = of_match_device(c_can_of_table, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Failed to find matching dt id\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ id = match->data;
+ } else {
+ id = platform_get_device_id(pdev);
+ }
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev,
+ "failed to configure pins from driver\n");
+
+ /* get the appropriate clk */
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ /* get the platform data */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!mem || irq <= 0) {
+ ret = -ENODEV;
+ goto exit_free_clk;
+ }
+
+ if (!request_mem_region(mem->start, resource_size(mem),
+ KBUILD_MODNAME)) {
+ dev_err(&pdev->dev, "resource unavailable\n");
+ ret = -ENODEV;
+ goto exit_free_clk;
+ }
+
+ addr = ioremap(mem->start, resource_size(mem));
+ if (!addr) {
+ dev_err(&pdev->dev, "failed to map can port\n");
+ ret = -ENOMEM;
+ goto exit_release_mem;
+ }
+
+ /* allocate the c_can device */
+ dev = alloc_c_can_dev();
+ if (!dev) {
+ ret = -ENOMEM;
+ goto exit_iounmap;
+ }
+
+ priv = netdev_priv(dev);
+ switch (id->driver_data) {
+ case BOSCH_C_CAN:
+ priv->regs = reg_map_c_can;
+ switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+ case IORESOURCE_MEM_32BIT:
+ priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
+ break;
+ case IORESOURCE_MEM_16BIT:
+ default:
+ priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+ break;
+ }
+ break;
+ case BOSCH_D_CAN:
+ priv->regs = reg_map_d_can;
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+ priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
+ priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
+
+ if (pdev->dev.of_node)
+ priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
+ else
+ priv->instance = pdev->id;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->raminit_ctrlreg = devm_request_and_ioremap(&pdev->dev, res);
+ if (!priv->raminit_ctrlreg || priv->instance < 0)
+ dev_info(&pdev->dev, "control memory is not used for raminit\n");
+ else
+ priv->raminit = c_can_hw_raminit;
+ break;
+ default:
+ ret = -EINVAL;
+ goto exit_free_device;
+ }
+
+ dev->irq = irq;
+ priv->base = addr;
+ priv->device = &pdev->dev;
+ priv->can.clock.freq = clk_get_rate(clk);
+ priv->priv = clk;
+ priv->type = id->driver_data;
+
+ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ ret = register_c_can_dev(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, ret);
+ goto exit_free_device;
+ }
+
+ dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+ KBUILD_MODNAME, priv->base, dev->irq);
+ return 0;
+
+exit_free_device:
+ platform_set_drvdata(pdev, NULL);
+ free_c_can_dev(dev);
+exit_iounmap:
+ iounmap(addr);
+exit_release_mem:
+ release_mem_region(mem->start, resource_size(mem));
+exit_free_clk:
+ clk_put(clk);
+exit:
+ dev_err(&pdev->dev, "probe failed\n");
+
+ return ret;
+}
+
+static int c_can_plat_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+
+ unregister_c_can_dev(dev);
+ platform_set_drvdata(pdev, NULL);
+
+ free_c_can_dev(dev);
+ iounmap(priv->base);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+
+ clk_put(priv->priv);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(ndev);
+
+ if (priv->type != BOSCH_D_CAN) {
+ dev_warn(&pdev->dev, "Not supported\n");
+ return 0;
+ }
+
+ if (netif_running(ndev)) {
+ netif_stop_queue(ndev);
+ netif_device_detach(ndev);
+ }
+
+ ret = c_can_power_down(ndev);
+ if (ret) {
+ netdev_err(ndev, "failed to enter power down mode\n");
+ return ret;
+ }
+
+ priv->can.state = CAN_STATE_SLEEPING;
+
+ return 0;
+}
+
+static int c_can_resume(struct platform_device *pdev)
+{
+ int ret;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = netdev_priv(ndev);
+
+ if (priv->type != BOSCH_D_CAN) {
+ dev_warn(&pdev->dev, "Not supported\n");
+ return 0;
+ }
+
+ ret = c_can_power_up(ndev);
+ if (ret) {
+ netdev_err(ndev, "Still in power down mode\n");
+ return ret;
+ }
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ if (netif_running(ndev)) {
+ netif_device_attach(ndev);
+ netif_start_queue(ndev);
+ }
+
+ return 0;
+}
+#else
+#define c_can_suspend NULL
+#define c_can_resume NULL
+#endif
+
+static struct platform_driver c_can_plat_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(c_can_of_table),
+ },
+ .probe = c_can_plat_probe,
+ .remove = c_can_plat_remove,
+ .suspend = c_can_suspend,
+ .resume = c_can_resume,
+ .id_table = c_can_id_table,
+};
+
+module_platform_driver(c_can_plat_driver);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
-- 
1.9.1


>From 8740cfe7fd960727ad3e993da5366c88e2280264 Mon Sep 17 00:00:00 2001
From: Michael Haberler <git@mah.priv.at>
Date: Tue, 28 Apr 2015 15:17:40 +0200
Subject: [PATCH 3/3] xeno_d_can: RTDM driver for Bosch CCAN and DCAN
 peripherals

author: Steve Battazzo <sbattazzo@gmail.com>
---
 c_can/Makefile               |  35 +-
 c_can/README                 |   5 +
 c_can/rtcan_c_can.c          | 755
+++++++++++++++++++++----------------------
 c_can/rtcan_c_can.h          |  56 +++-
 c_can/rtcan_c_can_platform.c | 163 ++++------
 5 files changed, 522 insertions(+), 492 deletions(-)
 create mode 100644 c_can/README

diff --git a/c_can/Makefile b/c_can/Makefile
index ad1cc84..54889d6 100644
--- a/c_can/Makefile
+++ b/c_can/Makefile
@@ -1,9 +1,36 @@
 #
 #  Makefile for the Bosch C_CAN controller drivers.
 #
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)

-obj-$(CONFIG_CAN_C_CAN) += c_can.o
-obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
-obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
+# Makefile frag for Linux v2.6 and v3.x

-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/can
-Idrivers/xenomai/can/c_can
+
+obj-$(CONFIG_XENO_DRIVERS_CAN_CCAN) += xeno_can_c_can.o
+
+xeno_can_c_can-y := rtcan_c_can.o rtcan_c_can_platform.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_CAN_CCAN) += xeno_can_c_can.o
+
+list-multi := xeno_can_c_can.o
+
+xeno_can_c_can-objs := rtcan_c_can.o rtcan_c_can_platform.o
+
+
+export-objs := $(xeno_can_c_can-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai
-I$(TOPDIR)/include/xenomai/compat -I..  -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_can_c_can.o: $(xeno_can_c_can-objs)
+ $(LD) -r -o $@ $(xeno_can_c_can-objs)
+
+endif
diff --git a/c_can/README b/c_can/README
new file mode 100644
index 0000000..15b4c51
--- /dev/null
+++ b/c_can/README
@@ -0,0 +1,5 @@
+# xeno_d_can
+
+Driver for Bosch CCAN and DCAN peripherals ported to RTDM for use with
Xenomai.
+Based heavily on existing Linux driver for the same hardware. Tested on
Beaglebone Black.
+
diff --git a/c_can/rtcan_c_can.c b/c_can/rtcan_c_can.c
index 2282b1a..bf4660e 100644
--- a/c_can/rtcan_c_can.c
+++ b/c_can/rtcan_c_can.c
@@ -1,19 +1,20 @@
 /*
- * CAN bus driver for Bosch C_CAN controller
+ * CAN bus driver for Bosch C_CAN controller, ported to Xenomai RTDM
  *
- * Copyright (C) 2010 ST Microelectronics
- * Bhupesh Sharma <bhupesh.sharma@st.com>
  *
+ * Stephen J. Battazzo <stephen.j.battazzo@nasa.gov>,
+ * MEI Services/NASA Ames Research Center
+ *
+ * Borrowed original driver from:
+ *
+ * Bhupesh Sharma <bhupesh.sharma@st.com>, ST Microelectronics
  * Borrowed heavily from the C_CAN driver originally written by:
  * Copyright (C) 2007
  * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
  * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
  *
- * TX and RX NAPI implementation has been borrowed from at91 CAN driver
- * written by:
- * Copyright
- * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
- * (C) 2008, 2009 by Marc Kleine-Budde <kernel@pengutronix.de>
+ * TX and RX NAPI implementation has been removed and replaced with RT
Socket CAN implementation.
+ * RT Socket CAN implementation inspired by Flexcan RTDM port by Wolfgang
Grandegger <wg@denx.de>
  *
  * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
  * Bosch C_CAN user manual can be obtained from:
@@ -29,18 +30,32 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/list.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_device.h>
+#endif
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <rtdm/rtdm_driver.h>

-#include <linux/can.h>
-#include <linux/can/dev.h>
-#include <linux/can/error.h>
+/* CAN device profile */
+#include <rtdm/rtcan.h>
+#include "rtcan_dev.h"
+#include "rtcan_raw.h"
+#include "rtcan_internal.h"

-#include "c_can.h"
+#include "rtcan_c_can.h"
+
+//borrowed this from linux/can/dev.h for now:
+#define CAN_MAX_DLC 8
+#define get_can_dlc(i)          (min_t(__u8, (i), CAN_MAX_DLC))

 /* Number of interface registers */
 #define IF_ENUM_REG_LEN 11
@@ -197,8 +212,8 @@ enum c_can_bus_error_types {
  C_CAN_ERROR_PASSIVE,
 };

-static const struct can_bittiming_const c_can_bittiming_const = {
- .name = KBUILD_MODNAME,
+struct can_bittiming_const c_can_bittiming_const = {
+ .name = DRV_NAME,
  .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */
  .tseg1_max = 16,
  .tseg2_min = 1, /* Time segment 2 = phase_seg2 */
@@ -209,6 +224,7 @@ static const struct can_bittiming_const
c_can_bittiming_const = {
  .brp_inc = 1,
 };

+
 static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
 {
  if (priv->device)
@@ -289,10 +305,10 @@ static inline int c_can_msg_obj_is_busy(struct
c_can_priv *priv, int iface)
  return 0;
 }

-static inline void c_can_object_get(struct net_device *dev,
+static inline void c_can_object_get(struct rtcan_device *dev,
  int iface, int objno, int mask)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  /*
  * As per specs, after writting the message object number in the
@@ -306,13 +322,13 @@ static inline void c_can_object_get(struct net_device
*dev,
  IFX_WRITE_LOW_16BIT(objno));

  if (c_can_msg_obj_is_busy(priv, iface))
- netdev_err(dev, "timed out in object get\n");
+ rtcandev_err(dev, "timed out in object get\n");
 }

-static inline void c_can_object_put(struct net_device *dev,
+static inline void c_can_object_put(struct rtcan_device *dev,
  int iface, int objno, int mask)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  /*
  * As per specs, after writting the message object number in the
@@ -326,16 +342,16 @@ static inline void c_can_object_put(struct net_device
*dev,
  IFX_WRITE_LOW_16BIT(objno));

  if (c_can_msg_obj_is_busy(priv, iface))
- netdev_err(dev, "timed out in object put\n");
+ rtcandev_err(dev, "timed out in object put\n");
 }

-static void c_can_write_msg_object(struct net_device *dev,
+static void c_can_write_msg_object(struct rtcan_device *dev,
  int iface, struct can_frame *frame, int objno)
 {
  int i;
  u16 flags = 0;
  unsigned int id;
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  if (!(frame->can_id & CAN_RTR_FLAG))
  flags |= IF_ARB_TRANSMIT;
@@ -365,11 +381,11 @@ static void c_can_write_msg_object(struct net_device
*dev,
  c_can_object_put(dev, iface, objno, IF_COMM_ALL);
 }

-static inline void c_can_mark_rx_msg_obj(struct net_device *dev,
+static inline void c_can_mark_rx_msg_obj(struct rtcan_device *dev,
  int iface, int ctrl_mask,
  int obj)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
  ctrl_mask & ~(IF_MCONT_MSGLST | IF_MCONT_INTPND));
@@ -377,12 +393,12 @@ static inline void c_can_mark_rx_msg_obj(struct
net_device *dev,

 }

-static inline void c_can_activate_all_lower_rx_msg_obj(struct net_device
*dev,
+static inline void c_can_activate_all_lower_rx_msg_obj(struct rtcan_device
*dev,
  int iface,
  int ctrl_mask)
 {
  int i;
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  for (i = C_CAN_MSG_OBJ_RX_FIRST; i <= C_CAN_MSG_RX_LOW_LAST; i++) {
  priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
@@ -392,11 +408,11 @@ static inline void
c_can_activate_all_lower_rx_msg_obj(struct net_device *dev,
  }
 }

-static inline void c_can_activate_rx_msg_obj(struct net_device *dev,
+static inline void c_can_activate_rx_msg_obj(struct rtcan_device *dev,
  int iface, int ctrl_mask,
  int obj)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface),
  ctrl_mask & ~(IF_MCONT_MSGLST |
@@ -404,15 +420,15 @@ static inline void c_can_activate_rx_msg_obj(struct
net_device *dev,
  c_can_object_put(dev, iface, obj, IF_COMM_CONTROL);
 }

-static void c_can_handle_lost_msg_obj(struct net_device *dev,
+static void c_can_handle_lost_msg_obj(struct rtcan_device *dev,
  int iface, int objno)
 {
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
- struct can_frame *frame;
+ struct c_can_priv *priv = rtcan_priv(dev);

- netdev_err(dev, "msg lost in buffer %d\n", objno);
+ struct rtcan_skb skb;
+ struct rtcan_rb_frame *cf = &skb.rb_frame;
+
+ rtcandev_err(dev, "msg lost in buffer %d\n", objno);

  c_can_object_get(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);

@@ -421,36 +437,22 @@ static void c_can_handle_lost_msg_obj(struct
net_device *dev,

  c_can_object_put(dev, 0, objno, IF_COMM_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++;
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;

- netif_receive_skb(skb);
+ rtcan_rcv(dev, &skb);
 }

-static int c_can_read_msg_object(struct net_device *dev, int iface, int
ctrl)
+static int c_can_read_msg_object(struct rtcan_device *dev, int iface, int
ctrl, struct rtcan_skb *skb)
 {
  u16 flags, data;
  int i;
  unsigned int val;
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct sk_buff *skb;
- struct can_frame *frame;
-
- skb = alloc_can_skb(dev, &frame);
- if (!skb) {
- stats->rx_dropped++;
- return -ENOMEM;
- }
+ struct c_can_priv *priv = rtcan_priv(dev);
+ struct rtcan_rb_frame *frame = &skb->rb_frame;

  frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+ skb->rb_frame_size = EMPTY_RB_FRAME_SIZE + CAN_ERR_DLC;

  flags = priv->read_reg(priv, C_CAN_IFACE(ARB2_REG, iface));
  val = priv->read_reg(priv, C_CAN_IFACE(ARB1_REG, iface)) |
@@ -472,19 +474,14 @@ static int c_can_read_msg_object(struct net_device
*dev, int iface, int ctrl)
  }
  }

- netif_receive_skb(skb);
-
- stats->rx_packets++;
- stats->rx_bytes += frame->can_dlc;
-
  return 0;
 }

-static void c_can_setup_receive_object(struct net_device *dev, int iface,
+static void c_can_setup_receive_object(struct rtcan_device *dev, int iface,
  int objno, unsigned int mask,
  unsigned int id, unsigned int mcont)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
  IFX_WRITE_LOW_16BIT(mask));
@@ -503,13 +500,13 @@ static void c_can_setup_receive_object(struct
net_device *dev, int iface,
  priv->write_reg(priv, C_CAN_IFACE(MSGCTRL_REG, iface), mcont);
  c_can_object_put(dev, iface, objno, IF_COMM_ALL & ~IF_COMM_TXRQST);

- netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
- c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
+ //rtcandev_dbg(dev, "setup obj no:%d, msgval:0x%08x\n", objno,
+ // c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
 }

-static void c_can_inval_msg_object(struct net_device *dev, int iface, int
objno)
+static void c_can_inval_msg_object(struct rtcan_device *dev, int iface,
int objno)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface), 0);
  priv->write_reg(priv, C_CAN_IFACE(ARB2_REG, iface), 0);
@@ -517,8 +514,8 @@ static void c_can_inval_msg_object(struct net_device
*dev, int iface, int objno)

  c_can_object_put(dev, iface, objno, IF_COMM_ARB | IF_COMM_CONTROL);

- netdev_dbg(dev, "obj no:%d, msgval:0x%08x\n", objno,
- c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
+ //rtcandev_dbg(dev, "invalidate obj no:%d, msgval:0x%08x\n", objno,
+ // c_can_read_reg32(priv, C_CAN_MSGVAL1_REG));
 }

 static inline int c_can_is_next_tx_obj_busy(struct c_can_priv *priv, int
objno)
@@ -535,56 +532,46 @@ static inline int c_can_is_next_tx_obj_busy(struct
c_can_priv *priv, int objno)
  return 0;
 }

-static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
+int c_can_start_xmit(struct rtcan_device *dev, struct can_frame *cf)
 {
  u32 msg_obj_no;
- struct c_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;
-
+ struct c_can_priv *priv = rtcan_priv(dev);
+
  msg_obj_no = get_tx_next_msg_obj(priv);

  /* prepare message object for transmission */
- c_can_write_msg_object(dev, 0, frame, msg_obj_no);
- can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+ c_can_write_msg_object(dev, 0, cf, msg_obj_no);

  /*
  * 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 (c_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||
- (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
- netif_stop_queue(dev);

- return NETDEV_TX_OK;
+ return 0;
 }

-static int c_can_set_bittiming(struct net_device *dev)
+int c_can_set_bittiming(struct rtcan_device *dev)
 {
  unsigned int reg_btr, reg_brpe, ctrl_save;
  u8 brp, brpe, sjw, tseg1, tseg2;
  u32 ten_bit_brp;
- struct c_can_priv *priv = netdev_priv(dev);
- const struct can_bittiming *bt = &priv->can.bittiming;
-
+ struct c_can_priv *priv = rtcan_priv(dev);
+ struct can_bittime *bt = &priv->bit_time;
+
  /* c_can provides a 6-bit brp and 4-bit brpe fields */
- ten_bit_brp = bt->brp - 1;
+ ten_bit_brp = bt->std.brp - 1;
  brp = ten_bit_brp & BTR_BRP_MASK;
  brpe = ten_bit_brp >> 6;

- sjw = bt->sjw - 1;
- tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
- tseg2 = bt->phase_seg2 - 1;
+ sjw = bt->std.sjw - 1;
+ tseg1 = bt->std.prop_seg + bt->std.phase_seg1 - 1;
+ tseg2 = bt->std.phase_seg2 - 1;
  reg_btr = brp | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
  (tseg2 << BTR_TSEG2_SHIFT);
  reg_brpe = brpe & BRP_EXT_BRPE_MASK;

- netdev_info(dev,
- "setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);
+ rtcandev_info(dev,"setting BTR=%04x BRPE=%04x\n", reg_btr, reg_brpe);

  ctrl_save = priv->read_reg(priv, C_CAN_CTRL_REG);
  priv->write_reg(priv, C_CAN_CTRL_REG,
@@ -605,7 +592,7 @@ static int c_can_set_bittiming(struct net_device *dev)
  * See user guide document for further details on configuring message
  * objects.
  */
-static void c_can_configure_msg_objects(struct net_device *dev)
+static void c_can_configure_msg_objects(struct rtcan_device *dev)
 {
  int i;

@@ -628,27 +615,27 @@ static void c_can_configure_msg_objects(struct
net_device *dev)
  * - set operating mode
  * - configure message objects
  */
-static void c_can_chip_config(struct net_device *dev)
+static void c_can_chip_config(struct rtcan_device *dev)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

  /* enable automatic retransmission */
  priv->write_reg(priv, C_CAN_CTRL_REG,
  CONTROL_ENABLE_AR);

- if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
-    (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
+ if ((dev->ctrl_mode & CAN_CTRLMODE_LISTENONLY) &&
+    (dev->ctrl_mode & CAN_CTRLMODE_LOOPBACK)) {
  /* loopback + silent mode : useful for hot self-test */
  priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
  CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
  priv->write_reg(priv, C_CAN_TEST_REG,
  TEST_LBACK | TEST_SILENT);
- } else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+ } else if (dev->ctrl_mode & CAN_CTRLMODE_LOOPBACK) {
  /* loopback mode : useful for self-test function */
  priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
  CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
  priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
- } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+ } else if (dev->ctrl_mode & CAN_CTRLMODE_LISTENONLY) {
  /* silent mode : bus-monitoring mode */
  priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_EIE |
  CONTROL_SIE | CONTROL_IE | CONTROL_TEST);
@@ -668,63 +655,136 @@ static void c_can_chip_config(struct net_device *dev)
  c_can_set_bittiming(dev);
 }

-static void c_can_start(struct net_device *dev)
+int c_can_save_bit_time(struct rtcan_device *dev,
+ struct can_bittime *bt,
+ rtdm_lockctx_t *lock_ctx)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);

- /* basic c_can configuration */
- c_can_chip_config(dev);
+ memcpy(&priv->bit_time, bt, sizeof(*bt));

- 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 */
- c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+ return 0;
 }

-static void c_can_stop(struct net_device *dev)
+static int c_can_mode_start(struct rtcan_device *dev, rtdm_lockctx_t
*lock_ctx)
 {
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);
+ int err;
+
+ switch (dev->state) {
+
+ case CAN_STATE_ACTIVE:
+ case CAN_STATE_BUS_WARNING:
+ case CAN_STATE_BUS_PASSIVE:
+ //rtcandev_info(dev, "Mode start: state active, bus warning, or
passive\n");
+ break;

- /* disable all interrupts */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+ case CAN_STATE_STOPPED:
+ /* Register IRQ handler and pass device structure as arg */
+ err = rtdm_irq_request(&dev->irq_handle, priv->irq,
+       c_can_interrupt, 0, DRV_NAME,
+       (void *)dev);
+ if (err) {
+ rtcandev_err(dev, "couldn't request irq %d\n",priv->irq);
+ goto out;
+ }
+
+ c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
+
+ /* start chip and queuing */
+ c_can_chip_config(dev);
+ dev->state = CAN_STATE_ERROR_ACTIVE;
+
+ /* reset tx helper pointers */
+ priv->tx_next = priv->tx_echo = 0;
+
+ /* enable status change, error and module interrupts */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+
+ /* Set up sender "mutex" */
+ rtdm_sem_init(&dev->tx_sem, C_CAN_MSG_OBJ_TX_NUM);

- /* set the state as STOPPED */
- priv->can.state = CAN_STATE_STOPPED;
-}
+ break;

-static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
-{
- switch (mode) {
- case CAN_MODE_START:
- c_can_start(dev);
- netif_wake_queue(dev);
+ case CAN_STATE_BUS_OFF:
+ /* Set up sender "mutex" */
+ rtdm_sem_init(&dev->tx_sem, C_CAN_MSG_OBJ_TX_NUM);
+ /* start chip and queuing */
+ c_can_pm_runtime_get_sync(priv);
+ c_can_reset_ram(priv, true);
+ c_can_chip_config(dev);
+ dev->state = CAN_STATE_ERROR_ACTIVE;
+ /* reset tx helper pointers */
+ priv->tx_next = priv->tx_echo = 0;
+ /* enable status change, error and module interrupts */
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
  break;
+
+ case CAN_STATE_SLEEPING:
+ //rtcandev_info(dev, "Mode start: state sleeping\n");
  default:
- return -EOPNOTSUPP;
+ /* Never reached, but we don't want nasty compiler warnings ... */
+ break;
  }

  return 0;
+out:
+ c_can_pm_runtime_put_sync(priv);
+ return err;
 }

-static int c_can_get_berr_counter(const struct net_device *dev,
- struct can_berr_counter *bec)
+static void c_can_mode_stop(struct rtcan_device *dev, rtdm_lockctx_t
*lock_ctx)
 {
- unsigned int reg_err_counter;
- struct c_can_priv *priv = netdev_priv(dev);
-
- c_can_pm_runtime_get_sync(priv);
+ struct c_can_priv *priv = rtcan_priv(dev);
+ can_state_t state;
+
+
+
+ state = dev->state;
+ /* If controller is not operating anyway, go out */
+ if (!CAN_STATE_OPERATING(state))
+ return;
+
+ //rtcandev_info(dev, "Mode stop.\n");
+ /* disable all interrupts */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);

- reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
- bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
- ERR_CNT_REC_SHIFT;
- bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
+ /* set the state as STOPPED */
+ dev->state = CAN_STATE_STOPPED;
+
+ /* Wake up waiting senders */
+ rtdm_sem_destroy(&dev->tx_sem);

+ rtdm_irq_free(&dev->irq_handle);
  c_can_pm_runtime_put_sync(priv);
+}

- return 0;
+
+int c_can_set_mode(struct rtcan_device *dev, can_mode_t mode,
rtdm_lockctx_t *lock_ctx)
+{
+ int err = 0;
+ //rtcandev_info(dev, "Set mode.\n");
+
+ switch (mode) {
+
+ case CAN_MODE_STOP:
+ //rtcandev_info(dev, "Set mode: stop\n");
+ c_can_mode_stop(dev, lock_ctx);
+ break;
+
+ case CAN_MODE_START:
+ //rtcandev_info(dev, "Set mode: start\n");
+ err = c_can_mode_start(dev, lock_ctx);
+ break;
+
+ case CAN_MODE_SLEEP:
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
 }

 /*
@@ -738,33 +798,29 @@ static int c_can_get_berr_counter(const struct
net_device *dev,
  * 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 c_can_do_tx(struct net_device *dev)
+static void c_can_do_tx(struct rtcan_device *dev)
 {
  u32 val;
  u32 msg_obj_no;
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
+ struct c_can_priv *priv = rtcan_priv(dev);

  for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
  msg_obj_no = get_tx_echo_msg_obj(priv);
  val = c_can_read_reg32(priv, C_CAN_TXRQST1_REG);
  if (!(val & (1 << (msg_obj_no - 1)))) {
- can_get_echo_skb(dev,
- msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
- stats->tx_bytes += priv->read_reg(priv,
- C_CAN_IFACE(MSGCTRL_REG, 0))
- & IF_MCONT_DLC_MASK;
- stats->tx_packets++;
+ //can_get_echo_skb(dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
  c_can_inval_msg_object(dev, 0, msg_obj_no);
  } else {
+ rtdm_sem_up(&dev->tx_sem);
  break;
  }
  }

  /* restart queue if wrap-up or if queue stalled on last pkt */
  if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
- ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
- netif_wake_queue(dev);
+ ((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0)){
+ rtdm_sem_up(&dev->tx_sem);
+ }
 }

 /*
@@ -789,15 +845,17 @@ static void c_can_do_tx(struct net_device *dev)
  *   C_CAN_MSG_RX_LOW_LAST then clear the NEWDAT bit of
  *   only this message object.
  */
-static int c_can_do_rx_poll(struct net_device *dev, int quota)
+static int c_can_do_rx_poll(struct rtcan_device *dev)
 {
  u32 num_rx_pkts = 0;
  unsigned int msg_obj, msg_ctrl_save;
- struct c_can_priv *priv = netdev_priv(dev);
+ struct c_can_priv *priv = rtcan_priv(dev);
  u32 val = c_can_read_reg32(priv, C_CAN_INTPND1_REG);
+
+ struct rtcan_skb skb;

  for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
- msg_obj <= C_CAN_MSG_OBJ_RX_LAST && quota > 0;
+ msg_obj <= C_CAN_MSG_OBJ_RX_LAST;
  val = c_can_read_reg32(priv, C_CAN_INTPND1_REG),
  msg_obj++) {
  /*
@@ -816,7 +874,6 @@ static int c_can_do_rx_poll(struct net_device *dev, int
quota)
  if (msg_ctrl_save & IF_MCONT_MSGLST) {
  c_can_handle_lost_msg_obj(dev, 0, msg_obj);
  num_rx_pkts++;
- quota--;
  continue;
  }

@@ -824,7 +881,7 @@ static int c_can_do_rx_poll(struct net_device *dev, int
quota)
  continue;

  /* read the data from the message object */
- c_can_read_msg_object(dev, 0, msg_ctrl_save);
+ c_can_read_msg_object(dev, 0, msg_ctrl_save, &skb);

  if (msg_obj < C_CAN_MSG_RX_LOW_LAST)
  c_can_mark_rx_msg_obj(dev, 0,
@@ -837,98 +894,88 @@ static int c_can_do_rx_poll(struct net_device *dev,
int quota)
  /* activate all lower message objects */
  c_can_activate_all_lower_rx_msg_obj(dev,
  0, msg_ctrl_save);
-
+
+ rtcan_rcv(dev, &skb);
  num_rx_pkts++;
- quota--;
  }
  }

  return num_rx_pkts;
 }

-static inline int c_can_has_and_handle_berr(struct c_can_priv *priv)
-{
- return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
- (priv->current_status & LEC_UNUSED);
-}
-
-static int c_can_handle_state_change(struct net_device *dev,
+static int c_can_handle_state_change(struct rtcan_device *dev,
  enum c_can_bus_error_types error_type)
 {
  unsigned int reg_err_counter;
+ u8 txerr;
+ u8 rxerr;
  unsigned int rx_err_passive;
- struct c_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;
-
+ struct c_can_priv *priv = rtcan_priv(dev);
+ struct rtcan_skb skb;
+ struct rtcan_rb_frame *cf = &skb.rb_frame;
+
  /* propagate the error condition to the CAN stack */
- skb = alloc_can_err_skb(dev, &cf);
- if (unlikely(!skb))
- return 0;
-
- c_can_get_berr_counter(dev, &bec);
  reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
+ rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >> ERR_CNT_REC_SHIFT;
+ txerr = reg_err_counter & ERR_CNT_TEC_MASK;
  rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
  ERR_CNT_RP_SHIFT;

  switch (error_type) {
  case C_CAN_ERROR_WARNING:
  /* error warning state */
- priv->can.can_stats.error_warning++;
- priv->can.state = CAN_STATE_ERROR_WARNING;
+ skb.rb_frame_size = EMPTY_RB_FRAME_SIZE + CAN_ERR_DLC;
+ dev->state = CAN_STATE_ERROR_WARNING;
  cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] = (bec.txerr > bec.rxerr) ?
+ cf->data[1] = (txerr > rxerr) ?
  CAN_ERR_CRTL_TX_WARNING :
  CAN_ERR_CRTL_RX_WARNING;
- cf->data[6] = bec.txerr;
- cf->data[7] = bec.rxerr;
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;

  break;
  case C_CAN_ERROR_PASSIVE:
  /* error passive state */
- priv->can.can_stats.error_passive++;
- priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ skb.rb_frame_size = EMPTY_RB_FRAME_SIZE + CAN_ERR_DLC;
+ dev->state = CAN_STATE_ERROR_PASSIVE;
  cf->can_id |= CAN_ERR_CRTL;
  if (rx_err_passive)
  cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
- if (bec.txerr > 127)
+ if (txerr > 127)
  cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;

- cf->data[6] = bec.txerr;
- cf->data[7] = bec.rxerr;
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
  break;
  case C_CAN_BUS_OFF:
  /* bus-off state */
- priv->can.state = CAN_STATE_BUS_OFF;
+ skb.rb_frame_size = EMPTY_RB_FRAME_SIZE + CAN_ERR_DLC;
+ dev->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
  */
  c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
- can_bus_off(dev);
+ /* Wake up waiting senders */
+ rtdm_sem_destroy(&dev->tx_sem);
  break;
  default:
  break;
  }

- netif_receive_skb(skb);
- stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
+ rtcan_rcv(dev, &skb);

  return 1;
 }

-static int c_can_handle_bus_err(struct net_device *dev,
+static int c_can_handle_bus_err(struct rtcan_device *dev,
  enum c_can_lec_type lec_type)
 {
- struct c_can_priv *priv = netdev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct can_frame *cf;
- struct sk_buff *skb;
-
+ struct c_can_priv *priv = rtcan_priv(dev);
+ struct rtcan_skb skb;
+ struct rtcan_rb_frame *cf = &skb.rb_frame;
+ skb.rb_frame_size = EMPTY_RB_FRAME_SIZE + CAN_ERR_DLC;
  /*
  * early exit if no lec update or no error.
  * no lec update means that no CAN bus event has been detected
@@ -938,9 +985,9 @@ static int c_can_handle_bus_err(struct net_device *dev,
  return 0;

  /* propagate the error condition to the CAN stack */
- skb = alloc_can_err_skb(dev, &cf);
- if (unlikely(!skb))
- return 0;
+ //skb = alloc_can_err_skb(dev, &cf);
+ //if (unlikely(!skb))
+ // return 0;

  /*
  * check for 'last error code' which tells us the
@@ -948,35 +995,34 @@ static int c_can_handle_bus_err(struct net_device
*dev,
  */

  /* 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");
+ rtcandev_dbg(dev, "stuff error\n");
  cf->data[2] |= CAN_ERR_PROT_STUFF;
  break;
  case LEC_FORM_ERROR:
- netdev_dbg(dev, "form error\n");
+ rtcandev_dbg(dev, "form error\n");
  cf->data[2] |= CAN_ERR_PROT_FORM;
  break;
  case LEC_ACK_ERROR:
- netdev_dbg(dev, "ack error\n");
+ rtcandev_dbg(dev, "ack error\n");
  cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
  CAN_ERR_PROT_LOC_ACK_DEL);
  break;
  case LEC_BIT1_ERROR:
- netdev_dbg(dev, "bit1 error\n");
+ rtcandev_dbg(dev, "bit1 error\n");
  cf->data[2] |= CAN_ERR_PROT_BIT1;
  break;
  case LEC_BIT0_ERROR:
- netdev_dbg(dev, "bit0 error\n");
+ rtcandev_dbg(dev, "bit0 error\n");
  cf->data[2] |= CAN_ERR_PROT_BIT0;
  break;
  case LEC_CRC_ERROR:
- netdev_dbg(dev, "CRC error\n");
+ rtcandev_dbg(dev, "CRC error\n");
  cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
  CAN_ERR_PROT_LOC_CRC_DEL);
  break;
@@ -987,202 +1033,172 @@ static int c_can_handle_bus_err(struct net_device
*dev,
  /* set a `lec` value so that we can check for updates later */
  priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);

- netif_receive_skb(skb);
- stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
+ rtcan_rcv(dev, &skb);

  return 1;
 }

-static int c_can_poll(struct napi_struct *napi, int quota)
+int c_can_interrupt(rtdm_irq_t *irq_handle)
 {
- u16 irqstatus;
+ struct rtcan_device *dev = rtdm_irq_get_arg(irq_handle, void);
+ struct c_can_priv *priv = rtcan_priv(dev);
+ //u16 irqstatus;
  int lec_type = 0;
- int work_done = 0;
- struct net_device *dev = napi->dev;
- struct c_can_priv *priv = netdev_priv(dev);
-
- irqstatus = priv->irqstatus;
- if (!irqstatus)
- goto end;
-
+ int recv_lock_free = 1;
+ int ret = RTDM_IRQ_NONE;
+
+ priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
+ if (!priv->irqstatus)
+ return RTDM_IRQ_NONE;
+
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+ rtdm_lock_get(&dev->device_lock);
+
  /* status events have the highest priority */
- if (irqstatus == STATUS_INTERRUPT) {
+ if (priv->irqstatus == STATUS_INTERRUPT) {
  priv->current_status = priv->read_reg(priv,
  C_CAN_STS_REG);

  /* handle Tx/Rx events */
- if (priv->current_status & STATUS_TXOK)
+ if (priv->current_status & STATUS_TXOK){
  priv->write_reg(priv, C_CAN_STS_REG,
  priv->current_status & ~STATUS_TXOK);
+ //rtcandev_info(dev, "IRQ: TX OK.\r\n");
+ }

- if (priv->current_status & STATUS_RXOK)
+ if (priv->current_status & STATUS_RXOK){
  priv->write_reg(priv, C_CAN_STS_REG,
  priv->current_status & ~STATUS_RXOK);
+ //rtcandev_info(dev, "IRQ: RX OK.\r\n");
+ }

  /* handle state changes */
  if ((priv->current_status & STATUS_EWARN) &&
  (!(priv->last_status & STATUS_EWARN))) {
- netdev_dbg(dev, "entered error warning state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_WARNING);
+ rtcandev_dbg(dev, "entered error warning state\n");
+ c_can_handle_state_change(dev,C_CAN_ERROR_WARNING);
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+ ret = RTDM_IRQ_HANDLED;
  }
  if ((priv->current_status & STATUS_EPASS) &&
  (!(priv->last_status & STATUS_EPASS))) {
- netdev_dbg(dev, "entered error passive state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_ERROR_PASSIVE);
+ rtcandev_dbg(dev, "entered error passive state\n");
+ c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+ ret = RTDM_IRQ_HANDLED;
  }
  if ((priv->current_status & STATUS_BOFF) &&
  (!(priv->last_status & STATUS_BOFF))) {
- netdev_dbg(dev, "entered bus off state\n");
- work_done += c_can_handle_state_change(dev,
- C_CAN_BUS_OFF);
+ rtcandev_dbg(dev, "entered bus off state\n");
+ c_can_handle_state_change(dev,C_CAN_BUS_OFF);
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+ ret = RTDM_IRQ_HANDLED;
  }

  /* handle bus recovery events */
  if ((!(priv->current_status & STATUS_BOFF)) &&
  (priv->last_status & STATUS_BOFF)) {
- netdev_dbg(dev, "left bus off state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ rtcandev_dbg(dev, "left bus off state\n");
+ dev->state = CAN_STATE_ERROR_ACTIVE;
+ ret = RTDM_IRQ_HANDLED;
  }
  if ((!(priv->current_status & STATUS_EPASS)) &&
  (priv->last_status & STATUS_EPASS)) {
- netdev_dbg(dev, "left error passive state\n");
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ rtcandev_dbg(dev, "left error passive state\n");
+ dev->state = CAN_STATE_ERROR_ACTIVE;
+ ret = RTDM_IRQ_HANDLED;
  }

  priv->last_status = priv->current_status;

  /* handle lec errors on the bus */
- lec_type = c_can_has_and_handle_berr(priv);
+ lec_type = (priv->current_status & LEC_UNUSED);
  if (lec_type)
- work_done += c_can_handle_bus_err(dev, lec_type);
- } else if ((irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
+ c_can_handle_bus_err(dev, lec_type);
+
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+ ret = RTDM_IRQ_HANDLED;
+
+ }
+ else if ((priv->irqstatus >= C_CAN_MSG_OBJ_RX_FIRST) &&
+ (priv->irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
  /* handle events corresponding to receive message objects */
- work_done += c_can_do_rx_poll(dev, (quota - work_done));
- } else if ((irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
- (irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
+ c_can_do_rx_poll(dev);
+
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+
+ ret = RTDM_IRQ_HANDLED;
+
+ }
+ else if ((priv->irqstatus >= C_CAN_MSG_OBJ_TX_FIRST) &&
+ (priv->irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
  /* handle events corresponding to transmit message objects */
  c_can_do_tx(dev);
+
+ if (rtcan_loopback_pending(dev)) {
+ if (recv_lock_free) {
+ recv_lock_free = 0;
+ rtdm_lock_get(&rtcan_recv_list_lock);
+ rtdm_lock_get(&rtcan_socket_lock);
+ }
+ rtcan_loopback(dev);
+ }
+ ret = RTDM_IRQ_HANDLED;
  }

-end:
- if (work_done < quota) {
- napi_complete(napi);
- /* enable all IRQs */
- c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
- }
-
- return work_done;
-}
-
-static irqreturn_t c_can_isr(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct c_can_priv *priv = netdev_priv(dev);
-
- priv->irqstatus = priv->read_reg(priv, C_CAN_INT_REG);
- if (!priv->irqstatus)
- return IRQ_NONE;
-
- /* disable all interrupts and schedule the NAPI */
- c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
- napi_schedule(&priv->napi);
-
- return IRQ_HANDLED;
-}
-
-static int c_can_open(struct net_device *dev)
-{
- int err;
- struct c_can_priv *priv = netdev_priv(dev);
-
- c_can_pm_runtime_get_sync(priv);
- c_can_reset_ram(priv, true);
-
- /* open the can device */
- err = open_candev(dev);
- if (err) {
- netdev_err(dev, "failed to open can device\n");
- goto exit_open_fail;
- }
-
- /* register interrupt handler */
- err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
- dev);
- if (err < 0) {
- netdev_err(dev, "failed to request interrupt\n");
- goto exit_irq_fail;
+ if (!recv_lock_free) {
+ rtdm_lock_put(&rtcan_socket_lock);
+ rtdm_lock_put(&rtcan_recv_list_lock);
  }
-
- napi_enable(&priv->napi);
-
- /* start the c_can controller */
- c_can_start(dev);
-
- netif_start_queue(dev);
-
- return 0;
-
-exit_irq_fail:
- close_candev(dev);
-exit_open_fail:
- c_can_reset_ram(priv, false);
- c_can_pm_runtime_put_sync(priv);
- return err;
-}
-
-static int c_can_close(struct net_device *dev)
-{
- struct c_can_priv *priv = netdev_priv(dev);
-
- netif_stop_queue(dev);
- napi_disable(&priv->napi);
- c_can_stop(dev);
- free_irq(dev->irq, dev);
- close_candev(dev);
-
- c_can_reset_ram(priv, false);
- c_can_pm_runtime_put_sync(priv);
-
- return 0;
+ rtdm_lock_put(&dev->device_lock);
+ c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+
+ return ret;
 }

-struct net_device *alloc_c_can_dev(void)
+struct rtcan_device *alloc_c_can_dev(void)
 {
- struct net_device *dev;
+ struct rtcan_device *dev;
  struct c_can_priv *priv;

- dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
+ dev = rtcan_dev_alloc(sizeof(struct c_can_priv), 0);
  if (!dev)
  return NULL;

- priv = netdev_priv(dev);
- netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
+ priv = rtcan_priv(dev);

  priv->dev = dev;
- priv->can.bittiming_const = &c_can_bittiming_const;
- priv->can.do_set_mode = c_can_set_mode;
- priv->can.do_get_berr_counter = c_can_get_berr_counter;
- priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
- CAN_CTRLMODE_LISTENONLY |
- CAN_CTRLMODE_BERR_REPORTING;
-
  return dev;
 }
-EXPORT_SYMBOL_GPL(alloc_c_can_dev);
+//EXPORT_SYMBOL_GPL(alloc_c_can_dev);

 #ifdef CONFIG_PM
-int c_can_power_down(struct net_device *dev)
+int c_can_power_down(struct rtcan_device *dev)
 {
  u32 val;
  unsigned long time_out;
- struct c_can_priv *priv = netdev_priv(dev);
-
- if (!(dev->flags & IFF_UP))
- return 0;
+ struct c_can_priv *priv = rtcan_priv(dev);

  WARN_ON(priv->type != BOSCH_D_CAN);

@@ -1200,23 +1216,24 @@ int c_can_power_down(struct net_device *dev)
  if (time_after(jiffies, time_out))
  return -ETIMEDOUT;

- c_can_stop(dev);
+ /* disable all interrupts */
+ c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+ /* set the state as STOPPED */
+ dev->state = CAN_STATE_STOPPED;

  c_can_reset_ram(priv, false);
  c_can_pm_runtime_put_sync(priv);

  return 0;
 }
-EXPORT_SYMBOL_GPL(c_can_power_down);
+//EXPORT_SYMBOL_GPL(c_can_power_down);

-int c_can_power_up(struct net_device *dev)
+int c_can_power_up(struct rtcan_device *dev)
 {
  u32 val;
  unsigned long time_out;
- struct c_can_priv *priv = netdev_priv(dev);
-
- if (!(dev->flags & IFF_UP))
- return 0;
+ struct c_can_priv *priv = rtcan_priv(dev);

  WARN_ON(priv->type != BOSCH_D_CAN);

@@ -1240,53 +1257,33 @@ int c_can_power_up(struct net_device *dev)
  if (time_after(jiffies, time_out))
  return -ETIMEDOUT;

- c_can_start(dev);
-
  return 0;
 }
-EXPORT_SYMBOL_GPL(c_can_power_up);
+//EXPORT_SYMBOL_GPL(c_can_power_up);
 #endif

-void free_c_can_dev(struct net_device *dev)
-{
- free_candev(dev);
-}
-EXPORT_SYMBOL_GPL(free_c_can_dev);

-static const struct net_device_ops c_can_netdev_ops = {
- .ndo_open = c_can_open,
- .ndo_stop = c_can_close,
- .ndo_start_xmit = c_can_start_xmit,
-};
-
-int register_c_can_dev(struct net_device *dev)
+int register_c_candev(struct rtcan_device *dev)
 {
- struct c_can_priv *priv = netdev_priv(dev);
- int err;
-
+ int err;
+ struct c_can_priv *priv = rtcan_priv(dev);
+
  c_can_pm_runtime_enable(priv);
+
+ err = rtcan_dev_register(dev);
+ if (err)
+ goto out_chip_disable;

- dev->flags |= IFF_ECHO; /* we support local echo */
- dev->netdev_ops = &c_can_netdev_ops;
+ return 0;

- err = register_candev(dev);
- if (err)
- c_can_pm_runtime_disable(priv);
+out_chip_disable:
+ c_can_pm_runtime_disable(priv);

  return err;
 }
-EXPORT_SYMBOL_GPL(register_c_can_dev);

-void unregister_c_can_dev(struct net_device *dev)
+void unregister_c_candev(struct rtcan_device *dev)
 {
- struct c_can_priv *priv = netdev_priv(dev);
-
- unregister_candev(dev);
-
- c_can_pm_runtime_disable(priv);
+ c_can_mode_stop(dev, NULL);
+ rtcan_dev_unregister(dev);
 }
-EXPORT_SYMBOL_GPL(unregister_c_can_dev);
-
-MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
diff --git a/c_can/rtcan_c_can.h b/c_can/rtcan_c_can.h
index d2e1c21..379e943 100644
--- a/c_can/rtcan_c_can.h
+++ b/c_can/rtcan_c_can.h
@@ -1,14 +1,21 @@
 /*
- * CAN bus driver for Bosch C_CAN controller
+ * CAN bus driver for Bosch C_CAN controller, ported to Xenomai RTDM
  *
- * Copyright (C) 2010 ST Microelectronics
- * Bhupesh Sharma <bhupesh.sharma@st.com>
  *
+ * Stephen J. Battazzo <stephen.j.battazzo@nasa.gov>,
+ * MEI Services/NASA Ames Research Center
+ *
+ * Borrowed original driver from:
+ *
+ * Bhupesh Sharma <bhupesh.sharma@st.com>, ST Microelectronics
  * Borrowed heavily from the C_CAN driver originally written by:
  * Copyright (C) 2007
  * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
  * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
  *
+ * TX and RX NAPI implementation has been removed and replaced with RT
Socket CAN implementation.
+ * RT Socket CAN implementation inspired by Flexcan RTDM port by Wolfgang
Grandegger <wg@denx.de>
+ *
  * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
  * Bosch C_CAN user manual can be obtained from:
  * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
@@ -19,8 +26,8 @@
  * warranty of any kind, whether express or implied.
  */

-#ifndef C_CAN_H
-#define C_CAN_H
+#ifndef RTCAN_C_CAN_H
+#define RTCAN_C_CAN_H

 enum reg {
  C_CAN_CTRL_REG = 0,
@@ -63,7 +70,7 @@ enum reg {
  C_CAN_MSGVAL2_REG,
 };

-static const u16 reg_map_c_can[] = {
+static u16 reg_map_c_can[] = {
  [C_CAN_CTRL_REG] = 0x00,
  [C_CAN_STS_REG] = 0x02,
  [C_CAN_ERR_CNT_REG] = 0x04,
@@ -103,7 +110,7 @@ static const u16 reg_map_c_can[] = {
  [C_CAN_MSGVAL2_REG] = 0xB2,
 };

-static const u16 reg_map_d_can[] = {
+static u16 reg_map_d_can[] = {
  [C_CAN_CTRL_REG] = 0x00,
  [C_CAN_CTRL_EX_REG] = 0x02,
  [C_CAN_STS_REG] = 0x04,
@@ -150,12 +157,18 @@ enum c_can_dev_id {
  BOSCH_D_CAN,
 };

+#define DEV_NAME "rtcan%d"
+#define DRV_NAME "c_can"
+
 /* c_can private data structure */
 struct c_can_priv {
- struct can_priv can; /* must be the first member */
- struct napi_struct napi;
- struct net_device *dev;
+ struct rtcan_device *dev;
+
+ int irq;
+
  struct device *device;
+
+ struct can_bittime bit_time;
  int tx_object;
  int current_status;
  int last_status;
@@ -174,14 +187,23 @@ struct c_can_priv {
  void (*raminit) (const struct c_can_priv *priv, bool enable);
 };

-struct net_device *alloc_c_can_dev(void);
-void free_c_can_dev(struct net_device *dev);
-int register_c_can_dev(struct net_device *dev);
-void unregister_c_can_dev(struct net_device *dev);
+struct rtcan_device *alloc_c_can_dev(void);
+
+int register_c_candev(struct rtcan_device *dev);
+void unregister_c_candev(struct rtcan_device *dev);
+int c_can_interrupt(rtdm_irq_t *irq_handle);
+int c_can_start_xmit(struct rtcan_device *dev, struct can_frame *cf);
+int c_can_set_bittiming(struct rtcan_device *dev);
+int c_can_set_mode(struct rtcan_device *dev, can_mode_t mode,
rtdm_lockctx_t *lock_ctx);
+int c_can_save_bit_time(struct rtcan_device *dev,
+ struct can_bittime *bt,
+ rtdm_lockctx_t *lock_ctx);
+extern struct can_bittiming_const c_can_bittiming_const;

 #ifdef CONFIG_PM
-int c_can_power_up(struct net_device *dev);
-int c_can_power_down(struct net_device *dev);
+int c_can_power_up(struct rtcan_device *dev);
+int c_can_power_down(struct rtcan_device *dev);
 #endif

-#endif /* C_CAN_H */
+
+#endif
diff --git a/c_can/rtcan_c_can_platform.c b/c_can/rtcan_c_can_platform.c
index d63b919..002aa39 100644
--- a/c_can/rtcan_c_can_platform.c
+++ b/c_can/rtcan_c_can_platform.c
@@ -1,14 +1,21 @@
 /*
- * Platform CAN bus driver for Bosch C_CAN controller
+ * CAN bus driver for Bosch C_CAN controller, ported to Xenomai RTDM
  *
- * Copyright (C) 2010 ST Microelectronics
- * Bhupesh Sharma <bhupesh.sharma@st.com>
  *
+ * Stephen J. Battazzo <stephen.j.battazzo@nasa.gov>,
+ * MEI Services/NASA Ames Research Center
+ *
+ * Borrowed original driver from:
+ *
+ * Bhupesh Sharma <bhupesh.sharma@st.com>, ST Microelectronics
  * Borrowed heavily from the C_CAN driver originally written by:
  * Copyright (C) 2007
  * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
  * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
  *
+ * TX and RX NAPI implementation has been removed and replaced with RT
Socket CAN implementation.
+ * RT Socket CAN implementation inspired by Flexcan RTDM port by Wolfgang
Grandegger <wg@denx.de>
+ *
  * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A
and B.
  * Bosch C_CAN user manual can be obtained from:
  * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
@@ -34,9 +41,14 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>

-#include <linux/can/dev.h>
+#include <rtdm/rtcan.h>
+#include "rtcan_internal.h"
+#include "rtcan_dev.h"
+
+#include "rtcan_c_can.h"

-#include "c_can.h"
+static char *c_can_ctrl_name = "DCAN";
+static char *my_board_name = "BBB";

 #define CAN_RAMINIT_START_MASK(i) (1 << (i))

@@ -84,11 +96,11 @@ static void c_can_hw_raminit(const struct c_can_priv
*priv, bool enable)

 static struct platform_device_id c_can_id_table[] = {
  [BOSCH_C_CAN_PLATFORM] = {
- .name = KBUILD_MODNAME,
+ .name = DRV_NAME,
  .driver_data = BOSCH_C_CAN,
  },
  [BOSCH_C_CAN] = {
- .name = "c_can",
+ .name = DRV_NAME,
  .driver_data = BOSCH_C_CAN,
  },
  [BOSCH_D_CAN] = {
@@ -110,7 +122,7 @@ static int c_can_plat_probe(struct platform_device
*pdev)
 {
  int ret;
  void __iomem *addr;
- struct net_device *dev;
+ struct rtcan_device *dev;
  struct c_can_priv *priv;
  const struct of_device_id *match;
  const struct platform_device_id *id;
@@ -143,7 +155,9 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  ret = -ENODEV;
  goto exit;
  }
-
+
+ dev_info(&pdev->dev, "setting up step 1: platform_get_resource\n");
+
  /* get the platform data */
  mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  irq = platform_get_irq(pdev, 0);
@@ -151,13 +165,17 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  ret = -ENODEV;
  goto exit_free_clk;
  }
-
+
+ dev_info(&pdev->dev, "setting up step 2: request mem region. Start %x,
size %d\n", mem->start, resource_size(mem));
+
  if (!request_mem_region(mem->start, resource_size(mem),
- KBUILD_MODNAME)) {
+ DRV_NAME)) {
  dev_err(&pdev->dev, "resource unavailable\n");
  ret = -ENODEV;
  goto exit_free_clk;
  }
+
+ dev_info(&pdev->dev, "setting up step 3: ioremap. Start %x, size %d\n",
mem->start, resource_size(mem));

  addr = ioremap(mem->start, resource_size(mem));
  if (!addr) {
@@ -165,7 +183,9 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  ret = -ENOMEM;
  goto exit_release_mem;
  }
-
+
+ dev_info(&pdev->dev, "alloc dev...\n");
+
  /* allocate the c_can device */
  dev = alloc_c_can_dev();
  if (!dev) {
@@ -173,7 +193,7 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  goto exit_iounmap;
  }

- priv = netdev_priv(dev);
+ priv = rtcan_priv(dev);
  switch (id->driver_data) {
  case BOSCH_C_CAN:
  priv->regs = reg_map_c_can;
@@ -191,7 +211,6 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  break;
  case BOSCH_D_CAN:
  priv->regs = reg_map_d_can;
- priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
  priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
  priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;

@@ -199,9 +218,15 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  priv->instance = of_alias_get_id(pdev->dev.of_node, "d_can");
  else
  priv->instance = pdev->id;
-
+
+ dev_info(&pdev->dev, "platform_get_resource...\n");
+
  res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ dev_info(&pdev->dev, "devm request and ioremap..\n");
+
  priv->raminit_ctrlreg = devm_request_and_ioremap(&pdev->dev, res);
+
  if (!priv->raminit_ctrlreg || priv->instance < 0)
  dev_info(&pdev->dev, "control memory is not used for raminit\n");
  else
@@ -212,30 +237,40 @@ static int c_can_plat_probe(struct platform_device
*pdev)
  goto exit_free_device;
  }

- dev->irq = irq;
+ priv->irq = irq;
  priv->base = addr;
  priv->device = &pdev->dev;
- priv->can.clock.freq = clk_get_rate(clk);
  priv->priv = clk;
  priv->type = id->driver_data;

  platform_set_drvdata(pdev, dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- ret = register_c_can_dev(dev);
+
+ dev->ctrl_name = c_can_ctrl_name;
+ dev->board_name = my_board_name;
+ dev->base_addr = (unsigned long)addr;
+ dev->can_sys_clock = clk_get_rate(clk);
+ dev->hard_start_xmit = c_can_start_xmit;
+ dev->do_set_mode = c_can_set_mode;
+ dev->do_set_bit_time = c_can_save_bit_time;
+ dev->bittiming_const = &c_can_bittiming_const;
+ dev->state = CAN_STATE_STOPPED;
+
+ /* Give device an interface name */
+ strncpy(dev->name, DEV_NAME, IFNAMSIZ);
+
+ ret = register_c_candev(dev);
  if (ret) {
  dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
- KBUILD_MODNAME, ret);
+ DRV_NAME, ret);
  goto exit_free_device;
  }

  dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
- KBUILD_MODNAME, priv->base, dev->irq);
+ DRV_NAME, priv->base, priv->irq);
  return 0;

 exit_free_device:
  platform_set_drvdata(pdev, NULL);
- free_c_can_dev(dev);
 exit_iounmap:
  iounmap(addr);
 exit_release_mem:
@@ -250,98 +285,42 @@ exit:

 static int c_can_plat_remove(struct platform_device *pdev)
 {
- struct net_device *dev = platform_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(dev);
+ struct rtcan_device *dev = platform_get_drvdata(pdev);
+ struct c_can_priv *priv = rtcan_priv(dev);
  struct resource *mem;

- unregister_c_can_dev(dev);
+ unregister_c_candev(dev);
  platform_set_drvdata(pdev, NULL);

- free_c_can_dev(dev);
  iounmap(priv->base);

  mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  release_mem_region(mem->start, resource_size(mem));

  clk_put(priv->priv);
+
+ rtcan_dev_free(dev);

  return 0;
 }

-#ifdef CONFIG_PM
-static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
-{
- int ret;
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(ndev);
-
- if (priv->type != BOSCH_D_CAN) {
- dev_warn(&pdev->dev, "Not supported\n");
- return 0;
- }
-
- if (netif_running(ndev)) {
- netif_stop_queue(ndev);
- netif_device_detach(ndev);
- }
-
- ret = c_can_power_down(ndev);
- if (ret) {
- netdev_err(ndev, "failed to enter power down mode\n");
- return ret;
- }
-
- priv->can.state = CAN_STATE_SLEEPING;
-
- return 0;
-}
-
-static int c_can_resume(struct platform_device *pdev)
-{
- int ret;
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct c_can_priv *priv = netdev_priv(ndev);
-
- if (priv->type != BOSCH_D_CAN) {
- dev_warn(&pdev->dev, "Not supported\n");
- return 0;
- }
-
- ret = c_can_power_up(ndev);
- if (ret) {
- netdev_err(ndev, "Still in power down mode\n");
- return ret;
- }
-
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
-
- if (netif_running(ndev)) {
- netif_device_attach(ndev);
- netif_start_queue(ndev);
- }
-
- return 0;
-}
-#else
-#define c_can_suspend NULL
-#define c_can_resume NULL
-#endif
-
 static struct platform_driver c_can_plat_driver = {
  .driver = {
- .name = KBUILD_MODNAME,
+ /* For legacy platform support */
+ .name = DRV_NAME,
  .owner = THIS_MODULE,
+#ifdef CONFIG_OF
  .of_match_table = of_match_ptr(c_can_of_table),
+#endif
  },
+ .id_table = c_can_id_table,
  .probe = c_can_plat_probe,
  .remove = c_can_plat_remove,
- .suspend = c_can_suspend,
- .resume = c_can_resume,
- .id_table = c_can_id_table,
 };

 module_platform_driver(c_can_plat_driver);

-MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
+
+MODULE_AUTHOR("Stephen J. Battazzo <stephen.j.battazzo@nasa.gov>");
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");
+MODULE_DESCRIPTION("CAN bus RTDM driver for Bosch C_CAN controller");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread
* [Xenomai] RT-CAN driver for C_CAN,D_CAN cores ready
@ 2015-04-19 23:01 Michael Haberler
  2015-04-26 20:46 ` Wolfgang Grandegger
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Haberler @ 2015-04-19 23:01 UTC (permalink / raw)
  To: xenomai

here is the RT-CAN driver by Steve Battazzo for (among others) the
Beaglebone: https://github.com/mhaberler/xeno_d_can/commits/for-xenomai-2

I've reconstructed the history as Steve based this on the 3.8 c_can driver.
The problems Steve originally noted are resolved.

Please let me know if anything is missing for a merge into Xenomai 2.

- Michael


Usage:

blacklist the Linux drivers in /etc/modprobe.d/can-blackist.conf:

blacklist c_can_platform

blacklist c_can

blacklist can_dev


enable the can pins using the universal overlay (
https://github.com/cdsteinkuehler/beaglebone-universal-io)


config-pin overlay cape-universal

config-pin P9.24 can

config-pin P9.26 can


# load the rtcan mods

modprobe xeno_can

modprobe rtcan_can


# start the rtcan interface

rtcanconfig rtcan1 -b 1000000 start

rtcansend rtcan1 --verbose --identifier=0x1  0x04 0x01 0x00 0x00 0x0f 0xff
0xe7 0x00

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-04-29  7:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-28 15:47 [Xenomai] RT-CAN driver for C_CAN,D_CAN cores ready Michael Haberler
2015-04-28 16:02 ` Gilles Chanteperdrix
2015-04-28 20:19   ` Michael Haberler
2015-04-29  4:30     ` Gilles Chanteperdrix
2015-04-29  7:05 ` Wolfgang Grandegger
  -- strict thread matches above, loose matches on Subject: below --
2015-04-19 23:01 Michael Haberler
2015-04-26 20:46 ` Wolfgang Grandegger
2015-04-28 14:01   ` Michael Haberler
2015-04-28 14:11     ` Gilles Chanteperdrix
2015-04-29  6:35       ` Wolfgang Grandegger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.