netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 09/13] can: pruss CAN driver.
       [not found] <1297435892-28278-1-git-send-email-subhasish@mistralsolutions.com>
@ 2011-02-11 14:51 ` Subhasish Ghosh
       [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
  2011-02-18 15:07   ` Arnd Bergmann
  0 siblings, 2 replies; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: davinci-linux-open-source
  Cc: linux-arm-kernel, m-watkins, nsekhar, sachi, Subhasish Ghosh,
	Wolfgang Grandegger, open list:CAN NETWORK DRIVERS,
	open list:CAN NETWORK DRIVERS, open list

This patch adds support for the CAN device emulated on PRUSS.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/net/can/Kconfig                     |    1 +
 drivers/net/can/Makefile                    |    1 +
 drivers/net/can/da8xx_pruss/Kconfig         |   73 ++
 drivers/net/can/da8xx_pruss/Makefile        |    7 +
 drivers/net/can/da8xx_pruss/pruss_can.c     |  758 +++++++++++++++++
 drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++
 drivers/net/can/da8xx_pruss/pruss_can_api.h |  290 +++++++
 7 files changed, 2357 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/da8xx_pruss/Kconfig
 create mode 100644 drivers/net/can/da8xx_pruss/Makefile
 create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c
 create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c
 create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index d5a9db6..ae8f0f9 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -112,6 +112,7 @@ config PCH_CAN
 	  This driver can access CAN bus.
 
 source "drivers/net/can/mscan/Kconfig"
+source "drivers/net/can/da8xx_pruss/Kconfig"
 
 source "drivers/net/can/sja1000/Kconfig"
 
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 07ca159..849cdbf 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
 obj-$(CONFIG_CAN_MSCAN)		+= mscan/
 obj-$(CONFIG_CAN_AT91)		+= at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
+obj-$(CONFIG_CAN_TI_DA8XX_PRU)	+= da8xx_pruss/
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
 obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
diff --git a/drivers/net/can/da8xx_pruss/Kconfig b/drivers/net/can/da8xx_pruss/Kconfig
new file mode 100644
index 0000000..8b68f68
--- /dev/null
+++ b/drivers/net/can/da8xx_pruss/Kconfig
@@ -0,0 +1,73 @@
+#
+# CAN Lite Kernel Configuration
+#
+config CAN_TI_DA8XX_PRU
+	depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	tristate "PRU based CAN emulation for DA8XX"
+	---help---
+	Enable this to emulate a CAN controller on the PRU of DA8XX.
+	If not sure, mark N
+
+config DA8XX_PRU_CANID_MBX0
+	hex "CANID for mailbox 0"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 0
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX1
+	hex "CANID for mailbox 1"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	 ---help---
+	Enter the CANID for mailbox 1
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX2
+	hex "CANID for mailbox 2"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 2
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX3
+	hex "CANID for mailbox 3"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 3
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX4
+	hex "CANID for mailbox 4"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 4
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX5
+	hex "CANID for mailbox 5"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 5
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX6
+	hex "CANID for mailbox 6"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 6
+	Default value is set to 0x123, change this as required.
+
+config DA8XX_PRU_CANID_MBX7
+	hex "CANID for mailbox 7"
+	depends on CAN_TI_DA8XX_PRU
+	default "0x123"
+	---help---
+	Enter the CANID for mailbox 7
+	Default value is set to 0x123, change this as required.
diff --git a/drivers/net/can/da8xx_pruss/Makefile b/drivers/net/can/da8xx_pruss/Makefile
new file mode 100644
index 0000000..48f3055
--- /dev/null
+++ b/drivers/net/can/da8xx_pruss/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for CAN Lite emulation
+#
+can_emu-objs :=   pruss_can.o \
+                  pruss_can_api.o
+
+obj-$(CONFIG_CAN_TI_DA8XX_PRU)    += can_emu.o
diff --git a/drivers/net/can/da8xx_pruss/pruss_can.c b/drivers/net/can/da8xx_pruss/pruss_can.c
new file mode 100644
index 0000000..1b3afde
--- /dev/null
+++ b/drivers/net/can/da8xx_pruss/pruss_can.c
@@ -0,0 +1,758 @@
+/*
+ *  TI DA8XX PRU CAN Emulation device driver
+ *  Author: subhasish@mistralsolutions.com
+ *
+ *  This driver supports TI's PRU CAN Emulation and the
+ *  specs for the same is available at <http://www.ti.com>
+ *
+ *  Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation version 2.
+ *
+ *  This program is distributed as is WITHOUT ANY WARRANTY of any
+ *  kind, whether express or implied; without even the implied warranty
+ *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <mach/da8xx.h>
+#include "pruss_can_api.h"
+
+#define DRV_NAME "da8xx_pruss_can"
+#define DRV_DESC "TI PRU CAN Controller Driver v0.1"
+#define PRU_CAN_START		1
+#define PRU_CAN_STOP		0
+#define MB_MIN			0
+#define MB_MAX			7
+
+#define PRU_CANMID_IDE			BIT(29)	/* Extended frame format */
+
+#define PRU_CAN_ISR_BIT_CCI		BIT(15)
+#define PRU_CAN_ISR_BIT_ESI		BIT(14)
+#define PRU_CAN_ISR_BIT_SRDI		BIT(13)
+#define PRU_CAN_ISR_BIT_RRI		BIT(8)
+
+#define PRU_CAN_MBXSR_BIT_STATE		BIT(7)
+#define PRU_CAN_MBXSR_BIT_TC		BIT(6)
+#define PRU_CAN_MBXSR_BIT_ERR		BIT(5)
+#define PRU_CAN_MBXSR_BIT_OF		BIT(0)
+
+#define PRU_CAN_GSR_BIT_TXM		BIT(7)
+#define PRU_CAN_GSR_BIT_RXM		BIT(6)
+#define PRU_CAN_GSR_BIT_CM		BIT(5)
+#define PRU_CAN_GSR_BIT_EPM		BIT(4)
+#define PRU_CAN_GSR_BIT_BFM		BIT(3)
+#define RTR_MBX_NO			8
+#define MAX_INIT_RETRIES		20
+#define L138_PRU_ARM_FREQ		312000
+#define DFLT_PRU_FREQ			156000000
+#define DFLT_PRU_BITRATE		125000
+
+#define CONFIG_DA8XX_PRU_CANID_MBX0	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX1	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX2	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX3	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX4	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX5	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX6	0x123
+#define CONFIG_DA8XX_PRU_CANID_MBX7	0x123
+
+#ifdef __CAN_DEBUG
+#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args)
+#else
+#define __can_debug(fmt, args...)
+#endif
+#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)
+
+/*
+ * omapl_pru can private data
+ */
+struct omapl_pru_can_priv {
+	struct can_priv can;
+	struct workqueue_struct *pru_can_wQ;
+	struct work_struct rx_work;
+	struct net_device *ndev;
+	struct device *dev; /* pdev->dev */
+	struct clk *clk_timer;
+	u32 timer_freq;
+	can_emu_app_hndl can_tx_hndl;
+	can_emu_app_hndl can_rx_hndl;
+	const struct firmware *fw_rx;
+	const struct firmware *fw_tx;
+	spinlock_t mbox_lock;
+	u32 trx_irq;
+	u32 tx_head;
+	u32 tx_tail;
+	u32 tx_next;
+	u32 rx_next;
+};
+
+static int omapl_pru_can_get_state(const struct net_device *ndev,
+				   enum can_state *state)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	*state = priv->can.state;
+	return 0;
+}
+
+static int omapl_pru_can_set_bittiming(struct net_device *ndev)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	struct can_bittiming *bt = &priv->can.bittiming;
+	long bit_error = 0;
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) {
+		dev_warn(priv->dev, "WARN: Triple"
+			 "sampling not set due to h/w limitations");
+	}
+	if (pru_can_calc_timing(priv->dev, priv->can.clock.freq,
+				bt->bitrate) != 0)
+		return -EINVAL;
+	bit_error =
+	    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
+	      bt->bitrate) * 1000) / bt->bitrate;
+	if (bit_error) {
+		bit_error =
+		    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
+		      bt->bitrate) * 1000000) / bt->bitrate;
+		printk(KERN_INFO "\nBitrate error %ld.%ld%%\n",
+			bit_error / 10000, bit_error % 1000);
+	} else
+		printk(KERN_INFO "\nBitrate error 0.0%%\n");
+
+	return 0;
+}
+
+static void omapl_pru_can_stop(struct net_device *ndev)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	u16 int_mask = 0;
+
+	pru_can_mask_ints(priv->dev, int_mask);	/* mask all ints */
+	pru_can_start_abort_tx(priv->dev, PRU_CAN_STOP);
+	priv->can.state = CAN_STATE_STOPPED;
+}
+
+/*
+ * This is to just set the can state to ERROR_ACTIVE
+ *	ip link set canX up type can bitrate 125000
+ */
+static void omapl_pru_can_start(struct net_device *ndev)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	u16 int_mask = 0xFFFF;
+
+	if (priv->can.state != CAN_STATE_STOPPED)
+		omapl_pru_can_stop(ndev);
+
+	pru_can_mask_ints(priv->dev, int_mask);	/* unmask all ints */
+
+	pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
+	pru_can_get_global_status(priv->dev, &priv->can_rx_hndl);
+
+	if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus)
+		priv->can.state = CAN_STATE_ERROR_PASSIVE;
+	else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus)
+		priv->can.state = CAN_STATE_BUS_OFF;
+	else
+		priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+static int omapl_pru_can_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+	int ret = 0;
+
+	switch (mode) {
+	case CAN_MODE_START:
+		omapl_pru_can_start(ndev);
+		if (netif_queue_stopped(ndev))
+			netif_wake_queue(ndev);
+		break;
+	case CAN_MODE_STOP:
+		omapl_pru_can_stop(ndev);
+		if (!netif_queue_stopped(ndev))
+			netif_stop_queue(ndev);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb,
+					    struct net_device *ndev)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	struct can_frame *cf = (struct can_frame *)skb->data;
+	int count;
+	u8 *data = cf->data;
+	u8 dlc = cf->can_dlc;
+	u8 *ptr8data = NULL;
+
+	netif_stop_queue(ndev);
+	if (cf->can_id & CAN_EFF_FLAG)	/* Extended frame format */
+		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
+		    (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE;
+	else			/* Standard frame format */
+		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
+		    (cf->can_id & CAN_SFF_MASK) << 18;
+
+	if (cf->can_id & CAN_RTR_FLAG)	/* Remote transmission request */
+		*((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG;
+
+	ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1);
+	for (count = 0; count < (u8) dlc; count++) {
+		*ptr8data-- = *data++;
+	}
+	*((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc;
+/*
+ * search for the next available mbx
+ * if the next mbx is busy, then try the next + 1
+ * do this until the head is reached.
+ * if still unable to tx, stop accepting any packets
+ * if able to tx and the head is reached, then reset next to tail, i.e mbx0
+ * if head is not reached, then just point to the next mbx
+ */
+	for (; priv->tx_next <= priv->tx_head; priv->tx_next++) {
+		priv->can_tx_hndl.ecanmailboxnumber =
+		    (can_mailbox_number) priv->tx_next;
+		if (-1 == pru_can_write_data_to_mailbox(priv->dev,
+					&priv->can_tx_hndl)) {
+			if (priv->tx_next == priv->tx_head) {
+				priv->tx_next = priv->tx_tail;
+				if (!netif_queue_stopped(ndev))
+					netif_stop_queue(ndev);	/* IF stalled */
+				dev_err(priv->dev,
+					"%s: no tx mbx available", __func__);
+				return NETDEV_TX_BUSY;
+			} else
+				continue;
+		} else {
+			/* set transmit request */
+			pru_can_tx(priv->dev, priv->tx_next, CAN_TX_PRU_1);
+			pru_can_tx_mode_set(priv->dev, false, ecanreceive);
+			pru_can_tx_mode_set(priv->dev, true, ecantransmit);
+			pru_can_start_abort_tx(priv->dev, PRU_CAN_START);
+			priv->tx_next++;
+			can_put_echo_skb(skb, ndev, 0);
+			break;
+		}
+	}
+	if (priv->tx_next > priv->tx_head) {
+		priv->tx_next = priv->tx_tail;
+	}
+	return NETDEV_TX_OK;
+}
+
+static int omapl_pru_can_rx(struct net_device *ndev, u32 mbxno)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	struct net_device_stats *stats = &ndev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	u32 pru_can_mbx_data;
+	u8 *data = NULL;
+	u8 *ptr8data = NULL;
+	int count = 0;
+
+	skb = alloc_can_skb(ndev, &cf);
+	if (!skb) {
+		if (printk_ratelimit())
+			dev_err(priv->dev,
+				"alloc_can_skb() failed\n");
+		return -ENOMEM;
+	}
+	data = cf->data;
+	/*      get payload */
+	priv->can_rx_hndl.ecanmailboxnumber = (can_mailbox_number) mbxno;
+	if (pru_can_get_data_from_mailbox(priv->dev, &priv->can_rx_hndl)) {
+		__can_err("failed to get data from mailbox\n");
+		return -EAGAIN;
+	}
+	/* give ownweship to pru */
+	pru_can_tx(priv->dev, mbxno, CAN_RX_PRU_0);
+
+	/* get data length code */
+	cf->can_dlc =
+	    get_can_dlc(*
+			((u32 *) &priv->can_rx_hndl.strcanmailbox.
+			 u16datalength) & 0xF);
+	if (cf->can_dlc <= 4) {
+		ptr8data =
+		    &priv->can_rx_hndl.strcanmailbox.u8data3 + (4 -
+								cf->can_dlc);
+		for (count = 0; count < cf->can_dlc; count++) {
+			*data++ = *ptr8data++;
+		}
+	} else {
+		ptr8data = &priv->can_rx_hndl.strcanmailbox.u8data3;
+		for (count = 0; count < 4; count++) {
+			*data++ = *ptr8data++;
+		}
+		ptr8data =
+		    &priv->can_rx_hndl.strcanmailbox.u8data4 - (cf->can_dlc -
+								5);
+		for (count = 0; count < cf->can_dlc - 4; count++) {
+			*data++ = *ptr8data++;
+		}
+	}
+
+	pru_can_mbx_data = *((u32 *) &priv->can_rx_hndl.strcanmailbox);
+	/* get id extended or std */
+	if (pru_can_mbx_data & PRU_CANMID_IDE)
+		cf->can_id = (pru_can_mbx_data & CAN_EFF_MASK) | CAN_EFF_FLAG;
+	else
+		cf->can_id = (pru_can_mbx_data >> 18) & CAN_SFF_MASK;
+
+	if (pru_can_mbx_data & CAN_RTR_FLAG)
+		cf->can_id |= CAN_RTR_FLAG;
+
+	netif_rx_ni(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+	return 0;
+}
+
+static int omapl_pru_can_err(struct net_device *ndev, int int_status,
+			     int err_status)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	struct net_device_stats *stats = &ndev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	int tx_err_cnt, rx_err_cnt;
+
+	/* propogate the error condition to the can stack */
+	skb = alloc_can_err_skb(ndev, &cf);
+	if (!skb) {
+		if (printk_ratelimit())
+			dev_err(priv->dev,
+				"alloc_can_err_skb() failed\n");
+		return -ENOMEM;
+	}
+
+	if (err_status & PRU_CAN_GSR_BIT_EPM) {	/* error passive int */
+		priv->can.state = CAN_STATE_ERROR_PASSIVE;
+		++priv->can.can_stats.error_passive;
+		cf->can_id |= CAN_ERR_CRTL;
+		tx_err_cnt = pru_can_get_error_cnt(priv->dev, CAN_TX_PRU_1);
+		rx_err_cnt = pru_can_get_error_cnt(priv->dev, CAN_RX_PRU_0);
+		if (tx_err_cnt > 127)
+			cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+		if (rx_err_cnt > 127)
+			cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+
+		dev_dbg(priv->ndev->dev.parent, "Error passive interrupt\n");
+	}
+
+	if (err_status & PRU_CAN_GSR_BIT_BFM) {
+		priv->can.state = CAN_STATE_BUS_OFF;
+		cf->can_id |= CAN_ERR_BUSOFF;
+		/*
+		 *      Disable all interrupts in bus-off to avoid int hog
+		 *      this should be handled by the pru
+		 */
+		pru_can_mask_ints(priv->dev, 0xFFFF);
+		can_bus_off(ndev);
+		dev_dbg(priv->ndev->dev.parent, "Bus off mode\n");
+	}
+
+	netif_rx(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+	return 0;
+}
+
+void omapl_pru_can_rx_wQ(struct work_struct *work)
+{
+	struct omapl_pru_can_priv *priv = container_of(work,
+			struct omapl_pru_can_priv, rx_work);
+	struct net_device *ndev = priv->ndev;
+	u32 bit_set, mbxno = 0;
+
+	if (-1 == pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
+		return;
+
+	if (PRU_CAN_ISR_BIT_RRI & priv->can_rx_hndl.u32interruptstatus) {
+		mbxno = RTR_MBX_NO;
+		omapl_pru_can_rx(ndev, mbxno);
+	} else {
+		/* Extract the mboxno from the status */
+		for (bit_set = 0; ((priv->can_rx_hndl.u32interruptstatus & 0xFF)
+						>> bit_set != 0); bit_set++)
+		;
+		if (0 == bit_set) {
+			dev_err(priv->dev,
+				"%s: invalid mailbox number: %X\n", __func__,
+				priv->can_rx_hndl.u32interruptstatus);
+		} else {
+			mbxno = bit_set - 1;
+			if (PRU_CAN_ISR_BIT_ESI & priv->can_rx_hndl.
+			    u32interruptstatus) {
+				pru_can_get_global_status(priv->dev,
+					&priv->can_rx_hndl);
+				omapl_pru_can_err(ndev,
+				priv->can_rx_hndl.u32interruptstatus,
+				priv->can_rx_hndl.u32globalstatus);
+			} else {
+				omapl_pru_can_rx(ndev, mbxno);
+			}
+		}
+	}
+}
+
+irqreturn_t omapl_tx_can_intr(int irq, void *dev_id)
+{
+	struct net_device *ndev = dev_id;
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	struct net_device_stats *stats = &ndev->stats;
+	u32 bit_set, mbxno;
+
+	pru_can_get_intr_status(priv->dev, &priv->can_tx_hndl);
+	if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus)
+	    || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) {
+		__can_debug("tx_int_status = 0x%X\n",
+			    priv->can_tx_hndl.u32interruptstatus);
+		can_free_echo_skb(ndev, 0);
+	} else {
+		for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF)
+						>> bit_set != 0); bit_set++)
+		;
+		if (0 == bit_set) {
+			__can_err("%s: invalid mailbox number\n", __func__);
+			can_free_echo_skb(ndev, 0);
+		} else {
+			mbxno = bit_set - 1;	/* mail box numbering starts from 0 */
+			if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl.
+			    u32interruptstatus) {
+				/* read gsr and ack pru */
+				pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
+				omapl_pru_can_err(ndev,
+						  priv->can_tx_hndl.
+						  u32interruptstatus,
+						  priv->can_tx_hndl.
+						  u32globalstatus);
+			} else {
+				stats->tx_packets++;
+				/* stats->tx_bytes += dlc; */
+				/*can_get_echo_skb(ndev, 0);*/
+			}
+		}
+	}
+	if (netif_queue_stopped(ndev))
+		netif_wake_queue(ndev);
+
+	can_get_echo_skb(ndev, 0);
+	pru_can_tx_mode_set(priv->dev, true, ecanreceive);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t omapl_rx_can_intr(int irq, void *dev_id)
+{
+
+	struct net_device *ndev = dev_id;
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	u32 intc_status = 0;
+
+	intc_status = pru_can_get_intc_status(priv->dev);
+	if (intc_status & 4)
+		return omapl_tx_can_intr(irq, dev_id);
+	if (intc_status & 2) {
+		if (!work_pending(&priv->rx_work))
+			queue_work(priv->pru_can_wQ, &priv->rx_work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int omapl_pru_can_open(struct net_device *ndev)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+	int err;
+
+	/* register interrupt handler */
+	err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
+			  "pru_can_irq", ndev);
+	if (err) {
+		dev_err(priv->dev, "error requesting rx interrupt\n");
+		goto exit_trx_irq;
+	}
+	/* common open */
+	err = open_candev(ndev);
+	if (err) {
+		dev_err(priv->dev, "open_candev() failed %d\n", err);
+		goto exit_open;
+	}
+
+	pru_can_emu_init(priv->dev, priv->can.clock.freq);
+	priv->tx_tail = MB_MIN;
+	priv->tx_head = MB_MAX;
+
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX0, 0);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX1, 1);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX2, 2);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX3, 3);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX4, 4);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX5, 5);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX6, 6);
+	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX7, 7);
+
+	omapl_pru_can_start(ndev);
+	netif_start_queue(ndev);
+	return 0;
+
+exit_open:
+	free_irq(priv->trx_irq, ndev);
+exit_trx_irq:
+	return err;
+}
+
+static int omapl_pru_can_close(struct net_device *ndev)
+{
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+
+	if (!netif_queue_stopped(ndev))
+		netif_stop_queue(ndev);
+
+	close_candev(ndev);
+
+	free_irq(priv->trx_irq, ndev);
+	return 0;
+}
+
+static const struct net_device_ops omapl_pru_can_netdev_ops = {
+	.ndo_open		= omapl_pru_can_open,
+	.ndo_stop		= omapl_pru_can_close,
+	.ndo_start_xmit		= omapl_pru_can_start_xmit,
+};
+
+static int __devinit omapl_pru_can_probe(struct platform_device *pdev)
+{
+	struct net_device *ndev = NULL;
+	const struct da8xx_pru_can_data *pdata;
+	struct omapl_pru_can_priv *priv = NULL;
+	struct device *dev = &pdev->dev;
+	u32 err;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	ndev = alloc_candev(sizeof(struct omapl_pru_can_priv), MB_MAX + 1);
+	if (!ndev) {
+		dev_err(&pdev->dev, "alloc_candev failed\n");
+		err = -ENOMEM;
+		goto probe_exit;
+	}
+	priv = netdev_priv(ndev);
+
+	priv->trx_irq = platform_get_irq(to_platform_device(dev->parent), 0);
+	if (!priv->trx_irq) {
+		dev_err(&pdev->dev, "unable to get pru interrupt resources!\n");
+		err = -ENODEV;
+		goto probe_exit;
+	}
+
+	priv->ndev = ndev;
+	priv->dev = dev; /* priv->dev = pdev->dev */
+
+	priv->can.bittiming_const = NULL;
+	priv->can.do_set_bittiming = omapl_pru_can_set_bittiming;
+	priv->can.do_set_mode = omapl_pru_can_set_mode;
+	priv->can.do_get_state = omapl_pru_can_get_state;
+	priv->can_tx_hndl.u8prunumber = CAN_TX_PRU_1;
+	priv->can_rx_hndl.u8prunumber = CAN_RX_PRU_0;
+
+	/* we support local echo, no arp */
+	ndev->flags |= (IFF_ECHO | IFF_NOARP);
+
+	/* pdev->dev->device_private->driver_data = ndev */
+	platform_set_drvdata(pdev, ndev);
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+	ndev->netdev_ops = &omapl_pru_can_netdev_ops;
+
+	priv->can.clock.freq = pruss_get_clk_freq(priv->dev);
+
+	priv->clk_timer = clk_get(&pdev->dev, "pll1_sysclk2");
+	if (IS_ERR(priv->clk_timer)) {
+		dev_err(&pdev->dev, "no timer clock available\n");
+		err = PTR_ERR(priv->clk_timer);
+		priv->clk_timer = NULL;
+		goto probe_exit_candev;
+	}
+	priv->timer_freq = clk_get_rate(priv->clk_timer);
+
+	err = register_candev(ndev);
+	if (err) {
+		dev_err(&pdev->dev, "register_candev() failed\n");
+		err = -ENODEV;
+		goto probe_exit_clk;
+	}
+
+	err = request_firmware(&priv->fw_tx, "PRU_CAN_Emulation_Tx.bin",
+			&pdev->dev);
+	if (err) {
+		dev_err(&pdev->dev, "can't load firmware\n");
+		err = -ENODEV;
+		goto probe_exit_clk;
+	}
+
+	dev_info(&pdev->dev, "fw_tx size %d. downloading...\n",
+		 priv->fw_tx->size);
+
+	err = request_firmware(&priv->fw_rx, "PRU_CAN_Emulation_Rx.bin",
+			&pdev->dev);
+	if (err) {
+		dev_err(&pdev->dev, "can't load firmware\n");
+		err = -ENODEV;
+		goto probe_release_fw;
+	}
+	dev_info(&pdev->dev, "fw_rx size %d. downloading...\n",
+		 priv->fw_rx->size);
+
+	/* init the pru */
+	pru_can_emu_init(priv->dev, priv->can.clock.freq);
+	udelay(200);
+
+	pruss_enable(priv->dev, CAN_RX_PRU_0);
+	pruss_enable(priv->dev, CAN_TX_PRU_1);
+
+	/* download firmware into pru */
+	err = pruss_load(priv->dev, CAN_RX_PRU_0,
+		(u32 *)priv->fw_rx->data, (priv->fw_rx->size / 4));
+	if (err) {
+		dev_err(&pdev->dev, "firmware download error\n");
+		err = -ENODEV;
+		goto probe_release_fw_1;
+	}
+	err = pruss_load(priv->dev, CAN_TX_PRU_1,
+		(u32 *)priv->fw_tx->data, (priv->fw_tx->size / 4));
+	if (err) {
+		dev_err(&pdev->dev, "firmware download error\n");
+		err = -ENODEV;
+		goto probe_release_fw_1;
+	}
+
+	if (pru_can_calc_timing(priv->dev, DFLT_PRU_FREQ,
+				DFLT_PRU_BITRATE) != 0)
+		return -EINVAL;
+
+	pruss_run(priv->dev, CAN_RX_PRU_0);
+	pruss_run(priv->dev, CAN_TX_PRU_1);
+
+	/*Create The Work Queue */
+	priv->pru_can_wQ = create_freezeable_workqueue("omapl_pru_wQ");
+	if (priv->pru_can_wQ == NULL) {
+		dev_err(&pdev->dev, "failed to create work queue\n");
+		err = -ENODEV;
+		goto probe_release_fw_1;
+	}
+
+	INIT_WORK(&priv->rx_work, omapl_pru_can_rx_wQ);
+	dev_info(&pdev->dev,
+		 "%s device registered (trx_irq = %d,  clk = %d)\n",
+		 DRV_NAME, priv->trx_irq, priv->can.clock.freq);
+
+	return 0;
+
+probe_release_fw_1:
+	release_firmware(priv->fw_rx);
+probe_release_fw:
+	release_firmware(priv->fw_tx);
+probe_exit_clk:
+	clk_put(priv->clk_timer);
+probe_exit_candev:
+	if (NULL != ndev)
+		free_candev(ndev);
+probe_exit:
+	return err;
+}
+
+static int __devexit omapl_pru_can_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
+
+	omapl_pru_can_stop(ndev);
+
+	pru_can_emu_exit(priv->dev);
+	release_firmware(priv->fw_tx);
+	release_firmware(priv->fw_rx);
+	clk_put(priv->clk_timer);
+	flush_workqueue(priv->pru_can_wQ);
+	destroy_workqueue(priv->pru_can_wQ);
+	unregister_candev(ndev);
+	free_candev(ndev);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int omapl_pru_can_suspend(struct platform_device *pdev,
+			pm_message_t mesg)
+{
+	dev_info(&pdev->dev, "%s not yet implemented\n", __func__);
+	return 0;
+}
+
+static int omapl_pru_can_resume(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev, "%s not yet implemented\n", __func__);
+	return 0;
+}
+#else
+#define omapl_pru_can_suspend NULL
+#define omapl_pru_can_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver omapl_pru_can_driver = {
+	.probe		= omapl_pru_can_probe,
+	.remove		= __devexit_p(omapl_pru_can_remove),
+	.suspend	= omapl_pru_can_suspend,
+	.resume		= omapl_pru_can_resume,
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init omapl_pru_can_init(void)
+{
+	__can_debug(KERN_INFO DRV_DESC "\n");
+	return platform_driver_register(&omapl_pru_can_driver);
+}
+
+module_init(omapl_pru_can_init);
+
+static void __exit omapl_pru_can_exit(void)
+{
+	__can_debug(KERN_INFO DRV_DESC " unloaded\n");
+	platform_driver_unregister(&omapl_pru_can_driver);
+}
+
+module_exit(omapl_pru_can_exit);
+
+MODULE_AUTHOR("Subhasish Ghosh <subhasish@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("omapl pru CAN netdevice driver");
diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.c b/drivers/net/can/da8xx_pruss/pruss_can_api.c
new file mode 100644
index 0000000..2f7438a
--- /dev/null
+++ b/drivers/net/can/da8xx_pruss/pruss_can_api.c
@@ -0,0 +1,1227 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Wilfred Felix
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as  published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include "pruss_can_api.h"
+
+static can_emu_drv_inst gstr_can_inst[ecanmaxinst];
+
+/*
+ * pru_can_set_brp()	Updates the  BRP register of PRU0
+ * and PRU1 of OMAP L138. This API will be called by the
+ * Application to updtae the BRP register of PRU0 and PRU1
+ *
+ * param	u16bitrateprescaler		The can bus bitrate
+ * prescaler value be set
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_set_brp(struct device *dev, u16 u16bitrateprescaler)
+{
+
+	u32 u32offset;
+
+	if (u16bitrateprescaler > 255) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER);
+	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
+
+	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
+	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
+
+	return 0;
+
+}
+
+/*
+ * pru_can_set_bit_timing()		Updates the timing register
+ * of PRU0 and PRU1 of OMAP L138. This API will be called by
+ * the Application to updtae the timing register of PRU0 and PRU1
+ *
+ * param	pstrbittiming		Pointer to structure holding
+ * the bit timing values for can bus.
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_set_bit_timing(struct device *dev,
+		can_bit_timing_consts *pstrbittiming)
+{
+
+	u32 u32offset;
+	u32 u32serregister;
+
+	u32serregister = 0;
+
+	if (pstrbittiming == NULL) {
+		return -1;
+	}
+
+	if ((pstrbittiming->u8syncjumpwidth > PRU_CAN_MAX_SJW) ||
+	    (pstrbittiming->u8phseg1 > PRU_CAN_MAX_PHSEG1) ||
+	    (pstrbittiming->u8phseg2 > PRU_CAN_MAX_PHSEG2)) {
+		return -1;
+	}
+
+	u32serregister = u32serregister |
+			((pstrbittiming->u8syncjumpwidth << 7) |
+			(pstrbittiming->u8phseg1 << 3) |
+			(pstrbittiming->u8phseg2));
+
+	u32offset = (PRU_CAN_TX_TIMING_REGISTER);
+	pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1);
+
+	u32offset = (PRU_CAN_RX_TIMING_REGISTER);
+	pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1);
+
+	return 0;
+}
+
+
+/*
+ * pru_can_calc_timing()
+ * Updates the  timing values of PRU0 and PRU1 of OMAP L138.
+ * This API will be called by the
+ * Application to updtae the timing values of PRU0 and PRU1
+ *
+ * return   SUCCESS or FAILURE
+ */
+
+s16 pru_can_calc_timing(struct device *dev, u32 pru_freq, u32 bit_rate)
+{
+	u16 u16phaseseg1;
+	u16 u16phaseseg2;
+	u32 u32offset;
+	u32 u32timing_value;
+	u32 u32setup_value;
+	u32timing_value = TIMER_CLK_FREQ / bit_rate;
+	u32offset = (PRU_CAN_TIMING_VAL_TX);
+	pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4);
+	pruss_readl(dev, u32offset, (u32 *) &u32timing_value, 4);
+	u32setup_value =
+	    (GPIO_SETUP_DELAY * (pru_freq / 1000000) / 1000) /
+	    DELAY_LOOP_LENGTH;
+	u32offset = (PRU_CAN_TIMING_VAL_TX_SJW);
+	pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4);
+	u16phaseseg1 = (u16) (u32timing_value / 2);
+	u16phaseseg2 = u32timing_value - u16phaseseg1;
+	u16phaseseg1 -= TIMER_SETUP_DELAY;
+	u16phaseseg2 -= TIMER_SETUP_DELAY;
+	u32setup_value = (u16phaseseg1 << 16) | u16phaseseg2;
+	u32offset = (PRU_CAN_TIMING_VAL_RX);
+	pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4);
+	u32offset = (PRU_CAN_TIMING_VAL_RX + 4);
+	pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4);
+
+	return 0;
+}
+
+/*
+ * pru_can_write_data_to_mailbox()
+ * Updates the transmit mailboxes of PRU1 of OMAP L138.
+ * This API will be called by the Application to update
+ * the transmit mailboxes of PRU1
+ *
+ * param  pu16canframedata	Can mailbox data buffer
+ *
+ * param  u8mailboxnum		Mailbox to be updated
+ *
+ * return SUCCESS or FAILURE
+ */
+s16 pru_can_write_data_to_mailbox(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl)
+{
+	s16 s16subrtnretval;
+	u32 u32offset;
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+
+	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
+	case 0:
+		u32offset = (PRU_CAN_TX_MAILBOX0);
+		break;
+	case 1:
+		u32offset = (PRU_CAN_TX_MAILBOX1);
+		break;
+	case 2:
+		u32offset = (PRU_CAN_TX_MAILBOX2);
+		break;
+	case 3:
+		u32offset = (PRU_CAN_TX_MAILBOX3);
+		break;
+	case 4:
+		u32offset = (PRU_CAN_TX_MAILBOX4);
+		break;
+	case 5:
+		u32offset = (PRU_CAN_TX_MAILBOX5);
+		break;
+	case 6:
+		u32offset = (PRU_CAN_TX_MAILBOX6);
+		break;
+	case 7:
+		u32offset = (PRU_CAN_TX_MAILBOX7);
+		break;
+	default:
+		return -1;
+	}
+
+	s16subrtnretval = pruss_writel(dev, u32offset,
+		(u32 *) &(pstremuapphndl->strcanmailbox), 4);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * pru_can_get_data_from_mailbox()
+ * Receive data from the receive mailboxes of PRU0  of OMAP L138.
+ * This API will be called by the Application to get data from
+ * the receive mailboxes of PRU0
+ *
+ * param  pu16canframedata	Can mailbox data buffer
+ *
+ * param  u8mailboxnum		Mailbox to be updated
+ *
+ * return SUCCESS or FAILURE
+ */
+s16 pru_can_get_data_from_mailbox(struct device *dev,
+		can_emu_app_hndl *pstremuapphndl)
+{
+	s16 s16subrtnretval;
+	u32 u32offset;
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+
+	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
+	case 0:
+		u32offset = (PRU_CAN_RX_MAILBOX0);
+		break;
+	case 1:
+		u32offset = (PRU_CAN_RX_MAILBOX1);
+		break;
+	case 2:
+		u32offset = (PRU_CAN_RX_MAILBOX2);
+		break;
+	case 3:
+		u32offset = (PRU_CAN_RX_MAILBOX3);
+		break;
+	case 4:
+		u32offset = (PRU_CAN_RX_MAILBOX4);
+		break;
+	case 5:
+		u32offset = (PRU_CAN_RX_MAILBOX5);
+		break;
+	case 6:
+		u32offset = (PRU_CAN_RX_MAILBOX6);
+		break;
+	case 7:
+		u32offset = (PRU_CAN_RX_MAILBOX7);
+		break;
+	case 8:
+		u32offset = (PRU_CAN_RX_MAILBOX8);
+		break;
+	default:
+		return -1;
+	}
+
+	s16subrtnretval =
+	    pruss_readl(dev, u32offset,
+		  (u32 *) &(pstremuapphndl->strcanmailbox),
+				  4);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * pru_can_receive_id_map()
+ * Receive mailboxes ID Mapping of PRU0  of OMAP L138.
+ * This API will be called by the Application
+ * to map the IDs  to receive mailboxes of PRU0
+ *
+ * param  u32nodeid		Can node ID
+ *
+ * param  ecanmailboxno		Mailbox to be mapped
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_rx_id_map(struct device *dev, u32 u32nodeid,
+		can_mailbox_number ecanmailboxno)
+{
+
+	pruss_writel(dev, (PRU_CAN_ID_MAP +
+		(((u8) ecanmailboxno) * 4)), (u32 *) &u32nodeid, 1);
+
+	return 0;
+}
+
+/*
+ * pru_can_get_intr_status()
+ * Gets the interrupts status register value.
+ * This API will be called by the Application
+ * to get the interrupts status register value
+ *
+ * param  u8prunumber	PRU number for which IntStatusReg
+ * has to be read
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_get_intr_status(struct device *dev,
+		can_emu_app_hndl *pstremuapphndl)
+{
+	u32 u32offset;
+	s16 s16subrtnretval = -1;
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+
+	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
+		u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER);
+	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
+		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER);
+	} else {
+		return -1;
+	}
+
+	s16subrtnretval = pruss_readl(dev, u32offset,
+		(u32 *) &pstremuapphndl->u32interruptstatus, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * pru_can_get_global_status()	Gets the globalstatus
+ * register value. This API will be called by the Application
+ * to  get the global status register value
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_get_global_status(struct device *dev,
+		can_emu_app_hndl *pstremuapphndl)
+{
+	u32 u32offset;
+	int s16subrtnretval = -1;
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+
+	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
+		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
+	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
+		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
+	} else {
+		return -1;
+	}
+
+	s16subrtnretval = pruss_readl(dev, u32offset,
+		(u32 *) &pstremuapphndl->u32globalstatus, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * pru_can_get_mailbox_status()		Gets the mailbox status
+ * register value. This API will be called by the Application
+ * to get the mailbox status register value
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_get_mailbox_status(struct device *dev,
+		can_emu_app_hndl *pstremuapphndl)
+{
+	u32 u32offset;
+	s16 s16subrtnretval = -1;
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+
+	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
+		switch (pstremuapphndl->ecanmailboxnumber) {
+		case 0:
+			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER);
+			break;
+		case 1:
+			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER);
+			break;
+		case 2:
+			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER);
+			break;
+		case 3:
+			u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER);
+			break;
+		case 4:
+			u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER);
+			break;
+		case 5:
+			u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER);
+			break;
+		case 6:
+			u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER);
+			break;
+		case 7:
+			u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER);
+			break;
+		default:
+			return -1;
+		}
+	}
+
+	else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
+		switch (pstremuapphndl->ecanmailboxnumber) {
+		case 0:
+			u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER);
+			break;
+		case 1:
+			u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER);
+			break;
+		case 2:
+			u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER);
+			break;
+		case 3:
+			u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER);
+			break;
+		case 4:
+			u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER);
+			break;
+		case 5:
+			u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER);
+			break;
+		case 6:
+			u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER);
+			break;
+		case 7:
+			u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER);
+			break;
+		case 8:
+			u32offset = (PRU_CAN_RX_MAILBOX8_STATUS_REGISTER);
+			break;
+		default:
+			return -1;
+		}
+	}
+
+	else {
+		return -1;
+	}
+
+	s16subrtnretval = pruss_readl(dev, u32offset,
+		(u32 *) &pstremuapphndl->u32mailboxstatus, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	return 0;
+}
+
+s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag,
+				can_transfer_direction ecan_trx)
+{
+	u32 u32offset;
+	u32 u32value;
+
+	if (ecan_trx == ecantransmit) {
+		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
+		pruss_readl(dev, u32offset, &u32value, 1);
+		if (btransfer_flag == true) {
+			u32value &= 0x1F;
+			u32value |= 0x80;
+		} else {
+			u32value &= 0x7F;
+		}
+		pruss_writel(dev, u32offset, &u32value, 1);
+		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
+		pruss_writel(dev, u32offset, &u32value, 1);
+	} else if (ecan_trx == ecanreceive) {
+		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
+		pruss_readl(dev, u32offset, &u32value, 1);
+		if (btransfer_flag == true) {
+			u32value &= 0x1F;
+			u32value |= 0x40;
+		} else {
+			u32value &= 0xBF;
+		}
+		pruss_writel(dev, u32offset, &u32value, 1);
+		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
+		pruss_writel(dev, u32offset, &u32value, 1);
+	} else
+		return -1;
+
+	return 0;
+}
+
+/*
+ * pru_can_config_mode_set()		Sets the timing value
+ * for data transfer. This API will be called by the Application
+ * to set timing valus for data transfer
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_config_mode_set(struct device *dev, bool bconfigmodeflag)
+{
+
+	u32 u32bitrateprescaler;
+	u32 u32canbittiming;
+
+	pruss_readl(dev, (PRU_CAN_TX_CLOCK_BRP_REGISTER),
+			(u32 *) &u32bitrateprescaler, 1);
+	pruss_readl(dev, (PRU_CAN_TX_TIMING_REGISTER),
+			(u32 *) &u32canbittiming, 1);
+
+	if (bconfigmodeflag == 1) {
+		pru_can_calc_timing(dev, u32canbittiming, u32bitrateprescaler);
+	}
+
+	else {
+		pru_can_calc_timing(dev, 0, 0);
+	}
+
+	return 0;
+}
+
+/*
+ * pru_can_emu_init()		Initializes the Can
+ * Emulation Parameters. This API will be called by the Application
+ * to Initialize the Can Emulation Parameters
+ *
+ * param    u32pruclock         PRU Clock value
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_emu_init(struct device *dev, u32 u32pruclock)
+{
+	u32 u32offset;
+	u32 u32value;
+	s16 s16subrtnretval = -1;
+	u8 u8loop;
+
+	for (u8loop = 0; u8loop < (u8) ecanmaxinst; u8loop++) {
+		gstr_can_inst[u8loop].bcaninststate = (bool) 0;
+		gstr_can_inst[u8loop].ecantransferdirection =
+		    (can_transfer_direction) 0;
+		gstr_can_inst[u8loop].u32apphandlerptr = 0;
+	}
+
+	u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000040;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000040;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_INTERRUPT_MASK_REGISTER & 0xFFFF);
+	u32value = 0x00004000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval =
+	    pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000001;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_TIMING_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_POLARITY0 & 0xFFFF);
+	u32value = 0xFFFFFFFF;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	u32offset = (PRUSS_INTC_POLARITY1 & 0xFFFF);
+	u32value = 0xFFFFFFFF;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	u32offset = (PRUSS_INTC_TYPE0 & 0xFFFF);
+	u32value = 0x1C000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	u32offset = (PRUSS_INTC_TYPE1 & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_HSTINTENIDXCLR & 0xFFFF);
+	u32value = 0x0;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_GLBLEN & 0xFFFF);
+	u32value = 0x1;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	/* tx intr map arm->pru */
+	u32offset = (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
+	u32value = 0x0;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_HOSTMAP0 & 0xFFFF);
+	u32value = 0x03020100;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_HOSTMAP1 & 0xFFFF);
+	u32value = 0x07060504;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_HOSTMAP2 & 0xFFFF);
+	u32value = 0x0000908;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_CHANMAP0 & 0xFFFF);
+	u32value = 0;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_CHANMAP8 & 0xFFFF);
+	u32value = 0x00020200;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+	u32value = 32;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+	u32value = 19;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 19;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+	u32value = 18;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 18;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+	u32value = 34;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 34;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 32;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRUSS_INTC_HOSTINTEN & 0xFFFF);
+	u32value = 0x5;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+/* PRU0 - Rx Internal Registers Initializations */
+
+	u32offset = (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000040;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_INTERRUPT_MASK_REGISTER & 0xFFFF);
+	u32value = 0x00004000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x0000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_ERROR_COUNTER_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_TIMING_REGISTER & 0xFFFF);
+	u32value = 0x0000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+
+	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER & 0xFFFF);
+	u32value = 0x00000000;
+	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	return 0;
+}
+
+
+/*
+ * pru_can_emu_open()		Opens the can emu for
+ * application to use. This API will be called by the Application
+ * to Open the can emu for application to use.
+ *
+ * param	pstremuapphndl	Pointer to application handler
+ * structure
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_emu_open(struct device *dev, can_emu_app_hndl *pstremuapphndl)
+{
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+
+	if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 1) {
+		return -1;
+	}
+
+	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].
+					bcaninststate = (bool)1;
+	gstr_can_inst[(u8) pstremuapphndl->
+		ecaninstance].ecantransferdirection =
+		(can_transfer_direction)(u8)pstremuapphndl->ecantransferdirection;
+	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].
+		u32apphandlerptr = (u32) pstremuapphndl;
+
+	return 0;
+}
+
+
+/*
+ * brief    pru_can_emu_close()	Closes the can emu for other
+ * applications to use. This API will be called by the Application to Close
+ * the can emu for other applications to use
+ *
+ * param	pstremuapphndl	Pointer to application handler structure
+ *
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_emu_close(struct device *dev, can_emu_app_hndl *pstremuapphndl)
+{
+
+	if (pstremuapphndl == NULL) {
+		return -1;
+	}
+	if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 0) {
+		return -1;
+	}
+	if ((u32) pstremuapphndl != gstr_can_inst[(u8) pstremuapphndl->
+			ecaninstance].u32apphandlerptr){
+		return -1;
+	}
+	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].bcaninststate
+		= (bool) 0;
+	gstr_can_inst[(u8) pstremuapphndl->
+	ecaninstance].ecantransferdirection = (can_transfer_direction) 0;
+	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].u32apphandlerptr = 0;
+
+	return 0;
+}
+
+/*
+ * brief    pru_can_emu_exit()	Diables all the PRUs
+ * This API will be called by the Application to disable all PRUs
+ * param	None
+ * return   SUCCESS or FAILURE
+ */
+s16 pru_can_emu_exit(struct device *dev)
+{
+	s16 s16subrtnretval;
+
+	s16subrtnretval = pruss_disable(dev, CAN_RX_PRU_0);
+	if (s16subrtnretval == -1)
+		return -1;
+	s16subrtnretval = pruss_disable(dev, CAN_TX_PRU_1);
+	if (s16subrtnretval == -1)
+		return -1;
+
+	return 0;
+}
+
+s16 pru_can_emu_sreset(struct device *dev)
+{
+	return 0;
+}
+
+s16 pru_can_tx(struct device *dev, u8 u8mailboxnumber, u8 u8prunumber)
+{
+	u32 u32offset = 0;
+	u32 u32value = 0;
+	s16 s16subrtnretval = -1;
+
+	if (DA8XX_PRUCORE_1 == u8prunumber) {
+		switch (u8mailboxnumber) {
+		case 0:
+			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+					(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 1:
+			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 2:
+			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 3:
+			u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 4:
+			u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 5:
+			u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 6:
+			u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 7:
+			u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000080;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		default:
+			return -1;
+		}
+	} else {
+
+		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
+		u32value = 0x00000000;
+		s16subrtnretval = pruss_readl(dev, u32offset,
+						(u32 *) &u32value, 1);
+		if (s16subrtnretval == -1) {
+			return -1;
+		}
+		u32value = u32value & ~(1 << u8mailboxnumber);
+		s16subrtnretval = pruss_writel(dev, u32offset,
+					(u32 *) &u32value, 1);
+		if (s16subrtnretval == -1) {
+			return -1;
+		}
+
+		switch (u8mailboxnumber) {
+		case 0:
+			u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 1:
+			u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 2:
+			u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 3:
+			u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 4:
+			u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 5:
+			u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 6:
+			u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		case 7:
+			u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
+			u32value = 0x00000000;
+			s16subrtnretval = pruss_writel(dev, u32offset,
+						(u32 *) &u32value, 1);
+			if (s16subrtnretval == -1) {
+				return -1;
+			}
+			break;
+		default:
+			return -1;
+		}
+	}
+	return 0;
+}
+
+s16 pru_can_start_abort_tx(struct device *dev, bool bcantransmitabortflag)
+{
+	u32 u32offset;
+	u32 u32value;
+	s16 s16subrtnretval;
+	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+	u32value = 32;
+	s16subrtnretval = pruss_writel(dev, u32offset,
+					(u32 *) &u32value, 1);
+
+	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 32;
+	s16subrtnretval = pruss_writel(dev, u32offset,
+					(u32 *) &u32value, 1);
+
+	u32offset = (PRUSS_INTC_STATIDXSET & 0xFFFF);
+	u32value = 32;
+	s16subrtnretval = pruss_writel(dev, u32offset,
+					(u32 *) &u32value, 1);
+	if (s16subrtnretval == -1) {
+		return -1;
+	}
+	return 0;
+}
+
+s16 pru_can_mask_ints(struct device *dev, u32 int_mask)
+{
+	return 0;
+}
+
+int pru_can_get_error_cnt(struct device *dev, u8 u8prunumber)
+{
+	return 0;
+}
+
+int pru_can_get_intc_status(struct device *dev)
+{
+	u32 u32offset = 0;
+	u32 u32getvalue = 0;
+	u32 u32clrvalue = 0;
+
+	u32offset = (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+	pruss_readl(dev, u32offset, (u32 *) &u32getvalue, 1);
+
+	if (u32getvalue & 4)
+		u32clrvalue = 34;	/* CLR Event 34 */
+
+	if (u32getvalue & 2)
+		u32clrvalue = 33;	/* CLR Event 33  */
+
+	if (u32clrvalue) {
+		u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+		pruss_writel(dev, u32offset, &u32clrvalue, 1);
+	} else
+		return -1;
+
+	return u32getvalue;
+}
diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.h b/drivers/net/can/da8xx_pruss/pruss_can_api.h
new file mode 100644
index 0000000..7550456
--- /dev/null
+++ b/drivers/net/can/da8xx_pruss/pruss_can_api.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Ganeshan N
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as  published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _PRU_CAN_API_H_
+#define _PRU_CAN_API_H_
+
+#include <linux/types.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+
+
+#define CAN_BIT_TIMINGS			(0x273)
+
+/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */
+#define	TIMER_CLK_FREQ			132000000
+
+#define TIMER_SETUP_DELAY		14
+#define GPIO_SETUP_DELAY		150
+
+#define CAN_RX_PRU_0			PRUSS_NUM0
+#define CAN_TX_PRU_1			PRUSS_NUM1
+
+/* Number of Instruction in the Delay loop */
+#define DELAY_LOOP_LENGTH		2
+
+#define PRU1_BASE_ADDR			0x2000
+
+#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER		(PRU1_BASE_ADDR)
+#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x04)
+#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER		(PRU1_BASE_ADDR	+ 0x08)
+#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x0C)
+#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x10)
+#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x14)
+#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x18)
+#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x1C)
+#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x20)
+#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x24)
+#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x28)
+#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x2C)
+#define PRU_CAN_TX_ERROR_COUNTER_REGISTER		(PRU1_BASE_ADDR	+ 0x30)
+#define PRU_CAN_TX_TIMING_REGISTER			(PRU1_BASE_ADDR	+ 0x34)
+#define PRU_CAN_TX_CLOCK_BRP_REGISTER			(PRU1_BASE_ADDR	+ 0x38)
+
+#define PRU_CAN_TX_MAILBOX0				(PRU1_BASE_ADDR	+ 0x40)
+#define PRU_CAN_TX_MAILBOX1				(PRU1_BASE_ADDR	+ 0x50)
+#define PRU_CAN_TX_MAILBOX2				(PRU1_BASE_ADDR	+ 0x60)
+#define PRU_CAN_TX_MAILBOX3				(PRU1_BASE_ADDR	+ 0x70)
+#define PRU_CAN_TX_MAILBOX4				(PRU1_BASE_ADDR	+ 0x80)
+#define PRU_CAN_TX_MAILBOX5				(PRU1_BASE_ADDR	+ 0x90)
+#define PRU_CAN_TX_MAILBOX6				(PRU1_BASE_ADDR	+ 0xA0)
+#define PRU_CAN_TX_MAILBOX7				(PRU1_BASE_ADDR	+ 0xB0)
+
+#define PRU_CAN_TIMING_VAL_TX				(PRU1_BASE_ADDR	+ 0xC0)
+#define PRU_CAN_TIMING_VAL_TX_SJW			(PRU1_BASE_ADDR	+ 0xC4)
+#define PRU_CAN_TRANSMIT_FRAME				(PRU1_BASE_ADDR	+ 0xE0)
+
+#define PRU0_BASE_ADDR					0
+
+#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER		(PRU0_BASE_ADDR)
+#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x04)
+#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER		(PRU0_BASE_ADDR	+ 0x08)
+#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x0C)
+#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x10)
+#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x14)
+#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x18)
+#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x1C)
+#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x20)
+#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x24)
+#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x28)
+#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x2C)
+#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x30)
+#define PRU_CAN_RX_ERROR_COUNTER_REGISTER		(PRU0_BASE_ADDR	+ 0x34)
+#define PRU_CAN_RX_TIMING_REGISTER			(PRU0_BASE_ADDR	+ 0x38)
+#define PRU_CAN_RX_CLOCK_BRP_REGISTER			(PRU0_BASE_ADDR	+ 0x3C)
+
+#define PRU_CAN_RX_MAILBOX0				(PRU0_BASE_ADDR	+ 0x40)
+#define PRU_CAN_RX_MAILBOX1				(PRU0_BASE_ADDR	+ 0x50)
+#define PRU_CAN_RX_MAILBOX2				(PRU0_BASE_ADDR	+ 0x60)
+#define PRU_CAN_RX_MAILBOX3				(PRU0_BASE_ADDR	+ 0x70)
+#define PRU_CAN_RX_MAILBOX4				(PRU0_BASE_ADDR	+ 0x80)
+#define PRU_CAN_RX_MAILBOX5				(PRU0_BASE_ADDR	+ 0x90)
+#define PRU_CAN_RX_MAILBOX6				(PRU0_BASE_ADDR	+ 0xA0)
+#define PRU_CAN_RX_MAILBOX7				(PRU0_BASE_ADDR	+ 0xB0)
+#define PRU_CAN_RX_MAILBOX8				(PRU0_BASE_ADDR	+ 0xC0)
+
+#define PRU_CAN_TIMING_VAL_RX				(PRU0_BASE_ADDR	+ 0xD0)
+#define PRU_CAN_RECEIVE_FRAME				(PRU0_BASE_ADDR	+ 0xD4)
+#define PRU_CAN_ID_MAP					(PRU0_BASE_ADDR	+ 0xF0)
+
+#define PRU_CAN_ERROR_ACTIVE				128
+
+#define CAN_ACK_FAILED					0xE
+#define CAN_ARBTR_FAIL					0xD
+#define CAN_BIT_ERROR					0xC
+#define CAN_TRANSMISSION_SUCCESS			0xA
+
+#define STD_DATA_FRAME					0x1
+#define EXTD_DATA_FRAME					0x2
+#define STD_REMOTE_FRAME				0x3
+#define EXTD_REMOTE_FRAME				0x4
+
+#define PRU_CAN_MAX_SJW					8
+#define PRU_CAN_MAX_PHSEG1				25
+#define PRU_CAN_MAX_PHSEG2				25
+
+#define DA8XX_PRUCANCORE_0_REGS				0x7000
+#define DA8XX_PRUCANCORE_1_REGS				0x7800
+#define PRU0_PROG_RAM_START_OFFSET			0x8000
+#define PRU1_PROG_RAM_START_OFFSET			0xC000
+#define PRU_CAN_INIT_MAX_TIMEOUT			0xFF
+
+typedef enum {
+	ecaninst0 = 0,
+	ecaninst1,
+	ecanmaxinst
+} can_instance_enum;
+
+typedef enum {
+	ecanmailbox0 = 0,
+	ecanmailbox1,
+	ecanmailbox2,
+	ecanmailbox3,
+	ecanmailbox4,
+	ecanmailbox5,
+	ecanmailbox6,
+	ecanmailbox7
+} can_mailbox_number;
+
+typedef enum {
+	ecandirectioninit = 0,
+	ecantransmit,
+	ecanreceive
+} can_transfer_direction;
+
+typedef struct {
+	u16 u16extendedidentifier;
+	u16 u16baseidentifier;
+	u8 u8data7;
+	u8 u8data6;
+	u8 u8data5;
+	u8 u8data4;
+	u8 u8data3;
+	u8 u8data2;
+	u8 u8data1;
+	u8 u8data0;
+	u16 u16datalength;
+	u16 u16crc;
+} can_mail_box_structure;
+
+typedef struct {
+	can_transfer_direction ecantransferdirection;
+} can_mailbox_config;
+
+typedef struct {
+	can_instance_enum ecaninstance;
+	can_transfer_direction ecantransferdirection;
+	can_mail_box_structure strcanmailbox;
+	can_mailbox_number ecanmailboxnumber;
+	u8 u8prunumber;
+	u32 u32globalstatus;
+	u32 u32interruptstatus;
+	u32 u32mailboxstatus;
+} can_emu_app_hndl;
+
+typedef struct {
+	bool bcaninststate;
+	can_transfer_direction ecantransferdirection;
+	u32 u32apphandlerptr;
+} can_emu_drv_inst;
+
+typedef struct {
+	u8 u8syncjumpwidth;
+	u8 u8phseg1;
+	u8 u8phseg2;
+} can_bit_timing_consts;
+
+/* Field Definition Macros  */
+
+/* CONTROL */
+
+/*
+ * pru_can_set_brp() Updates the  BRP register of PRU.
+ */
+s16 pru_can_set_brp(struct device *dev, u16 u16prescaler);
+
+/*
+ * pru_can_set_bit_timing() Updates the  timing register of PRU
+ */
+s16 pru_can_set_bit_timing(struct device *dev,
+			can_bit_timing_consts *pstrbittiming);
+
+/*
+ * pru_can_calc_timing() Updates the timing values of PRU
+ */
+s16 pru_can_calc_timing(struct device *dev,
+			u32 u32bittiming, u32 u32bitrateprescaler);
+
+/*
+ * pru_can_write_data_to_mailbox() Updates the transmit mailboxes of PRU1
+ */
+s16 pru_can_write_data_to_mailbox(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+/*
+ * pru_can_get_data_from_mailbox() Receive data from receive mailboxes
+ */
+s16 pru_can_get_data_from_mailbox(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+/*
+ * pru_can_rx_id_map() Receive mailboxes ID Mapping of PRU0
+ */
+s16 pru_can_rx_id_map(struct device *dev,
+			u32 u32nodeid, can_mailbox_number ecanmailboxno);
+
+/*
+ *pru_can_get_intr_status() Get interrupts status register value
+ */
+s16 pru_can_get_intr_status(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+
+/*
+ * pru_can_get_global_status() Get the globalstatus register value
+ */
+s16 pru_can_get_global_status(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+/*
+ * pru_can_get_mailbox_status() Get mailbox status reg value
+ */
+s16 pru_can_get_mailbox_status(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+/*
+ * pru_can_configuration_mode_set() Sets timing val for data transfer
+ */
+s16 pru_can_config_mode_set(struct device *dev,
+			bool bconfig_modeflag);
+
+/*
+ * pru_can_emu_init() Initializes Can Emulation Parameters
+ */
+s16 pru_can_emu_init(struct device *dev,
+			u32 u32pruclock);
+
+/*
+ * pru_can_emu_open() Opens can emu for application to use
+ */
+s16 pru_can_emu_open(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+/*
+ * pru_can_emu_close() Closes can emu for applications to use
+ */
+s16 pru_can_emu_close(struct device *dev,
+			can_emu_app_hndl *pstremuapphndl);
+
+/*
+ * pru_can_emu_exit() Diables all the PRUs
+ */
+s16 pru_can_emu_exit(struct device *dev);
+
+s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag,
+			 can_transfer_direction ecan_trx);
+
+s16 pru_can_emu_sreset(struct device *dev);
+
+s16 pru_can_tx(struct device *dev,
+			u8 u8mailboxnumber, u8 u8prunumber);
+
+s16 pru_can_start_abort_tx(struct device *dev,
+			bool btxabort_flag);
+
+s16 pru_can_mask_ints(struct device *dev, u32 int_mask);
+
+s32 pru_can_get_error_cnt(struct device *dev, u8 u8prunumber);
+
+s32 pru_can_get_intc_status(struct device *dev);
+#endif
-- 
1.7.2.3


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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
@ 2011-02-11 15:06     ` Kurt Van Dijck
  2011-02-14  4:54       ` Subhasish Ghosh
  2011-02-11 15:20     ` Kurt Van Dijck
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 21+ messages in thread
From: Kurt Van Dijck @ 2011-02-11 15:06 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	open list:CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	open list:CAN NETWORK DRIVERS,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	m-watkins-l0cyMroinI0, Wolfgang Grandegger

On Fri, Feb 11, 2011 at 08:21:28PM +0530, Subhasish Ghosh wrote:
> +config DA8XX_PRU_CANID_MBX0
> +	hex "CANID for mailbox 0"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 0
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX1
> +	hex "CANID for mailbox 1"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	 ---help---
> +	Enter the CANID for mailbox 1
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX2
> +	hex "CANID for mailbox 2"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 2
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX3
> +	hex "CANID for mailbox 3"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 3
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX4
> +	hex "CANID for mailbox 4"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 4
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX5
> +	hex "CANID for mailbox 5"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 5
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX6
> +	hex "CANID for mailbox 6"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 6
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX7
> +	hex "CANID for mailbox 7"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 7
> +	Default value is set to 0x123, change this as required.
Why is filling the mailboxes the job of kernel config?

Regards,
Kurt

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
  2011-02-11 15:06     ` Kurt Van Dijck
@ 2011-02-11 15:20     ` Kurt Van Dijck
       [not found]       ` <20110211152026.GC373-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
  2011-02-11 20:33     ` Wolfgang Grandegger
  2011-02-11 21:33     ` Marc Kleine-Budde
  3 siblings, 1 reply; 21+ messages in thread
From: Kurt Van Dijck @ 2011-02-11 15:20 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	open list:CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	open list:CAN NETWORK DRIVERS,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	m-watkins-l0cyMroinI0, Wolfgang Grandegger

Hi,

I looked a bit at the TX path:

On Fri, Feb 11, 2011 at 08:21:28PM +0530, Subhasish Ghosh wrote:
> +static int omapl_pru_can_set_bittiming(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct can_bittiming *bt = &priv->can.bittiming;
> +	long bit_error = 0;
> +
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) {
> +		dev_warn(priv->dev, "WARN: Triple"
> +			 "sampling not set due to h/w limitations");
You should not have enabled CAN_CTRLMODE_3_SAMPLES in the first place?
> +	}
> +	if (pru_can_calc_timing(priv->dev, priv->can.clock.freq,
> +				bt->bitrate) != 0)
> +		return -EINVAL;
> +	bit_error =
> +	    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
> +	      bt->bitrate) * 1000) / bt->bitrate;
> +	if (bit_error) {
> +		bit_error =
> +		    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
> +		      bt->bitrate) * 1000000) / bt->bitrate;
> +		printk(KERN_INFO "\nBitrate error %ld.%ld%%\n",
> +			bit_error / 10000, bit_error % 1000);
> +	} else
> +		printk(KERN_INFO "\nBitrate error 0.0%%\n");
> +
> +	return 0;
> +}
I wonder how much of this code is duplicated from drivers/net/can/dev.c ?

> +static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb,
> +					    struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct can_frame *cf = (struct can_frame *)skb->data;
> +	int count;
> +	u8 *data = cf->data;
> +	u8 dlc = cf->can_dlc;
> +	u8 *ptr8data = NULL;
> +
most drivers start with:
	if (can_dropped_invalid_skb(dev, skb))
		return NETDEV_TX_OK;

> +	netif_stop_queue(ndev);
why would you stop when you just resumed the queue?
> +	if (cf->can_id & CAN_EFF_FLAG)	/* Extended frame format */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
> +		    (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE;
> +	else			/* Standard frame format */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
> +		    (cf->can_id & CAN_SFF_MASK) << 18;
> +
> +	if (cf->can_id & CAN_RTR_FLAG)	/* Remote transmission request */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG;
> +
> +	ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1);
> +	for (count = 0; count < (u8) dlc; count++) {
> +		*ptr8data-- = *data++;
> +	}
> +	*((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc;
> +/*
> + * search for the next available mbx
> + * if the next mbx is busy, then try the next + 1
> + * do this until the head is reached.
> + * if still unable to tx, stop accepting any packets
> + * if able to tx and the head is reached, then reset next to tail, i.e mbx0
> + * if head is not reached, then just point to the next mbx
> + */
> +	for (; priv->tx_next <= priv->tx_head; priv->tx_next++) {
> +		priv->can_tx_hndl.ecanmailboxnumber =
> +		    (can_mailbox_number) priv->tx_next;
> +		if (-1 == pru_can_write_data_to_mailbox(priv->dev,
> +					&priv->can_tx_hndl)) {
> +			if (priv->tx_next == priv->tx_head) {
> +				priv->tx_next = priv->tx_tail;
> +				if (!netif_queue_stopped(ndev))
If you get here, the queue is not stopped. This test is therefore useless.
> +					netif_stop_queue(ndev);	/* IF stalled */
> +				dev_err(priv->dev,
> +					"%s: no tx mbx available", __func__);
> +				return NETDEV_TX_BUSY;
> +			} else
> +				continue;
> +		} else {
> +			/* set transmit request */
> +			pru_can_tx(priv->dev, priv->tx_next, CAN_TX_PRU_1);
> +			pru_can_tx_mode_set(priv->dev, false, ecanreceive);
> +			pru_can_tx_mode_set(priv->dev, true, ecantransmit);
> +			pru_can_start_abort_tx(priv->dev, PRU_CAN_START);
> +			priv->tx_next++;
> +			can_put_echo_skb(skb, ndev, 0);
> +			break;
> +		}
> +	}
> +	if (priv->tx_next > priv->tx_head) {
> +		priv->tx_next = priv->tx_tail;
> +	}
> +	return NETDEV_TX_OK;
> +}
> +
> +

> +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id)
> +{
> +	struct net_device *ndev = dev_id;
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct net_device_stats *stats = &ndev->stats;
> +	u32 bit_set, mbxno;
> +
> +	pru_can_get_intr_status(priv->dev, &priv->can_tx_hndl);
> +	if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus)
> +	    || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) {
> +		__can_debug("tx_int_status = 0x%X\n",
> +			    priv->can_tx_hndl.u32interruptstatus);
> +		can_free_echo_skb(ndev, 0);
> +	} else {
> +		for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF)
> +						>> bit_set != 0); bit_set++)
> +		;
> +		if (0 == bit_set) {
> +			__can_err("%s: invalid mailbox number\n", __func__);
> +			can_free_echo_skb(ndev, 0);
> +		} else {
> +			mbxno = bit_set - 1;	/* mail box numbering starts from 0 */
> +			if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl.
> +			    u32interruptstatus) {
> +				/* read gsr and ack pru */
> +				pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
> +				omapl_pru_can_err(ndev,
> +						  priv->can_tx_hndl.
> +						  u32interruptstatus,
> +						  priv->can_tx_hndl.
> +						  u32globalstatus);
> +			} else {
> +				stats->tx_packets++;
> +				/* stats->tx_bytes += dlc; */
> +				/*can_get_echo_skb(ndev, 0);*/
> +			}
> +		}
> +	}
> +	if (netif_queue_stopped(ndev))
you can call netif_wake_queue(ndev) multiple times, so there is no need
for netif_queue_stopped()
> +		netif_wake_queue(ndev);
> +
> +	can_get_echo_skb(ndev, 0);
> +	pru_can_tx_mode_set(priv->dev, true, ecanreceive);
> +	return IRQ_HANDLED;
> +}
> +
> +static int omapl_pru_can_open(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	int err;
> +
> +	/* register interrupt handler */
> +	err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
> +			  "pru_can_irq", ndev);
you're doing a lot of work _in_ the irq handler. Maybe threaded irq?

> +static int omapl_pru_can_close(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +
> +	if (!netif_queue_stopped(ndev))
check is not needed.
> +		netif_stop_queue(ndev);
> +
> +	close_candev(ndev);
> +
> +	free_irq(priv->trx_irq, ndev);
> +	return 0;
> +}
> +

Regards,
Kurt

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
  2011-02-11 15:06     ` Kurt Van Dijck
  2011-02-11 15:20     ` Kurt Van Dijck
@ 2011-02-11 20:33     ` Wolfgang Grandegger
  2011-02-11 21:33     ` Marc Kleine-Budde
  3 siblings, 0 replies; 21+ messages in thread
From: Wolfgang Grandegger @ 2011-02-11 20:33 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hello,

thanks for your contribution.

First some general comments:

- Please send a separate patch for the Socket-CAN driver.
  Or are there good reasons why we should look at the other 12 patches?

- Please run checkpatch.pl and fix the reported warnings. There are
  many.

- You are using casts extensively. Please get rid of them.

- Decoding the variable type into the name is *deprecated* in Linux.

- Also very long names are *deprecated* in Linux.

- Don't use typedef's.

Some more comments inline...

On 02/11/2011 03:51 PM, Subhasish Ghosh wrote:
> This patch adds support for the CAN device emulated on PRUSS.
> 
> Signed-off-by: Subhasish Ghosh <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
> ---
>  drivers/net/can/Kconfig                     |    1 +
>  drivers/net/can/Makefile                    |    1 +
>  drivers/net/can/da8xx_pruss/Kconfig         |   73 ++
>  drivers/net/can/da8xx_pruss/Makefile        |    7 +
>  drivers/net/can/da8xx_pruss/pruss_can.c     |  758 +++++++++++++++++
>  drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++
>  drivers/net/can/da8xx_pruss/pruss_can_api.h |  290 +++++++
>  7 files changed, 2357 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/da8xx_pruss/Kconfig
>  create mode 100644 drivers/net/can/da8xx_pruss/Makefile
>  create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c
>  create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c
>  create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h

Why not s/da8xx_pruss/pruss_can/ ?

> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index d5a9db6..ae8f0f9 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -112,6 +112,7 @@ config PCH_CAN
>  	  This driver can access CAN bus.
>  
>  source "drivers/net/can/mscan/Kconfig"
> +source "drivers/net/can/da8xx_pruss/Kconfig"
>  
>  source "drivers/net/can/sja1000/Kconfig"
>  
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 07ca159..849cdbf 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
>  obj-$(CONFIG_CAN_MSCAN)		+= mscan/
>  obj-$(CONFIG_CAN_AT91)		+= at91_can.o
>  obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
> +obj-$(CONFIG_CAN_TI_DA8XX_PRU)	+= da8xx_pruss/

Please use a common name/prefix, e.g. pruss_can.

>  obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
>  obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
>  obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
> diff --git a/drivers/net/can/da8xx_pruss/Kconfig b/drivers/net/can/da8xx_pruss/Kconfig
> new file mode 100644
> index 0000000..8b68f68
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/Kconfig
> @@ -0,0 +1,73 @@
> +#
> +# CAN Lite Kernel Configuration
> +#
> +config CAN_TI_DA8XX_PRU
> +	depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850
> +	tristate "PRU based CAN emulation for DA8XX"
> +	---help---
> +	Enable this to emulate a CAN controller on the PRU of DA8XX.
> +	If not sure, mark N
> +
> +config DA8XX_PRU_CANID_MBX0
> +	hex "CANID for mailbox 0"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 0
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX1
> +	hex "CANID for mailbox 1"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	 ---help---
> +	Enter the CANID for mailbox 1
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX2
> +	hex "CANID for mailbox 2"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 2
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX3
> +	hex "CANID for mailbox 3"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 3
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX4
> +	hex "CANID for mailbox 4"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 4
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX5
> +	hex "CANID for mailbox 5"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 5
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX6
> +	hex "CANID for mailbox 6"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 6
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX7
> +	hex "CANID for mailbox 7"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 7
> +	Default value is set to 0x123, change this as required.

Well, defining CAN identifiers via Kconfig entries is really wired.
Could you please explain why that's necessary and what's so special with
that CAN hardware. We need a better solution if the CAN controller
cannot handle and CAN id.

> diff --git a/drivers/net/can/da8xx_pruss/Makefile b/drivers/net/can/da8xx_pruss/Makefile
> new file mode 100644
> index 0000000..48f3055
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for CAN Lite emulation
> +#
> +can_emu-objs :=   pruss_can.o \
> +                  pruss_can_api.o
> +
> +obj-$(CONFIG_CAN_TI_DA8XX_PRU)    += can_emu.o

Again another name.

> diff --git a/drivers/net/can/da8xx_pruss/pruss_can.c b/drivers/net/can/da8xx_pruss/pruss_can.c
> new file mode 100644
> index 0000000..1b3afde
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can.c
> @@ -0,0 +1,758 @@
> +/*
> + *  TI DA8XX PRU CAN Emulation device driver
> + *  Author: subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org
> + *
> + *  This driver supports TI's PRU CAN Emulation and the
> + *  specs for the same is available at <http://www.ti.com>
> + *
> + *  Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License as
> + *  published by the Free Software Foundation version 2.
> + *
> + *  This program is distributed as is WITHOUT ANY WARRANTY of any
> + *  kind, whether express or implied; without even the implied warranty
> + *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/netdevice.h>
> +#include <linux/skbuff.h>
> +#include <linux/platform_device.h>
> +#include <linux/firmware.h>
> +#include <linux/clk.h>
> +#include <linux/types.h>
> +
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +#include <mach/da8xx.h>
> +#include "pruss_can_api.h"
> +
> +#define DRV_NAME "da8xx_pruss_can"
> +#define DRV_DESC "TI PRU CAN Controller Driver v0.1"
> +#define PRU_CAN_START		1
> +#define PRU_CAN_STOP		0
> +#define MB_MIN			0
> +#define MB_MAX			7
> +
> +#define PRU_CANMID_IDE			BIT(29)	/* Extended frame format */
> +
> +#define PRU_CAN_ISR_BIT_CCI		BIT(15)
> +#define PRU_CAN_ISR_BIT_ESI		BIT(14)
> +#define PRU_CAN_ISR_BIT_SRDI		BIT(13)
> +#define PRU_CAN_ISR_BIT_RRI		BIT(8)
> +
> +#define PRU_CAN_MBXSR_BIT_STATE		BIT(7)
> +#define PRU_CAN_MBXSR_BIT_TC		BIT(6)
> +#define PRU_CAN_MBXSR_BIT_ERR		BIT(5)
> +#define PRU_CAN_MBXSR_BIT_OF		BIT(0)
> +
> +#define PRU_CAN_GSR_BIT_TXM		BIT(7)
> +#define PRU_CAN_GSR_BIT_RXM		BIT(6)
> +#define PRU_CAN_GSR_BIT_CM		BIT(5)
> +#define PRU_CAN_GSR_BIT_EPM		BIT(4)
> +#define PRU_CAN_GSR_BIT_BFM		BIT(3)
> +#define RTR_MBX_NO			8
> +#define MAX_INIT_RETRIES		20
> +#define L138_PRU_ARM_FREQ		312000
> +#define DFLT_PRU_FREQ			156000000
> +#define DFLT_PRU_BITRATE		125000
> +
> +#define CONFIG_DA8XX_PRU_CANID_MBX0	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX1	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX2	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX3	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX4	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX5	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX6	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX7	0x123
> +
> +#ifdef __CAN_DEBUG
> +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args)
> +#else
> +#define __can_debug(fmt, args...)
> +#endif
> +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)

Please use dev_dbg, dev_err, ... or netif_dbg, netdev_err, ... instead.

> +/*
> + * omapl_pru can private data
> + */
> +struct omapl_pru_can_priv {
> +	struct can_priv can;
> +	struct workqueue_struct *pru_can_wQ;
> +	struct work_struct rx_work;
> +	struct net_device *ndev;
> +	struct device *dev; /* pdev->dev */
> +	struct clk *clk_timer;
> +	u32 timer_freq;
> +	can_emu_app_hndl can_tx_hndl;
> +	can_emu_app_hndl can_rx_hndl;
> +	const struct firmware *fw_rx;
> +	const struct firmware *fw_tx;
> +	spinlock_t mbox_lock;
> +	u32 trx_irq;
> +	u32 tx_head;
> +	u32 tx_tail;
> +	u32 tx_next;
> +	u32 rx_next;
> +};
> +
> +static int omapl_pru_can_get_state(const struct net_device *ndev,
> +				   enum can_state *state)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	*state = priv->can.state;
> +	return 0;
> +}


There is no need for that function as you handle state changes in the
interrupt context.

> +static int omapl_pru_can_set_bittiming(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct can_bittiming *bt = &priv->can.bittiming;
> +	long bit_error = 0;
> +
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) {
> +		dev_warn(priv->dev, "WARN: Triple"
> +			 "sampling not set due to h/w limitations");
> +	}

No need for this test as you have not set the CAN_CTRLMODE_3_SAMPLES bit
in priv.ctrlmode_supported.

> +	if (pru_can_calc_timing(priv->dev, priv->can.clock.freq,
> +				bt->bitrate) != 0)
> +		return -EINVAL;
> +	bit_error =
> +	    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
> +	      bt->bitrate) * 1000) / bt->bitrate;
> +	if (bit_error) {
> +		bit_error =
> +		    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
> +		      bt->bitrate) * 1000000) / bt->bitrate;
> +		printk(KERN_INFO "\nBitrate error %ld.%ld%%\n",
> +			bit_error / 10000, bit_error % 1000);
> +	} else
> +		printk(KERN_INFO "\nBitrate error 0.0%%\n");
> +
> +	return 0;

Please use the pre-calculated bit-timing parameters. Have a look to the
SJA1000 driver for further information:

http://lxr.linux.no/#linux+v2.6.37/drivers/net/can/sja1000/sja1000.c#L202

In general, please use the bit-timing interface of Socket-CAN and drop
you own.

> +}
> +
> +static void omapl_pru_can_stop(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	u16 int_mask = 0;
> +
> +	pru_can_mask_ints(priv->dev, int_mask);	/* mask all ints */
> +	pru_can_start_abort_tx(priv->dev, PRU_CAN_STOP);
> +	priv->can.state = CAN_STATE_STOPPED;
> +}
> +
> +/*
> + * This is to just set the can state to ERROR_ACTIVE
> + *	ip link set canX up type can bitrate 125000
> + */
> +static void omapl_pru_can_start(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	u16 int_mask = 0xFFFF;
> +
> +	if (priv->can.state != CAN_STATE_STOPPED)
> +		omapl_pru_can_stop(ndev);
> +
> +	pru_can_mask_ints(priv->dev, int_mask);	/* unmask all ints */
> +
> +	pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
> +	pru_can_get_global_status(priv->dev, &priv->can_rx_hndl);
> +
> +	if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus)

Decoding the variable type into the name is deprecated in Linux.

> +		priv->can.state = CAN_STATE_ERROR_PASSIVE;
> +	else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus)
> +		priv->can.state = CAN_STATE_BUS_OFF;
> +	else
> +		priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +}
> +
> +static int omapl_pru_can_set_mode(struct net_device *ndev, enum can_mode mode)
> +{
> +	int ret = 0;
> +
> +	switch (mode) {
> +	case CAN_MODE_START:
> +		omapl_pru_can_start(ndev);
> +		if (netif_queue_stopped(ndev))
> +			netif_wake_queue(ndev);
> +		break;
> +	case CAN_MODE_STOP:
> +		omapl_pru_can_stop(ndev);
> +		if (!netif_queue_stopped(ndev))
> +			netif_stop_queue(ndev);
> +		break;

This case is not supported.

> +	default:
> +		ret = -EOPNOTSUPP;
> +		break;
> +	}
> +	return ret;
> +}
> +
> +static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb,
> +					    struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct can_frame *cf = (struct can_frame *)skb->data;
> +	int count;
> +	u8 *data = cf->data;
> +	u8 dlc = cf->can_dlc;
> +	u8 *ptr8data = NULL;
> +
> +	netif_stop_queue(ndev);
> +	if (cf->can_id & CAN_EFF_FLAG)	/* Extended frame format */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
> +		    (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE;



> +	else			/* Standard frame format */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
> +		    (cf->can_id & CAN_SFF_MASK) << 18;

You use many of such wired expressions. strcanmailbox is a struct

  typedef struct {
	u16 u16extendedidentifier;
	u16 u16baseidentifier;
        ...
  } can_mail_box_structure;

and you obviously set the fist two fields. In contrast, the member
u16extendedidentifier is never directly used. Puh, that's magic. Please
make your code more transparent and readable.

> +	if (cf->can_id & CAN_RTR_FLAG)	/* Remote transmission request */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG;
> +
> +	ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1);
> +	for (count = 0; count < (u8) dlc; count++) {
> +		*ptr8data-- = *data++;
> +	}
> +	*((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc;

...

> +irqreturn_t omapl_rx_can_intr(int irq, void *dev_id)
> +{
> +
> +	struct net_device *ndev = dev_id;
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	u32 intc_status = 0;
> +
> +	intc_status = pru_can_get_intc_status(priv->dev);
> +	if (intc_status & 4)
> +		return omapl_tx_can_intr(irq, dev_id);
> +	if (intc_status & 2) {
> +		if (!work_pending(&priv->rx_work))
> +			queue_work(priv->pru_can_wQ, &priv->rx_work);

You handle RX in a work queue!? Please use NAPI instead.

> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int omapl_pru_can_open(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	int err;
> +
> +	/* register interrupt handler */
> +	err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
> +			  "pru_can_irq", ndev);
> +	if (err) {
> +		dev_err(priv->dev, "error requesting rx interrupt\n");
> +		goto exit_trx_irq;
> +	}
> +	/* common open */
> +	err = open_candev(ndev);
> +	if (err) {
> +		dev_err(priv->dev, "open_candev() failed %d\n", err);
> +		goto exit_open;
> +	}
> +
> +	pru_can_emu_init(priv->dev, priv->can.clock.freq);
> +	priv->tx_tail = MB_MIN;
> +	priv->tx_head = MB_MAX;
> +
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX0, 0);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX1, 1);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX2, 2);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX3, 3);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX4, 4);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX5, 5);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX6, 6);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX7, 7);
> +
> +	omapl_pru_can_start(ndev);
> +	netif_start_queue(ndev);
> +	return 0;
> +
> +exit_open:
> +	free_irq(priv->trx_irq, ndev);
> +exit_trx_irq:
> +	return err;
> +}
> +
> +static int omapl_pru_can_close(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +
> +	if (!netif_queue_stopped(ndev))
> +		netif_stop_queue(ndev);
> +
> +	close_candev(ndev);
> +
> +	free_irq(priv->trx_irq, ndev);
> +	return 0;
> +}
> +
> +static const struct net_device_ops omapl_pru_can_netdev_ops = {
> +	.ndo_open		= omapl_pru_can_open,
> +	.ndo_stop		= omapl_pru_can_close,
> +	.ndo_start_xmit		= omapl_pru_can_start_xmit,
> +};
> +
> +static int __devinit omapl_pru_can_probe(struct platform_device *pdev)
> +{
> +	struct net_device *ndev = NULL;
> +	const struct da8xx_pru_can_data *pdata;
> +	struct omapl_pru_can_priv *priv = NULL;
> +	struct device *dev = &pdev->dev;
> +	u32 err;
> +
> +	pdata = dev->platform_data;
> +	if (!pdata) {
> +		dev_err(&pdev->dev, "platform data not found\n");
> +		return -EINVAL;
> +	}
> +
> +	ndev = alloc_candev(sizeof(struct omapl_pru_can_priv), MB_MAX + 1);
> +	if (!ndev) {
> +		dev_err(&pdev->dev, "alloc_candev failed\n");
> +		err = -ENOMEM;
> +		goto probe_exit;
> +	}
> +	priv = netdev_priv(ndev);
> +
> +	priv->trx_irq = platform_get_irq(to_platform_device(dev->parent), 0);
> +	if (!priv->trx_irq) {
> +		dev_err(&pdev->dev, "unable to get pru interrupt resources!\n");
> +		err = -ENODEV;
> +		goto probe_exit;
> +	}
> +
> +	priv->ndev = ndev;
> +	priv->dev = dev; /* priv->dev = pdev->dev */
> +
> +	priv->can.bittiming_const = NULL;
> +	priv->can.do_set_bittiming = omapl_pru_can_set_bittiming;
> +	priv->can.do_set_mode = omapl_pru_can_set_mode;
> +	priv->can.do_get_state = omapl_pru_can_get_state;
> +	priv->can_tx_hndl.u8prunumber = CAN_TX_PRU_1;
> +	priv->can_rx_hndl.u8prunumber = CAN_RX_PRU_0;
> +
> +	/* we support local echo, no arp */
> +	ndev->flags |= (IFF_ECHO | IFF_NOARP);
> +
> +	/* pdev->dev->device_private->driver_data = ndev */
> +	platform_set_drvdata(pdev, ndev);
> +	SET_NETDEV_DEV(ndev, &pdev->dev);
> +	ndev->netdev_ops = &omapl_pru_can_netdev_ops;
> +
> +	priv->can.clock.freq = pruss_get_clk_freq(priv->dev);
> +
> +	priv->clk_timer = clk_get(&pdev->dev, "pll1_sysclk2");
> +	if (IS_ERR(priv->clk_timer)) {
> +		dev_err(&pdev->dev, "no timer clock available\n");
> +		err = PTR_ERR(priv->clk_timer);
> +		priv->clk_timer = NULL;
> +		goto probe_exit_candev;
> +	}
> +	priv->timer_freq = clk_get_rate(priv->clk_timer);
> +
> +	err = register_candev(ndev);
> +	if (err) {
> +		dev_err(&pdev->dev, "register_candev() failed\n");
> +		err = -ENODEV;
> +		goto probe_exit_clk;
> +	}
> +
> +	err = request_firmware(&priv->fw_tx, "PRU_CAN_Emulation_Tx.bin",
> +			&pdev->dev);
> +	if (err) {
> +		dev_err(&pdev->dev, "can't load firmware\n");
> +		err = -ENODEV;
> +		goto probe_exit_clk;
> +	}
> +
> +	dev_info(&pdev->dev, "fw_tx size %d. downloading...\n",
> +		 priv->fw_tx->size);
> +
> +	err = request_firmware(&priv->fw_rx, "PRU_CAN_Emulation_Rx.bin",
> +			&pdev->dev);
> +	if (err) {
> +		dev_err(&pdev->dev, "can't load firmware\n");
> +		err = -ENODEV;
> +		goto probe_release_fw;
> +	}
> +	dev_info(&pdev->dev, "fw_rx size %d. downloading...\n",
> +		 priv->fw_rx->size);
> +
> +	/* init the pru */
> +	pru_can_emu_init(priv->dev, priv->can.clock.freq);
> +	udelay(200);
> +
> +	pruss_enable(priv->dev, CAN_RX_PRU_0);
> +	pruss_enable(priv->dev, CAN_TX_PRU_1);
> +
> +	/* download firmware into pru */
> +	err = pruss_load(priv->dev, CAN_RX_PRU_0,
> +		(u32 *)priv->fw_rx->data, (priv->fw_rx->size / 4));
> +	if (err) {
> +		dev_err(&pdev->dev, "firmware download error\n");
> +		err = -ENODEV;
> +		goto probe_release_fw_1;
> +	}
> +	err = pruss_load(priv->dev, CAN_TX_PRU_1,
> +		(u32 *)priv->fw_tx->data, (priv->fw_tx->size / 4));
> +	if (err) {
> +		dev_err(&pdev->dev, "firmware download error\n");
> +		err = -ENODEV;
> +		goto probe_release_fw_1;
> +	}
> +
> +	if (pru_can_calc_timing(priv->dev, DFLT_PRU_FREQ,
> +				DFLT_PRU_BITRATE) != 0)
> +		return -EINVAL;

Please don't define a default bit-rate. It's error prune.

> +
> +	pruss_run(priv->dev, CAN_RX_PRU_0);
> +	pruss_run(priv->dev, CAN_TX_PRU_1);
> +
> +	/*Create The Work Queue */
> +	priv->pru_can_wQ = create_freezeable_workqueue("omapl_pru_wQ");
> +	if (priv->pru_can_wQ == NULL) {
> +		dev_err(&pdev->dev, "failed to create work queue\n");
> +		err = -ENODEV;
> +		goto probe_release_fw_1;
> +	}
> +
> +	INIT_WORK(&priv->rx_work, omapl_pru_can_rx_wQ);
> +	dev_info(&pdev->dev,
> +		 "%s device registered (trx_irq = %d,  clk = %d)\n",
> +		 DRV_NAME, priv->trx_irq, priv->can.clock.freq);
> +
> +	return 0;
> +
> +probe_release_fw_1:
> +	release_firmware(priv->fw_rx);
> +probe_release_fw:
> +	release_firmware(priv->fw_tx);
> +probe_exit_clk:
> +	clk_put(priv->clk_timer);
> +probe_exit_candev:
> +	if (NULL != ndev)
> +		free_candev(ndev);
> +probe_exit:
> +	return err;
> +}
> +
> +static int __devexit omapl_pru_can_remove(struct platform_device *pdev)
> +{
> +	struct net_device *ndev = platform_get_drvdata(pdev);
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +
> +	omapl_pru_can_stop(ndev);
> +
> +	pru_can_emu_exit(priv->dev);
> +	release_firmware(priv->fw_tx);
> +	release_firmware(priv->fw_rx);
> +	clk_put(priv->clk_timer);
> +	flush_workqueue(priv->pru_can_wQ);
> +	destroy_workqueue(priv->pru_can_wQ);
> +	unregister_candev(ndev);
> +	free_candev(ndev);
> +	platform_set_drvdata(pdev, NULL);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int omapl_pru_can_suspend(struct platform_device *pdev,
> +			pm_message_t mesg)
> +{
> +	dev_info(&pdev->dev, "%s not yet implemented\n", __func__);
> +	return 0;
> +}
> +
> +static int omapl_pru_can_resume(struct platform_device *pdev)
> +{
> +	dev_info(&pdev->dev, "%s not yet implemented\n", __func__);
> +	return 0;
> +}
> +#else
> +#define omapl_pru_can_suspend NULL
> +#define omapl_pru_can_resume NULL
> +#endif /* CONFIG_PM */
> +
> +static struct platform_driver omapl_pru_can_driver = {
> +	.probe		= omapl_pru_can_probe,
> +	.remove		= __devexit_p(omapl_pru_can_remove),
> +	.suspend	= omapl_pru_can_suspend,
> +	.resume		= omapl_pru_can_resume,
> +	.driver		= {
> +		.name	= DRV_NAME,
> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +static int __init omapl_pru_can_init(void)
> +{
> +	__can_debug(KERN_INFO DRV_DESC "\n");
> +	return platform_driver_register(&omapl_pru_can_driver);
> +}
> +
> +module_init(omapl_pru_can_init);
> +
> +static void __exit omapl_pru_can_exit(void)
> +{
> +	__can_debug(KERN_INFO DRV_DESC " unloaded\n");
> +	platform_driver_unregister(&omapl_pru_can_driver);
> +}
> +
> +module_exit(omapl_pru_can_exit);
> +
> +MODULE_AUTHOR("Subhasish Ghosh <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("omapl pru CAN netdevice driver");
> diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.c b/drivers/net/can/da8xx_pruss/pruss_can_api.c
> new file mode 100644
> index 0000000..2f7438a
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.c
> @@ -0,0 +1,1227 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Wilfred Felix
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as  published by the
> + * Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
> + * whether express or implied; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#include "pruss_can_api.h"
> +
> +static can_emu_drv_inst gstr_can_inst[ecanmaxinst];
> +
> +/*
> + * pru_can_set_brp()	Updates the  BRP register of PRU0
> + * and PRU1 of OMAP L138. This API will be called by the
> + * Application to updtae the BRP register of PRU0 and PRU1
> + *
> + * param	u16bitrateprescaler		The can bus bitrate
> + * prescaler value be set
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_set_brp(struct device *dev, u16 u16bitrateprescaler)
> +{
> +
> +	u32 u32offset;
> +
> +	if (u16bitrateprescaler > 255) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
> +
> +	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
> +
> +	return 0;
> +
> +}
> +
> +/*
> + * pru_can_set_bit_timing()		Updates the timing register
> + * of PRU0 and PRU1 of OMAP L138. This API will be called by
> + * the Application to updtae the timing register of PRU0 and PRU1
> + *
> + * param	pstrbittiming		Pointer to structure holding
> + * the bit timing values for can bus.
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_set_bit_timing(struct device *dev,
> +		can_bit_timing_consts *pstrbittiming)
> +{
> +
> +	u32 u32offset;
> +	u32 u32serregister;
> +
> +	u32serregister = 0;
> +
> +	if (pstrbittiming == NULL) {
> +		return -1;
> +	}
> +
> +	if ((pstrbittiming->u8syncjumpwidth > PRU_CAN_MAX_SJW) ||
> +	    (pstrbittiming->u8phseg1 > PRU_CAN_MAX_PHSEG1) ||
> +	    (pstrbittiming->u8phseg2 > PRU_CAN_MAX_PHSEG2)) {
> +		return -1;
> +	}
> +
> +	u32serregister = u32serregister |
> +			((pstrbittiming->u8syncjumpwidth << 7) |
> +			(pstrbittiming->u8phseg1 << 3) |
> +			(pstrbittiming->u8phseg2));
> +
> +	u32offset = (PRU_CAN_TX_TIMING_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1);
> +
> +	u32offset = (PRU_CAN_RX_TIMING_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1);
> +
> +	return 0;
> +}
> +
> +
> +/*
> + * pru_can_calc_timing()
> + * Updates the  timing values of PRU0 and PRU1 of OMAP L138.
> + * This API will be called by the
> + * Application to updtae the timing values of PRU0 and PRU1
> + *
> + * return   SUCCESS or FAILURE
> + */
> +
> +s16 pru_can_calc_timing(struct device *dev, u32 pru_freq, u32 bit_rate)
> +{
> +	u16 u16phaseseg1;
> +	u16 u16phaseseg2;
> +	u32 u32offset;
> +	u32 u32timing_value;
> +	u32 u32setup_value;
> +	u32timing_value = TIMER_CLK_FREQ / bit_rate;
> +	u32offset = (PRU_CAN_TIMING_VAL_TX);
> +	pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4);
> +	pruss_readl(dev, u32offset, (u32 *) &u32timing_value, 4);
> +	u32setup_value =
> +	    (GPIO_SETUP_DELAY * (pru_freq / 1000000) / 1000) /
> +	    DELAY_LOOP_LENGTH;
> +	u32offset = (PRU_CAN_TIMING_VAL_TX_SJW);
> +	pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4);
> +	u16phaseseg1 = (u16) (u32timing_value / 2);
> +	u16phaseseg2 = u32timing_value - u16phaseseg1;
> +	u16phaseseg1 -= TIMER_SETUP_DELAY;
> +	u16phaseseg2 -= TIMER_SETUP_DELAY;
> +	u32setup_value = (u16phaseseg1 << 16) | u16phaseseg2;
> +	u32offset = (PRU_CAN_TIMING_VAL_RX);
> +	pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4);
> +	u32offset = (PRU_CAN_TIMING_VAL_RX + 4);
> +	pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4);
> +
> +	return 0;
> +}

Why can't you use the common Socket-CAN bit-timing infrastructure.

> +/*
> + * pru_can_write_data_to_mailbox()
> + * Updates the transmit mailboxes of PRU1 of OMAP L138.
> + * This API will be called by the Application to update
> + * the transmit mailboxes of PRU1
> + *
> + * param  pu16canframedata	Can mailbox data buffer
> + *
> + * param  u8mailboxnum		Mailbox to be updated
> + *
> + * return SUCCESS or FAILURE
> + */
> +s16 pru_can_write_data_to_mailbox(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl)
> +{
> +	s16 s16subrtnretval;
> +	u32 u32offset;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
> +	case 0:
> +		u32offset = (PRU_CAN_TX_MAILBOX0);
> +		break;
> +	case 1:
> +		u32offset = (PRU_CAN_TX_MAILBOX1);
> +		break;
> +	case 2:
> +		u32offset = (PRU_CAN_TX_MAILBOX2);
> +		break;
> +	case 3:
> +		u32offset = (PRU_CAN_TX_MAILBOX3);
> +		break;
> +	case 4:
> +		u32offset = (PRU_CAN_TX_MAILBOX4);
> +		break;
> +	case 5:
> +		u32offset = (PRU_CAN_TX_MAILBOX5);
> +		break;
> +	case 6:
> +		u32offset = (PRU_CAN_TX_MAILBOX6);
> +		break;
> +	case 7:
> +		u32offset = (PRU_CAN_TX_MAILBOX7);
> +		break;
> +	default:
> +		return -1;
> +	}

There are more efficient ways to implemet that, e.g. by using an array.


> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +		(u32 *) &(pstremuapphndl->strcanmailbox), 4);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_data_from_mailbox()
> + * Receive data from the receive mailboxes of PRU0  of OMAP L138.
> + * This API will be called by the Application to get data from
> + * the receive mailboxes of PRU0
> + *
> + * param  pu16canframedata	Can mailbox data buffer
> + *
> + * param  u8mailboxnum		Mailbox to be updated
> + *
> + * return SUCCESS or FAILURE
> + */
> +s16 pru_can_get_data_from_mailbox(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	s16 s16subrtnretval;
> +	u32 u32offset;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
> +	case 0:
> +		u32offset = (PRU_CAN_RX_MAILBOX0);
> +		break;
> +	case 1:
> +		u32offset = (PRU_CAN_RX_MAILBOX1);
> +		break;
> +	case 2:
> +		u32offset = (PRU_CAN_RX_MAILBOX2);
> +		break;
> +	case 3:
> +		u32offset = (PRU_CAN_RX_MAILBOX3);
> +		break;
> +	case 4:
> +		u32offset = (PRU_CAN_RX_MAILBOX4);
> +		break;
> +	case 5:
> +		u32offset = (PRU_CAN_RX_MAILBOX5);
> +		break;
> +	case 6:
> +		u32offset = (PRU_CAN_RX_MAILBOX6);
> +		break;
> +	case 7:
> +		u32offset = (PRU_CAN_RX_MAILBOX7);
> +		break;
> +	case 8:
> +		u32offset = (PRU_CAN_RX_MAILBOX8);
> +		break;
> +	default:
> +		return -1;
> +	}

Ditto.

> +	s16subrtnretval =
> +	    pruss_readl(dev, u32offset,
> +		  (u32 *) &(pstremuapphndl->strcanmailbox),
> +				  4);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * pru_can_receive_id_map()
> + * Receive mailboxes ID Mapping of PRU0  of OMAP L138.
> + * This API will be called by the Application
> + * to map the IDs  to receive mailboxes of PRU0
> + *
> + * param  u32nodeid		Can node ID
> + *
> + * param  ecanmailboxno		Mailbox to be mapped
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_rx_id_map(struct device *dev, u32 u32nodeid,
> +		can_mailbox_number ecanmailboxno)
> +{
> +
> +	pruss_writel(dev, (PRU_CAN_ID_MAP +
> +		(((u8) ecanmailboxno) * 4)), (u32 *) &u32nodeid, 1);
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_intr_status()
> + * Gets the interrupts status register value.
> + * This API will be called by the Application
> + * to get the interrupts status register value
> + *
> + * param  u8prunumber	PRU number for which IntStatusReg
> + * has to be read
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_intr_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	s16 s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER);
> +	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER);
> +	} else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32interruptstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_global_status()	Gets the globalstatus
> + * register value. This API will be called by the Application
> + * to  get the global status register value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_global_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	int s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
> +	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
> +	} else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32globalstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_mailbox_status()		Gets the mailbox status
> + * register value. This API will be called by the Application
> + * to get the mailbox status register value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_mailbox_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	s16 s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		switch (pstremuapphndl->ecanmailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER);
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER);
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER);
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER);
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER);
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER);
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER);
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER);
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +
> +	else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		switch (pstremuapphndl->ecanmailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER);
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER);
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER);
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER);
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER);
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER);
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER);
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER);
> +			break;
> +		case 8:
> +			u32offset = (PRU_CAN_RX_MAILBOX8_STATUS_REGISTER);
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +
> +	else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32mailboxstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag,
> +				can_transfer_direction ecan_trx)
> +{
> +	u32 u32offset;
> +	u32 u32value;
> +
> +	if (ecan_trx == ecantransmit) {
> +		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
> +		pruss_readl(dev, u32offset, &u32value, 1);
> +		if (btransfer_flag == true) {
> +			u32value &= 0x1F;
> +			u32value |= 0x80;
> +		} else {
> +			u32value &= 0x7F;
> +		}
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +	} else if (ecan_trx == ecanreceive) {
> +		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
> +		pruss_readl(dev, u32offset, &u32value, 1);
> +		if (btransfer_flag == true) {
> +			u32value &= 0x1F;
> +			u32value |= 0x40;
> +		} else {
> +			u32value &= 0xBF;
> +		}
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +	} else
> +		return -1;
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_config_mode_set()		Sets the timing value
> + * for data transfer. This API will be called by the Application
> + * to set timing valus for data transfer
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_config_mode_set(struct device *dev, bool bconfigmodeflag)
> +{
> +
> +	u32 u32bitrateprescaler;
> +	u32 u32canbittiming;
> +
> +	pruss_readl(dev, (PRU_CAN_TX_CLOCK_BRP_REGISTER),
> +			(u32 *) &u32bitrateprescaler, 1);
> +	pruss_readl(dev, (PRU_CAN_TX_TIMING_REGISTER),
> +			(u32 *) &u32canbittiming, 1);
> +
> +	if (bconfigmodeflag == 1) {
> +		pru_can_calc_timing(dev, u32canbittiming, u32bitrateprescaler);
> +	}
> +
> +	else {
> +		pru_can_calc_timing(dev, 0, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_emu_init()		Initializes the Can
> + * Emulation Parameters. This API will be called by the Application
> + * to Initialize the Can Emulation Parameters
> + *
> + * param    u32pruclock         PRU Clock value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_init(struct device *dev, u32 u32pruclock)
> +{
> +	u32 u32offset;
> +	u32 u32value;
> +	s16 s16subrtnretval = -1;
> +	u8 u8loop;
> +
> +	for (u8loop = 0; u8loop < (u8) ecanmaxinst; u8loop++) {
> +		gstr_can_inst[u8loop].bcaninststate = (bool) 0;
> +		gstr_can_inst[u8loop].ecantransferdirection =
> +		    (can_transfer_direction) 0;
> +		gstr_can_inst[u8loop].u32apphandlerptr = 0;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_INTERRUPT_MASK_REGISTER & 0xFFFF);
> +	u32value = 0x00004000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval =
> +	    pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_TIMING_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_POLARITY0 & 0xFFFF);
> +	u32value = 0xFFFFFFFF;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_POLARITY1 & 0xFFFF);
> +	u32value = 0xFFFFFFFF;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_TYPE0 & 0xFFFF);
> +	u32value = 0x1C000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_TYPE1 & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HSTINTENIDXCLR & 0xFFFF);
> +	u32value = 0x0;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_GLBLEN & 0xFFFF);
> +	u32value = 0x1;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	/* tx intr map arm->pru */
> +	u32offset = (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
> +	u32value = 0x0;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTMAP0 & 0xFFFF);
> +	u32value = 0x03020100;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTMAP1 & 0xFFFF);
> +	u32value = 0x07060504;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTMAP2 & 0xFFFF);
> +	u32value = 0x0000908;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_CHANMAP0 & 0xFFFF);
> +	u32value = 0;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_CHANMAP8 & 0xFFFF);
> +	u32value = 0x00020200;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 19;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 19;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 18;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 18;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 34;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 34;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTINTEN & 0xFFFF);
> +	u32value = 0x5;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +/* PRU0 - Rx Internal Registers Initializations */
> +
> +	u32offset = (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_INTERRUPT_MASK_REGISTER & 0xFFFF);
> +	u32value = 0x00004000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x0000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_ERROR_COUNTER_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_TIMING_REGISTER & 0xFFFF);
> +	u32value = 0x0000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}

Above I realize a lot of duplicated code. Could be handled by an array
more efficiently, I believe.


> +	return 0;
> +}
> +
> +
> +/*
> + * pru_can_emu_open()		Opens the can emu for
> + * application to use. This API will be called by the Application
> + * to Open the can emu for application to use.
> + *
> + * param	pstremuapphndl	Pointer to application handler
> + * structure
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_open(struct device *dev, can_emu_app_hndl *pstremuapphndl)
> +{
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 1) {
> +		return -1;
> +	}
> +
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].
> +					bcaninststate = (bool)1;
> +	gstr_can_inst[(u8) pstremuapphndl->
> +		ecaninstance].ecantransferdirection =
> +		(can_transfer_direction)(u8)pstremuapphndl->ecantransferdirection;
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].
> +		u32apphandlerptr = (u32) pstremuapphndl;
> +
> +	return 0;
> +}
> +
> +
> +/*
> + * brief    pru_can_emu_close()	Closes the can emu for other
> + * applications to use. This API will be called by the Application to Close
> + * the can emu for other applications to use
> + *
> + * param	pstremuapphndl	Pointer to application handler structure
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_close(struct device *dev, can_emu_app_hndl *pstremuapphndl)
> +{
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +	if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 0) {
> +		return -1;
> +	}
> +	if ((u32) pstremuapphndl != gstr_can_inst[(u8) pstremuapphndl->
> +			ecaninstance].u32apphandlerptr){
> +		return -1;
> +	}
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].bcaninststate
> +		= (bool) 0;
> +	gstr_can_inst[(u8) pstremuapphndl->
> +	ecaninstance].ecantransferdirection = (can_transfer_direction) 0;
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].u32apphandlerptr = 0;
> +
> +	return 0;
> +}
> +
> +/*
> + * brief    pru_can_emu_exit()	Diables all the PRUs
> + * This API will be called by the Application to disable all PRUs
> + * param	None
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_exit(struct device *dev)
> +{
> +	s16 s16subrtnretval;
> +
> +	s16subrtnretval = pruss_disable(dev, CAN_RX_PRU_0);
> +	if (s16subrtnretval == -1)
> +		return -1;
> +	s16subrtnretval = pruss_disable(dev, CAN_TX_PRU_1);
> +	if (s16subrtnretval == -1)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +s16 pru_can_emu_sreset(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +s16 pru_can_tx(struct device *dev, u8 u8mailboxnumber, u8 u8prunumber)
> +{
> +	u32 u32offset = 0;
> +	u32 u32value = 0;
> +	s16 s16subrtnretval = -1;
> +
> +	if (DA8XX_PRUCORE_1 == u8prunumber) {
> +		switch (u8mailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		default:
> +			return -1;
> +		}
> +	} else {
> +
> +		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
> +		u32value = 0x00000000;
> +		s16subrtnretval = pruss_readl(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +		if (s16subrtnretval == -1) {
> +			return -1;
> +		}
> +		u32value = u32value & ~(1 << u8mailboxnumber);
> +		s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +		if (s16subrtnretval == -1) {
> +			return -1;
> +		}
> +
> +		switch (u8mailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		default:
> +			return -1;
> +		}

Ditto.

> +	}
> +	return 0;
> +}
> +
> +s16 pru_can_start_abort_tx(struct device *dev, bool bcantransmitabortflag)
> +{
> +	u32 u32offset;
> +	u32 u32value;
> +	s16 s16subrtnretval;
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +
> +	u32offset = (PRUSS_INTC_STATIDXSET & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +s16 pru_can_mask_ints(struct device *dev, u32 int_mask)
> +{
> +	return 0;
> +}
> +
> +int pru_can_get_error_cnt(struct device *dev, u8 u8prunumber)
> +{
> +	return 0;
> +}
> +
> +int pru_can_get_intc_status(struct device *dev)
> +{
> +	u32 u32offset = 0;
> +	u32 u32getvalue = 0;
> +	u32 u32clrvalue = 0;
> +
> +	u32offset = (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
> +	pruss_readl(dev, u32offset, (u32 *) &u32getvalue, 1);
> +
> +	if (u32getvalue & 4)
> +		u32clrvalue = 34;	/* CLR Event 34 */
> +
> +	if (u32getvalue & 2)
> +		u32clrvalue = 33;	/* CLR Event 33  */
> +
> +	if (u32clrvalue) {
> +		u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +		pruss_writel(dev, u32offset, &u32clrvalue, 1);
> +	} else
> +		return -1;
> +
> +	return u32getvalue;
> +}
> diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.h b/drivers/net/can/da8xx_pruss/pruss_can_api.h
> new file mode 100644
> index 0000000..7550456
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.h
> @@ -0,0 +1,290 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Ganeshan N
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as  published by the
> + * Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
> + * whether express or implied; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#ifndef _PRU_CAN_API_H_
> +#define _PRU_CAN_API_H_
> +
> +#include <linux/types.h>
> +#include <linux/mfd/pruss/da8xx_pru.h>
> +
> +
> +#define CAN_BIT_TIMINGS			(0x273)
> +
> +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */
> +#define	TIMER_CLK_FREQ			132000000
> +
> +#define TIMER_SETUP_DELAY		14
> +#define GPIO_SETUP_DELAY		150
> +
> +#define CAN_RX_PRU_0			PRUSS_NUM0
> +#define CAN_TX_PRU_1			PRUSS_NUM1
> +
> +/* Number of Instruction in the Delay loop */
> +#define DELAY_LOOP_LENGTH		2
> +
> +#define PRU1_BASE_ADDR			0x2000
> +
> +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER		(PRU1_BASE_ADDR)
> +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x04)
> +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER		(PRU1_BASE_ADDR	+ 0x08)
> +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x0C)
> +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x10)
> +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x14)
> +#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x18)
> +#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x1C)
> +#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x20)
> +#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x24)
> +#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x28)
> +#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x2C)
> +#define PRU_CAN_TX_ERROR_COUNTER_REGISTER		(PRU1_BASE_ADDR	+ 0x30)
> +#define PRU_CAN_TX_TIMING_REGISTER			(PRU1_BASE_ADDR	+ 0x34)
> +#define PRU_CAN_TX_CLOCK_BRP_REGISTER			(PRU1_BASE_ADDR	+ 0x38)
> +
> +#define PRU_CAN_TX_MAILBOX0				(PRU1_BASE_ADDR	+ 0x40)
> +#define PRU_CAN_TX_MAILBOX1				(PRU1_BASE_ADDR	+ 0x50)
> +#define PRU_CAN_TX_MAILBOX2				(PRU1_BASE_ADDR	+ 0x60)
> +#define PRU_CAN_TX_MAILBOX3				(PRU1_BASE_ADDR	+ 0x70)
> +#define PRU_CAN_TX_MAILBOX4				(PRU1_BASE_ADDR	+ 0x80)
> +#define PRU_CAN_TX_MAILBOX5				(PRU1_BASE_ADDR	+ 0x90)
> +#define PRU_CAN_TX_MAILBOX6				(PRU1_BASE_ADDR	+ 0xA0)
> +#define PRU_CAN_TX_MAILBOX7				(PRU1_BASE_ADDR	+ 0xB0)
> +
> +#define PRU_CAN_TIMING_VAL_TX				(PRU1_BASE_ADDR	+ 0xC0)
> +#define PRU_CAN_TIMING_VAL_TX_SJW			(PRU1_BASE_ADDR	+ 0xC4)
> +#define PRU_CAN_TRANSMIT_FRAME				(PRU1_BASE_ADDR	+ 0xE0)
> +
> +#define PRU0_BASE_ADDR					0
> +
> +#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER		(PRU0_BASE_ADDR)
> +#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x04)
> +#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER		(PRU0_BASE_ADDR	+ 0x08)
> +#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x0C)
> +#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x10)
> +#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x14)
> +#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x18)
> +#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x1C)
> +#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x20)
> +#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x24)
> +#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x28)
> +#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x2C)
> +#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x30)
> +#define PRU_CAN_RX_ERROR_COUNTER_REGISTER		(PRU0_BASE_ADDR	+ 0x34)
> +#define PRU_CAN_RX_TIMING_REGISTER			(PRU0_BASE_ADDR	+ 0x38)
> +#define PRU_CAN_RX_CLOCK_BRP_REGISTER			(PRU0_BASE_ADDR	+ 0x3C)
> +
> +#define PRU_CAN_RX_MAILBOX0				(PRU0_BASE_ADDR	+ 0x40)
> +#define PRU_CAN_RX_MAILBOX1				(PRU0_BASE_ADDR	+ 0x50)
> +#define PRU_CAN_RX_MAILBOX2				(PRU0_BASE_ADDR	+ 0x60)
> +#define PRU_CAN_RX_MAILBOX3				(PRU0_BASE_ADDR	+ 0x70)
> +#define PRU_CAN_RX_MAILBOX4				(PRU0_BASE_ADDR	+ 0x80)
> +#define PRU_CAN_RX_MAILBOX5				(PRU0_BASE_ADDR	+ 0x90)
> +#define PRU_CAN_RX_MAILBOX6				(PRU0_BASE_ADDR	+ 0xA0)
> +#define PRU_CAN_RX_MAILBOX7				(PRU0_BASE_ADDR	+ 0xB0)
> +#define PRU_CAN_RX_MAILBOX8				(PRU0_BASE_ADDR	+ 0xC0)
> +
> +#define PRU_CAN_TIMING_VAL_RX				(PRU0_BASE_ADDR	+ 0xD0)
> +#define PRU_CAN_RECEIVE_FRAME				(PRU0_BASE_ADDR	+ 0xD4)
> +#define PRU_CAN_ID_MAP					(PRU0_BASE_ADDR	+ 0xF0)

Please consider using a struct to define the register layout. This would
make you code much much more readable and compact:

	writel(&regs->brp_register, bitrateprescaler);

instead of:

	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);


> +#define PRU_CAN_ERROR_ACTIVE				128
> +
> +#define CAN_ACK_FAILED					0xE
> +#define CAN_ARBTR_FAIL					0xD
> +#define CAN_BIT_ERROR					0xC
> +#define CAN_TRANSMISSION_SUCCESS			0xA
> +
> +#define STD_DATA_FRAME					0x1
> +#define EXTD_DATA_FRAME					0x2
> +#define STD_REMOTE_FRAME				0x3
> +#define EXTD_REMOTE_FRAME				0x4
> +
> +#define PRU_CAN_MAX_SJW					8
> +#define PRU_CAN_MAX_PHSEG1				25
> +#define PRU_CAN_MAX_PHSEG2				25
> +
> +#define DA8XX_PRUCANCORE_0_REGS				0x7000
> +#define DA8XX_PRUCANCORE_1_REGS				0x7800
> +#define PRU0_PROG_RAM_START_OFFSET			0x8000
> +#define PRU1_PROG_RAM_START_OFFSET			0xC000
> +#define PRU_CAN_INIT_MAX_TIMEOUT			0xFF
> +
> +typedef enum {
> +	ecaninst0 = 0,
> +	ecaninst1,
> +	ecanmaxinst
> +} can_instance_enum;
> +
> +typedef enum {
> +	ecanmailbox0 = 0,
> +	ecanmailbox1,
> +	ecanmailbox2,
> +	ecanmailbox3,
> +	ecanmailbox4,
> +	ecanmailbox5,
> +	ecanmailbox6,
> +	ecanmailbox7
> +} can_mailbox_number;
> +
> +typedef enum {
> +	ecandirectioninit = 0,
> +	ecantransmit,
> +	ecanreceive
> +} can_transfer_direction;
> +
> +typedef struct {
> +	u16 u16extendedidentifier;
> +	u16 u16baseidentifier;
> +	u8 u8data7;
> +	u8 u8data6;
> +	u8 u8data5;
> +	u8 u8data4;
> +	u8 u8data3;
> +	u8 u8data2;
> +	u8 u8data1;
> +	u8 u8data0;
> +	u16 u16datalength;
> +	u16 u16crc;
> +} can_mail_box_structure;
> +
> +typedef struct {
> +	can_transfer_direction ecantransferdirection;
> +} can_mailbox_config;
> +
> +typedef struct {
> +	can_instance_enum ecaninstance;
> +	can_transfer_direction ecantransferdirection;
> +	can_mail_box_structure strcanmailbox;
> +	can_mailbox_number ecanmailboxnumber;
> +	u8 u8prunumber;
> +	u32 u32globalstatus;
> +	u32 u32interruptstatus;
> +	u32 u32mailboxstatus;
> +} can_emu_app_hndl;
> +
> +typedef struct {
> +	bool bcaninststate;
> +	can_transfer_direction ecantransferdirection;
> +	u32 u32apphandlerptr;
> +} can_emu_drv_inst;
> +
> +typedef struct {
> +	u8 u8syncjumpwidth;
> +	u8 u8phseg1;
> +	u8 u8phseg2;
> +} can_bit_timing_consts;

Don't use typedef's!

Thanks.

Wolfgang.

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
                       ` (2 preceding siblings ...)
  2011-02-11 20:33     ` Wolfgang Grandegger
@ 2011-02-11 21:33     ` Marc Kleine-Budde
  3 siblings, 0 replies; 21+ messages in thread
From: Marc Kleine-Budde @ 2011-02-11 21:33 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	m-watkins-l0cyMroinI0,
	Wolfgang Grandegger (maintainer:CAN NETWORK DRIVERS)


[-- Attachment #1.1: Type: text/plain, Size: 78981 bytes --]

On 02/11/2011 03:51 PM, Subhasish Ghosh wrote:
> This patch adds support for the CAN device emulated on PRUSS.

Is this a software CAN device running on the omap dsp? Nice :)
My first impression is that this driver needs a lot of work, but we'll
help you.

Being new to the OMAP world here are soo many names for the same thing,
i.e. the CAN core and driver:

- da8cc
- pruss
- omap
- pru

These or combination of these are used all over the code. I'm preferring
one common prefix. I like the PRU_ prefix for the defines and the pru_
for functions.

Please don't encode the variable type into their names (a.k.a. polish
notation), e.g. it's "u8 data" not "u8 u8data", No typedefs, enums just
like defines in uppercase.

Get rid of the of the extra layer in pruss_can_api.c.

More comments inline:

> Signed-off-by: Subhasish Ghosh <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
> ---
>  drivers/net/can/Kconfig                     |    1 +
>  drivers/net/can/Makefile                    |    1 +
>  drivers/net/can/da8xx_pruss/Kconfig         |   73 ++
>  drivers/net/can/da8xx_pruss/Makefile        |    7 +
>  drivers/net/can/da8xx_pruss/pruss_can.c     |  758 +++++++++++++++++
>  drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++
>  drivers/net/can/da8xx_pruss/pruss_can_api.h |  290 +++++++
>  7 files changed, 2357 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/can/da8xx_pruss/Kconfig
>  create mode 100644 drivers/net/can/da8xx_pruss/Makefile
>  create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c
>  create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c
>  create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h
> 
> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
> index d5a9db6..ae8f0f9 100644
> --- a/drivers/net/can/Kconfig
> +++ b/drivers/net/can/Kconfig
> @@ -112,6 +112,7 @@ config PCH_CAN
>  	  This driver can access CAN bus.
>  
>  source "drivers/net/can/mscan/Kconfig"
> +source "drivers/net/can/da8xx_pruss/Kconfig"
>  
>  source "drivers/net/can/sja1000/Kconfig"
>  
> diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
> index 07ca159..849cdbf 100644
> --- a/drivers/net/can/Makefile
> +++ b/drivers/net/can/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
>  obj-$(CONFIG_CAN_MSCAN)		+= mscan/
>  obj-$(CONFIG_CAN_AT91)		+= at91_can.o
>  obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
> +obj-$(CONFIG_CAN_TI_DA8XX_PRU)	+= da8xx_pruss/
>  obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
>  obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
>  obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
> diff --git a/drivers/net/can/da8xx_pruss/Kconfig b/drivers/net/can/da8xx_pruss/Kconfig
> new file mode 100644
> index 0000000..8b68f68
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/Kconfig
> @@ -0,0 +1,73 @@
> +#
> +# CAN Lite Kernel Configuration
     ^^^^^^^^^^^^^^^

what's can lite?

> +#
> +config CAN_TI_DA8XX_PRU
> +	depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850
> +	tristate "PRU based CAN emulation for DA8XX"
> +	---help---
> +	Enable this to emulate a CAN controller on the PRU of DA8XX.
> +	If not sure, mark N
> +
> +config DA8XX_PRU_CANID_MBX0
> +	hex "CANID for mailbox 0"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 0
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX1
> +	hex "CANID for mailbox 1"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	 ---help---
> +	Enter the CANID for mailbox 1
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX2
> +	hex "CANID for mailbox 2"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 2
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX3
> +	hex "CANID for mailbox 3"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 3
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX4
> +	hex "CANID for mailbox 4"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 4
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX5
> +	hex "CANID for mailbox 5"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 5
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX6
> +	hex "CANID for mailbox 6"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 6
> +	Default value is set to 0x123, change this as required.
> +
> +config DA8XX_PRU_CANID_MBX7
> +	hex "CANID for mailbox 7"
> +	depends on CAN_TI_DA8XX_PRU
> +	default "0x123"
> +	---help---
> +	Enter the CANID for mailbox 7
> +	Default value is set to 0x123, change this as required.

This doesn't fit to the Socketcan abstraction of a CAN card. Please
remove. After this "da8xx_pruss/Kconfig" just contains the
CAN_TI_DA8XX_PRU symbol, which can be added directly to
drivers/net/can/Kconfig. (With a perhaps a simpler kconfig symbol name.)

> diff --git a/drivers/net/can/da8xx_pruss/Makefile b/drivers/net/can/da8xx_pruss/Makefile
> new file mode 100644
> index 0000000..48f3055
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for CAN Lite emulation
> +#
> +can_emu-objs :=   pruss_can.o \
> +                  pruss_can_api.o

Do we need two c file? I haven't look at them, yet.

> +
> +obj-$(CONFIG_CAN_TI_DA8XX_PRU)    += can_emu.o
> diff --git a/drivers/net/can/da8xx_pruss/pruss_can.c b/drivers/net/can/da8xx_pruss/pruss_can.c
> new file mode 100644
> index 0000000..1b3afde
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can.c
> @@ -0,0 +1,758 @@
> +/*
> + *  TI DA8XX PRU CAN Emulation device driver
> + *  Author: subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org
> + *
> + *  This driver supports TI's PRU CAN Emulation and the
> + *  specs for the same is available at <http://www.ti.com>
> + *
> + *  Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/

You'll probably do some work on the driver, so add a 2011, here :)

> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License as
> + *  published by the Free Software Foundation version 2.
> + *
> + *  This program is distributed as is WITHOUT ANY WARRANTY of any
> + *  kind, whether express or implied; without even the implied warranty
> + *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/bitops.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/netdevice.h>
> +#include <linux/skbuff.h>
> +#include <linux/platform_device.h>
> +#include <linux/firmware.h>
> +#include <linux/clk.h>
> +#include <linux/types.h>
> +
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +#include <mach/da8xx.h>
> +#include "pruss_can_api.h"

Do we need a separate header file?
> +
> +#define DRV_NAME "da8xx_pruss_can"
> +#define DRV_DESC "TI PRU CAN Controller Driver v0.1"
> +#define PRU_CAN_START		1
> +#define PRU_CAN_STOP		0
> +#define MB_MIN			0
> +#define MB_MAX			7

please add the common PRU_ prefis to the MB_*, too.

> +
> +#define PRU_CANMID_IDE			BIT(29)	/* Extended frame format */
> +
> +#define PRU_CAN_ISR_BIT_CCI		BIT(15)
> +#define PRU_CAN_ISR_BIT_ESI		BIT(14)
> +#define PRU_CAN_ISR_BIT_SRDI		BIT(13)
> +#define PRU_CAN_ISR_BIT_RRI		BIT(8)
> +
> +#define PRU_CAN_MBXSR_BIT_STATE		BIT(7)
> +#define PRU_CAN_MBXSR_BIT_TC		BIT(6)
> +#define PRU_CAN_MBXSR_BIT_ERR		BIT(5)
> +#define PRU_CAN_MBXSR_BIT_OF		BIT(0)
> +
> +#define PRU_CAN_GSR_BIT_TXM		BIT(7)
> +#define PRU_CAN_GSR_BIT_RXM		BIT(6)
> +#define PRU_CAN_GSR_BIT_CM		BIT(5)
> +#define PRU_CAN_GSR_BIT_EPM		BIT(4)
> +#define PRU_CAN_GSR_BIT_BFM		BIT(3)
> +#define RTR_MBX_NO			8

We don't have special mailboxes for RTR, pleae remove.

add the PRU_ prefix here, too.
> +#define MAX_INIT_RETRIES		20
> +#define L138_PRU_ARM_FREQ		312000
> +#define DFLT_PRU_FREQ			156000000

Any change that you get these values from the a clock device?
e.g.:
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/flexcan.c#L909
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/flexcan.c#L946

> +#define DFLT_PRU_BITRATE		125000

Please remove, we don't have a default bitrate.

> +
> +#define CONFIG_DA8XX_PRU_CANID_MBX0	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX1	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX2	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX3	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX4	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX5	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX6	0x123
> +#define CONFIG_DA8XX_PRU_CANID_MBX7	0x123

as alreadt said, we don't have default canids, please remove.

> +
> +#ifdef __CAN_DEBUG
> +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args)
> +#else
> +#define __can_debug(fmt, args...)
> +#endif
> +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)

please use pr_<level> and and friends, use pr_fmt to set a common
prefix. Or even better use netdev_<level>.

> +
> +/*
> + * omapl_pru can private data
> + */
> +struct omapl_pru_can_priv {
> +	struct can_priv can;
> +	struct workqueue_struct *pru_can_wQ;
> +	struct work_struct rx_work;
> +	struct net_device *ndev;
> +	struct device *dev; /* pdev->dev */

nitpick: pointless comment :)

> +	struct clk *clk_timer;
> +	u32 timer_freq;
> +	can_emu_app_hndl can_tx_hndl;
> +	can_emu_app_hndl can_rx_hndl;

please no new typedefs.

> +	const struct firmware *fw_rx;
> +	const struct firmware *fw_tx;
> +	spinlock_t mbox_lock;
> +	u32 trx_irq;
> +	u32 tx_head;
> +	u32 tx_tail;
> +	u32 tx_next;
> +	u32 rx_next;

If these don't reflect register values, just use "unsigned int"s here.

> +};
> +
> +static int omapl_pru_can_get_state(const struct net_device *ndev,
> +				   enum can_state *state)

just for consistency most other can drivers use "struct net_device *dev".

> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	*state = priv->can.state;
> +	return 0;
> +}
> +
> +static int omapl_pru_can_set_bittiming(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct can_bittiming *bt = &priv->can.bittiming;
> +	long bit_error = 0;
> +
> +	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) {
> +		dev_warn(priv->dev, "WARN: Triple"
> +			 "sampling not set due to h/w limitations");
> +	}

No need to check this, just set the modes you support in
"priv->can.ctrlmode_supported".

http://lxr.linux.no/linux+v2.6.37/drivers/net/can/at91_can.c#L1091

> +	if (pru_can_calc_timing(priv->dev, priv->can.clock.freq,
> +				bt->bitrate) != 0)

The above function does _set_ the bit timing into the hardware, calling
it "can_calc_timing" is a bit misleading.

Don't calculate the bit timing yoursef. Please define your
bittiming_const and set it, see:

http://lxr.linux.no/linux+v2.6.37/drivers/net/can/at91_can.c#L173
http://lxr.linux.no/linux+v2.6.37/drivers/net/can/at91_can.c#L1088

> +		return -EINVAL;
> +	bit_error =
> +	    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
> +	      bt->bitrate) * 1000) / bt->bitrate;
> +	if (bit_error) {
> +		bit_error =
> +		    (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
> +		      bt->bitrate) * 1000000) / bt->bitrate;
> +		printk(KERN_INFO "\nBitrate error %ld.%ld%%\n",
> +			bit_error / 10000, bit_error % 1000);
> +	} else
> +		printk(KERN_INFO "\nBitrate error 0.0%%\n");
> +
> +	return 0;
> +}
> +
> +static void omapl_pru_can_stop(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	u16 int_mask = 0;
> +
> +	pru_can_mask_ints(priv->dev, int_mask);	/* mask all ints */
> +	pru_can_start_abort_tx(priv->dev, PRU_CAN_STOP);
> +	priv->can.state = CAN_STATE_STOPPED;
> +}
> +
> +/*
> + * This is to just set the can state to ERROR_ACTIVE
> + *	ip link set canX up type can bitrate 125000
> + */
> +static void omapl_pru_can_start(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	u16 int_mask = 0xFFFF;
> +
> +	if (priv->can.state != CAN_STATE_STOPPED)
> +		omapl_pru_can_stop(ndev);
> +
> +	pru_can_mask_ints(priv->dev, int_mask);	/* unmask all ints */
> +
> +	pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
> +	pru_can_get_global_status(priv->dev, &priv->can_rx_hndl);
> +
> +	if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus)
> +		priv->can.state = CAN_STATE_ERROR_PASSIVE;
> +	else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus)
> +		priv->can.state = CAN_STATE_BUS_OFF;
> +	else
> +		priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +}
> +
> +static int omapl_pru_can_set_mode(struct net_device *ndev, enum can_mode mode)
> +{
> +	int ret = 0;
> +
> +	switch (mode) {
> +	case CAN_MODE_START:
> +		omapl_pru_can_start(ndev);
> +		if (netif_queue_stopped(ndev))
> +			netif_wake_queue(ndev);
> +		break;
> +	case CAN_MODE_STOP:
> +		omapl_pru_can_stop(ndev);
> +		if (!netif_queue_stopped(ndev))
> +			netif_stop_queue(ndev);
> +		break;
> +	default:
> +		ret = -EOPNOTSUPP;
> +		break;
> +	}
> +	return ret;
> +}
> +
> +static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb,
> +					    struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct can_frame *cf = (struct can_frame *)skb->data;
> +	int count;
> +	u8 *data = cf->data;
> +	u8 dlc = cf->can_dlc;
> +	u8 *ptr8data = NULL;
> +
> +	netif_stop_queue(ndev);
> +	if (cf->can_id & CAN_EFF_FLAG)	/* Extended frame format */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
> +		    (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE;
> +	else			/* Standard frame format */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) =
> +		    (cf->can_id & CAN_SFF_MASK) << 18;
> +
> +	if (cf->can_id & CAN_RTR_FLAG)	/* Remote transmission request */
> +		*((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG;
> +
> +	ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1);
> +	for (count = 0; count < (u8) dlc; count++) {
> +		*ptr8data-- = *data++;
> +	}
> +	*((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc;
> +/*
> + * search for the next available mbx
> + * if the next mbx is busy, then try the next + 1
> + * do this until the head is reached.
> + * if still unable to tx, stop accepting any packets
> + * if able to tx and the head is reached, then reset next to tail, i.e mbx0
> + * if head is not reached, then just point to the next mbx
> + */
> +	for (; priv->tx_next <= priv->tx_head; priv->tx_next++) {
> +		priv->can_tx_hndl.ecanmailboxnumber =
> +		    (can_mailbox_number) priv->tx_next;
> +		if (-1 == pru_can_write_data_to_mailbox(priv->dev,
> +					&priv->can_tx_hndl)) {
> +			if (priv->tx_next == priv->tx_head) {
> +				priv->tx_next = priv->tx_tail;
> +				if (!netif_queue_stopped(ndev))
> +					netif_stop_queue(ndev);	/* IF stalled */
> +				dev_err(priv->dev,
> +					"%s: no tx mbx available", __func__);
> +				return NETDEV_TX_BUSY;
> +			} else
> +				continue;
> +		} else {
> +			/* set transmit request */
> +			pru_can_tx(priv->dev, priv->tx_next, CAN_TX_PRU_1);
> +			pru_can_tx_mode_set(priv->dev, false, ecanreceive);
> +			pru_can_tx_mode_set(priv->dev, true, ecantransmit);
> +			pru_can_start_abort_tx(priv->dev, PRU_CAN_START);
> +			priv->tx_next++;
> +			can_put_echo_skb(skb, ndev, 0);
> +			break;
> +		}
> +	}
> +	if (priv->tx_next > priv->tx_head) {
> +		priv->tx_next = priv->tx_tail;
> +	}
> +	return NETDEV_TX_OK;
> +}
> +
> +static int omapl_pru_can_rx(struct net_device *ndev, u32 mbxno)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct net_device_stats *stats = &ndev->stats;
> +	struct can_frame *cf;
> +	struct sk_buff *skb;
> +	u32 pru_can_mbx_data;
> +	u8 *data = NULL;
> +	u8 *ptr8data = NULL;
> +	int count = 0;
> +
> +	skb = alloc_can_skb(ndev, &cf);
> +	if (!skb) {
> +		if (printk_ratelimit())
> +			dev_err(priv->dev,
> +				"alloc_can_skb() failed\n");
> +		return -ENOMEM;
> +	}
> +	data = cf->data;
> +	/*      get payload */
> +	priv->can_rx_hndl.ecanmailboxnumber = (can_mailbox_number) mbxno;
> +	if (pru_can_get_data_from_mailbox(priv->dev, &priv->can_rx_hndl)) {
> +		__can_err("failed to get data from mailbox\n");
> +		return -EAGAIN;
> +	}
> +	/* give ownweship to pru */
> +	pru_can_tx(priv->dev, mbxno, CAN_RX_PRU_0);
> +
> +	/* get data length code */
> +	cf->can_dlc =
> +	    get_can_dlc(*
> +			((u32 *) &priv->can_rx_hndl.strcanmailbox.
> +			 u16datalength) & 0xF);
> +	if (cf->can_dlc <= 4) {
> +		ptr8data =
> +		    &priv->can_rx_hndl.strcanmailbox.u8data3 + (4 -
> +								cf->can_dlc);
> +		for (count = 0; count < cf->can_dlc; count++) {
> +			*data++ = *ptr8data++;
> +		}
> +	} else {
> +		ptr8data = &priv->can_rx_hndl.strcanmailbox.u8data3;
> +		for (count = 0; count < 4; count++) {
> +			*data++ = *ptr8data++;
> +		}
> +		ptr8data =
> +		    &priv->can_rx_hndl.strcanmailbox.u8data4 - (cf->can_dlc -
> +								5);
> +		for (count = 0; count < cf->can_dlc - 4; count++) {
> +			*data++ = *ptr8data++;
> +		}
> +	}
> +
> +	pru_can_mbx_data = *((u32 *) &priv->can_rx_hndl.strcanmailbox);
> +	/* get id extended or std */
> +	if (pru_can_mbx_data & PRU_CANMID_IDE)
> +		cf->can_id = (pru_can_mbx_data & CAN_EFF_MASK) | CAN_EFF_FLAG;
> +	else
> +		cf->can_id = (pru_can_mbx_data >> 18) & CAN_SFF_MASK;
> +
> +	if (pru_can_mbx_data & CAN_RTR_FLAG)
> +		cf->can_id |= CAN_RTR_FLAG;
> +
> +	netif_rx_ni(skb);
> +	stats->rx_packets++;
> +	stats->rx_bytes += cf->can_dlc;
> +	return 0;
> +}
> +
> +static int omapl_pru_can_err(struct net_device *ndev, int int_status,
> +			     int err_status)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct net_device_stats *stats = &ndev->stats;
> +	struct can_frame *cf;
> +	struct sk_buff *skb;
> +	int tx_err_cnt, rx_err_cnt;
> +
> +	/* propogate the error condition to the can stack */
> +	skb = alloc_can_err_skb(ndev, &cf);
> +	if (!skb) {
> +		if (printk_ratelimit())
> +			dev_err(priv->dev,
> +				"alloc_can_err_skb() failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	if (err_status & PRU_CAN_GSR_BIT_EPM) {	/* error passive int */
> +		priv->can.state = CAN_STATE_ERROR_PASSIVE;
> +		++priv->can.can_stats.error_passive;
> +		cf->can_id |= CAN_ERR_CRTL;
> +		tx_err_cnt = pru_can_get_error_cnt(priv->dev, CAN_TX_PRU_1);
> +		rx_err_cnt = pru_can_get_error_cnt(priv->dev, CAN_RX_PRU_0);
> +		if (tx_err_cnt > 127)
> +			cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> +		if (rx_err_cnt > 127)
> +			cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> +
> +		dev_dbg(priv->ndev->dev.parent, "Error passive interrupt\n");
> +	}
> +
> +	if (err_status & PRU_CAN_GSR_BIT_BFM) {
> +		priv->can.state = CAN_STATE_BUS_OFF;
> +		cf->can_id |= CAN_ERR_BUSOFF;
> +		/*
> +		 *      Disable all interrupts in bus-off to avoid int hog
> +		 *      this should be handled by the pru
> +		 */
> +		pru_can_mask_ints(priv->dev, 0xFFFF);
> +		can_bus_off(ndev);
> +		dev_dbg(priv->ndev->dev.parent, "Bus off mode\n");
> +	}
> +
> +	netif_rx(skb);
> +	stats->rx_packets++;
> +	stats->rx_bytes += cf->can_dlc;
> +	return 0;
> +}
> +
> +void omapl_pru_can_rx_wQ(struct work_struct *work)
> +{
> +	struct omapl_pru_can_priv *priv = container_of(work,
> +			struct omapl_pru_can_priv, rx_work);
> +	struct net_device *ndev = priv->ndev;
> +	u32 bit_set, mbxno = 0;
> +
> +	if (-1 == pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
> +		return;
> +
> +	if (PRU_CAN_ISR_BIT_RRI & priv->can_rx_hndl.u32interruptstatus) {
> +		mbxno = RTR_MBX_NO;
> +		omapl_pru_can_rx(ndev, mbxno);
> +	} else {
> +		/* Extract the mboxno from the status */
> +		for (bit_set = 0; ((priv->can_rx_hndl.u32interruptstatus & 0xFF)
> +						>> bit_set != 0); bit_set++)
> +		;
> +		if (0 == bit_set) {
> +			dev_err(priv->dev,
> +				"%s: invalid mailbox number: %X\n", __func__,
> +				priv->can_rx_hndl.u32interruptstatus);
> +		} else {
> +			mbxno = bit_set - 1;
> +			if (PRU_CAN_ISR_BIT_ESI & priv->can_rx_hndl.
> +			    u32interruptstatus) {
> +				pru_can_get_global_status(priv->dev,
> +					&priv->can_rx_hndl);
> +				omapl_pru_can_err(ndev,
> +				priv->can_rx_hndl.u32interruptstatus,
> +				priv->can_rx_hndl.u32globalstatus);
> +			} else {
> +				omapl_pru_can_rx(ndev, mbxno);
> +			}
> +		}
> +	}
> +}
> +
> +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id)
> +{
> +	struct net_device *ndev = dev_id;
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	struct net_device_stats *stats = &ndev->stats;
> +	u32 bit_set, mbxno;
> +
> +	pru_can_get_intr_status(priv->dev, &priv->can_tx_hndl);
> +	if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus)
> +	    || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) {
> +		__can_debug("tx_int_status = 0x%X\n",
> +			    priv->can_tx_hndl.u32interruptstatus);
> +		can_free_echo_skb(ndev, 0);
> +	} else {
> +		for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF)
> +						>> bit_set != 0); bit_set++)
> +		;
> +		if (0 == bit_set) {
> +			__can_err("%s: invalid mailbox number\n", __func__);
> +			can_free_echo_skb(ndev, 0);
> +		} else {
> +			mbxno = bit_set - 1;	/* mail box numbering starts from 0 */
> +			if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl.
> +			    u32interruptstatus) {
> +				/* read gsr and ack pru */
> +				pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
> +				omapl_pru_can_err(ndev,
> +						  priv->can_tx_hndl.
> +						  u32interruptstatus,
> +						  priv->can_tx_hndl.
> +						  u32globalstatus);
> +			} else {
> +				stats->tx_packets++;
> +				/* stats->tx_bytes += dlc; */
> +				/*can_get_echo_skb(ndev, 0);*/
> +			}
> +		}
> +	}
> +	if (netif_queue_stopped(ndev))
> +		netif_wake_queue(ndev);
> +
> +	can_get_echo_skb(ndev, 0);
> +	pru_can_tx_mode_set(priv->dev, true, ecanreceive);
> +	return IRQ_HANDLED;
> +}
> +
> +irqreturn_t omapl_rx_can_intr(int irq, void *dev_id)
> +{
> +
> +	struct net_device *ndev = dev_id;
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	u32 intc_status = 0;
> +
> +	intc_status = pru_can_get_intc_status(priv->dev);
> +	if (intc_status & 4)
> +		return omapl_tx_can_intr(irq, dev_id);
> +	if (intc_status & 2) {
> +		if (!work_pending(&priv->rx_work))
> +			queue_work(priv->pru_can_wQ, &priv->rx_work);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int omapl_pru_can_open(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +	int err;
> +
> +	/* register interrupt handler */
> +	err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
> +			  "pru_can_irq", ndev);
> +	if (err) {
> +		dev_err(priv->dev, "error requesting rx interrupt\n");
> +		goto exit_trx_irq;
> +	}
> +	/* common open */
> +	err = open_candev(ndev);
> +	if (err) {
> +		dev_err(priv->dev, "open_candev() failed %d\n", err);
> +		goto exit_open;
> +	}
> +
> +	pru_can_emu_init(priv->dev, priv->can.clock.freq);
> +	priv->tx_tail = MB_MIN;
> +	priv->tx_head = MB_MAX;
> +
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX0, 0);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX1, 1);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX2, 2);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX3, 3);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX4, 4);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX5, 5);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX6, 6);
> +	pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX7, 7);
> +
> +	omapl_pru_can_start(ndev);
> +	netif_start_queue(ndev);
> +	return 0;
> +
> +exit_open:
> +	free_irq(priv->trx_irq, ndev);
> +exit_trx_irq:
> +	return err;
> +}
> +
> +static int omapl_pru_can_close(struct net_device *ndev)
> +{
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +
> +	if (!netif_queue_stopped(ndev))
> +		netif_stop_queue(ndev);
> +
> +	close_candev(ndev);
> +
> +	free_irq(priv->trx_irq, ndev);
> +	return 0;
> +}
> +
> +static const struct net_device_ops omapl_pru_can_netdev_ops = {
> +	.ndo_open		= omapl_pru_can_open,
> +	.ndo_stop		= omapl_pru_can_close,
> +	.ndo_start_xmit		= omapl_pru_can_start_xmit,
> +};
> +
> +static int __devinit omapl_pru_can_probe(struct platform_device *pdev)
> +{
> +	struct net_device *ndev = NULL;
> +	const struct da8xx_pru_can_data *pdata;
> +	struct omapl_pru_can_priv *priv = NULL;
> +	struct device *dev = &pdev->dev;
> +	u32 err;
> +
> +	pdata = dev->platform_data;
> +	if (!pdata) {
> +		dev_err(&pdev->dev, "platform data not found\n");
> +		return -EINVAL;
> +	}
> +
> +	ndev = alloc_candev(sizeof(struct omapl_pru_can_priv), MB_MAX + 1);
> +	if (!ndev) {
> +		dev_err(&pdev->dev, "alloc_candev failed\n");
> +		err = -ENOMEM;
> +		goto probe_exit;
> +	}
> +	priv = netdev_priv(ndev);
> +
> +	priv->trx_irq = platform_get_irq(to_platform_device(dev->parent), 0);
> +	if (!priv->trx_irq) {
> +		dev_err(&pdev->dev, "unable to get pru interrupt resources!\n");
> +		err = -ENODEV;
> +		goto probe_exit;
> +	}
> +
> +	priv->ndev = ndev;
> +	priv->dev = dev; /* priv->dev = pdev->dev */
> +
> +	priv->can.bittiming_const = NULL;
> +	priv->can.do_set_bittiming = omapl_pru_can_set_bittiming;
> +	priv->can.do_set_mode = omapl_pru_can_set_mode;
> +	priv->can.do_get_state = omapl_pru_can_get_state;
> +	priv->can_tx_hndl.u8prunumber = CAN_TX_PRU_1;
> +	priv->can_rx_hndl.u8prunumber = CAN_RX_PRU_0;
> +
> +	/* we support local echo, no arp */
> +	ndev->flags |= (IFF_ECHO | IFF_NOARP);
> +
> +	/* pdev->dev->device_private->driver_data = ndev */
> +	platform_set_drvdata(pdev, ndev);
> +	SET_NETDEV_DEV(ndev, &pdev->dev);
> +	ndev->netdev_ops = &omapl_pru_can_netdev_ops;
> +
> +	priv->can.clock.freq = pruss_get_clk_freq(priv->dev);
> +
> +	priv->clk_timer = clk_get(&pdev->dev, "pll1_sysclk2");
> +	if (IS_ERR(priv->clk_timer)) {
> +		dev_err(&pdev->dev, "no timer clock available\n");
> +		err = PTR_ERR(priv->clk_timer);
> +		priv->clk_timer = NULL;
> +		goto probe_exit_candev;
> +	}
> +	priv->timer_freq = clk_get_rate(priv->clk_timer);
> +
> +	err = register_candev(ndev);
> +	if (err) {
> +		dev_err(&pdev->dev, "register_candev() failed\n");
> +		err = -ENODEV;
> +		goto probe_exit_clk;
> +	}
> +
> +	err = request_firmware(&priv->fw_tx, "PRU_CAN_Emulation_Tx.bin",
> +			&pdev->dev);
> +	if (err) {
> +		dev_err(&pdev->dev, "can't load firmware\n");
> +		err = -ENODEV;
> +		goto probe_exit_clk;
> +	}
> +
> +	dev_info(&pdev->dev, "fw_tx size %d. downloading...\n",
> +		 priv->fw_tx->size);
> +
> +	err = request_firmware(&priv->fw_rx, "PRU_CAN_Emulation_Rx.bin",
> +			&pdev->dev);
> +	if (err) {
> +		dev_err(&pdev->dev, "can't load firmware\n");
> +		err = -ENODEV;
> +		goto probe_release_fw;
> +	}
> +	dev_info(&pdev->dev, "fw_rx size %d. downloading...\n",
> +		 priv->fw_rx->size);
> +
> +	/* init the pru */
> +	pru_can_emu_init(priv->dev, priv->can.clock.freq);
> +	udelay(200);
> +
> +	pruss_enable(priv->dev, CAN_RX_PRU_0);
> +	pruss_enable(priv->dev, CAN_TX_PRU_1);
> +
> +	/* download firmware into pru */
> +	err = pruss_load(priv->dev, CAN_RX_PRU_0,
> +		(u32 *)priv->fw_rx->data, (priv->fw_rx->size / 4));
> +	if (err) {
> +		dev_err(&pdev->dev, "firmware download error\n");
> +		err = -ENODEV;
> +		goto probe_release_fw_1;
> +	}
> +	err = pruss_load(priv->dev, CAN_TX_PRU_1,
> +		(u32 *)priv->fw_tx->data, (priv->fw_tx->size / 4));
> +	if (err) {
> +		dev_err(&pdev->dev, "firmware download error\n");
> +		err = -ENODEV;
> +		goto probe_release_fw_1;
> +	}
> +
> +	if (pru_can_calc_timing(priv->dev, DFLT_PRU_FREQ,
> +				DFLT_PRU_BITRATE) != 0)
> +		return -EINVAL;
> +
> +	pruss_run(priv->dev, CAN_RX_PRU_0);
> +	pruss_run(priv->dev, CAN_TX_PRU_1);
> +
> +	/*Create The Work Queue */
> +	priv->pru_can_wQ = create_freezeable_workqueue("omapl_pru_wQ");
> +	if (priv->pru_can_wQ == NULL) {
> +		dev_err(&pdev->dev, "failed to create work queue\n");
> +		err = -ENODEV;
> +		goto probe_release_fw_1;
> +	}
> +
> +	INIT_WORK(&priv->rx_work, omapl_pru_can_rx_wQ);
> +	dev_info(&pdev->dev,
> +		 "%s device registered (trx_irq = %d,  clk = %d)\n",
> +		 DRV_NAME, priv->trx_irq, priv->can.clock.freq);
> +
> +	return 0;
> +
> +probe_release_fw_1:
> +	release_firmware(priv->fw_rx);
> +probe_release_fw:
> +	release_firmware(priv->fw_tx);
> +probe_exit_clk:
> +	clk_put(priv->clk_timer);
> +probe_exit_candev:
> +	if (NULL != ndev)
> +		free_candev(ndev);
> +probe_exit:
> +	return err;
> +}
> +
> +static int __devexit omapl_pru_can_remove(struct platform_device *pdev)
> +{
> +	struct net_device *ndev = platform_get_drvdata(pdev);
> +	struct omapl_pru_can_priv *priv = netdev_priv(ndev);
> +
> +	omapl_pru_can_stop(ndev);
> +
> +	pru_can_emu_exit(priv->dev);
> +	release_firmware(priv->fw_tx);
> +	release_firmware(priv->fw_rx);
> +	clk_put(priv->clk_timer);
> +	flush_workqueue(priv->pru_can_wQ);
> +	destroy_workqueue(priv->pru_can_wQ);
> +	unregister_candev(ndev);
> +	free_candev(ndev);
> +	platform_set_drvdata(pdev, NULL);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int omapl_pru_can_suspend(struct platform_device *pdev,
> +			pm_message_t mesg)
> +{
> +	dev_info(&pdev->dev, "%s not yet implemented\n", __func__);
> +	return 0;
> +}
> +
> +static int omapl_pru_can_resume(struct platform_device *pdev)
> +{
> +	dev_info(&pdev->dev, "%s not yet implemented\n", __func__);
> +	return 0;
> +}
> +#else
> +#define omapl_pru_can_suspend NULL
> +#define omapl_pru_can_resume NULL
> +#endif /* CONFIG_PM */
> +
> +static struct platform_driver omapl_pru_can_driver = {
> +	.probe		= omapl_pru_can_probe,
> +	.remove		= __devexit_p(omapl_pru_can_remove),
> +	.suspend	= omapl_pru_can_suspend,
> +	.resume		= omapl_pru_can_resume,
> +	.driver		= {
> +		.name	= DRV_NAME,
> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +static int __init omapl_pru_can_init(void)
> +{
> +	__can_debug(KERN_INFO DRV_DESC "\n");
> +	return platform_driver_register(&omapl_pru_can_driver);
> +}
> +
> +module_init(omapl_pru_can_init);
> +
> +static void __exit omapl_pru_can_exit(void)
> +{
> +	__can_debug(KERN_INFO DRV_DESC " unloaded\n");
> +	platform_driver_unregister(&omapl_pru_can_driver);
> +}
> +
> +module_exit(omapl_pru_can_exit);
> +
> +MODULE_AUTHOR("Subhasish Ghosh <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("omapl pru CAN netdevice driver");
> diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.c b/drivers/net/can/da8xx_pruss/pruss_can_api.c
> new file mode 100644
> index 0000000..2f7438a
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.c
> @@ -0,0 +1,1227 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Wilfred Felix
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as  published by the
> + * Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
> + * whether express or implied; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#include "pruss_can_api.h"
> +
> +static can_emu_drv_inst gstr_can_inst[ecanmaxinst];
> +
> +/*
> + * pru_can_set_brp()	Updates the  BRP register of PRU0
> + * and PRU1 of OMAP L138. This API will be called by the
> + * Application to updtae the BRP register of PRU0 and PRU1
> + *
> + * param	u16bitrateprescaler		The can bus bitrate
> + * prescaler value be set
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_set_brp(struct device *dev, u16 u16bitrateprescaler)
> +{
> +
> +	u32 u32offset;
> +
> +	if (u16bitrateprescaler > 255) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
> +
> +	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
> +
> +	return 0;
> +
> +}
> +
> +/*
> + * pru_can_set_bit_timing()		Updates the timing register
> + * of PRU0 and PRU1 of OMAP L138. This API will be called by
> + * the Application to updtae the timing register of PRU0 and PRU1
> + *
> + * param	pstrbittiming		Pointer to structure holding
> + * the bit timing values for can bus.
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_set_bit_timing(struct device *dev,
> +		can_bit_timing_consts *pstrbittiming)
> +{
> +
> +	u32 u32offset;
> +	u32 u32serregister;
> +
> +	u32serregister = 0;
> +
> +	if (pstrbittiming == NULL) {
> +		return -1;
> +	}
> +
> +	if ((pstrbittiming->u8syncjumpwidth > PRU_CAN_MAX_SJW) ||
> +	    (pstrbittiming->u8phseg1 > PRU_CAN_MAX_PHSEG1) ||
> +	    (pstrbittiming->u8phseg2 > PRU_CAN_MAX_PHSEG2)) {
> +		return -1;
> +	}
> +
> +	u32serregister = u32serregister |
> +			((pstrbittiming->u8syncjumpwidth << 7) |
> +			(pstrbittiming->u8phseg1 << 3) |
> +			(pstrbittiming->u8phseg2));
> +
> +	u32offset = (PRU_CAN_TX_TIMING_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1);
> +
> +	u32offset = (PRU_CAN_RX_TIMING_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1);
> +
> +	return 0;
> +}
> +
> +
> +/*
> + * pru_can_calc_timing()
> + * Updates the  timing values of PRU0 and PRU1 of OMAP L138.
> + * This API will be called by the
> + * Application to updtae the timing values of PRU0 and PRU1
> + *
> + * return   SUCCESS or FAILURE
> + */
> +
> +s16 pru_can_calc_timing(struct device *dev, u32 pru_freq, u32 bit_rate)
> +{
> +	u16 u16phaseseg1;
> +	u16 u16phaseseg2;
> +	u32 u32offset;
> +	u32 u32timing_value;
> +	u32 u32setup_value;
> +	u32timing_value = TIMER_CLK_FREQ / bit_rate;
> +	u32offset = (PRU_CAN_TIMING_VAL_TX);
> +	pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4);
> +	pruss_readl(dev, u32offset, (u32 *) &u32timing_value, 4);
> +	u32setup_value =
> +	    (GPIO_SETUP_DELAY * (pru_freq / 1000000) / 1000) /
> +	    DELAY_LOOP_LENGTH;
> +	u32offset = (PRU_CAN_TIMING_VAL_TX_SJW);
> +	pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4);
> +	u16phaseseg1 = (u16) (u32timing_value / 2);
> +	u16phaseseg2 = u32timing_value - u16phaseseg1;
> +	u16phaseseg1 -= TIMER_SETUP_DELAY;
> +	u16phaseseg2 -= TIMER_SETUP_DELAY;
> +	u32setup_value = (u16phaseseg1 << 16) | u16phaseseg2;
> +	u32offset = (PRU_CAN_TIMING_VAL_RX);
> +	pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4);
> +	u32offset = (PRU_CAN_TIMING_VAL_RX + 4);
> +	pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4);
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_write_data_to_mailbox()
> + * Updates the transmit mailboxes of PRU1 of OMAP L138.
> + * This API will be called by the Application to update
> + * the transmit mailboxes of PRU1
> + *
> + * param  pu16canframedata	Can mailbox data buffer
> + *
> + * param  u8mailboxnum		Mailbox to be updated
> + *
> + * return SUCCESS or FAILURE
> + */
> +s16 pru_can_write_data_to_mailbox(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl)
> +{
> +	s16 s16subrtnretval;
> +	u32 u32offset;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
> +	case 0:
> +		u32offset = (PRU_CAN_TX_MAILBOX0);
> +		break;
> +	case 1:
> +		u32offset = (PRU_CAN_TX_MAILBOX1);
> +		break;
> +	case 2:
> +		u32offset = (PRU_CAN_TX_MAILBOX2);
> +		break;
> +	case 3:
> +		u32offset = (PRU_CAN_TX_MAILBOX3);
> +		break;
> +	case 4:
> +		u32offset = (PRU_CAN_TX_MAILBOX4);
> +		break;
> +	case 5:
> +		u32offset = (PRU_CAN_TX_MAILBOX5);
> +		break;
> +	case 6:
> +		u32offset = (PRU_CAN_TX_MAILBOX6);
> +		break;
> +	case 7:
> +		u32offset = (PRU_CAN_TX_MAILBOX7);
> +		break;
> +	default:
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +		(u32 *) &(pstremuapphndl->strcanmailbox), 4);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_data_from_mailbox()
> + * Receive data from the receive mailboxes of PRU0  of OMAP L138.
> + * This API will be called by the Application to get data from
> + * the receive mailboxes of PRU0
> + *
> + * param  pu16canframedata	Can mailbox data buffer
> + *
> + * param  u8mailboxnum		Mailbox to be updated
> + *
> + * return SUCCESS or FAILURE
> + */
> +s16 pru_can_get_data_from_mailbox(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	s16 s16subrtnretval;
> +	u32 u32offset;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
> +	case 0:
> +		u32offset = (PRU_CAN_RX_MAILBOX0);
> +		break;
> +	case 1:
> +		u32offset = (PRU_CAN_RX_MAILBOX1);
> +		break;
> +	case 2:
> +		u32offset = (PRU_CAN_RX_MAILBOX2);
> +		break;
> +	case 3:
> +		u32offset = (PRU_CAN_RX_MAILBOX3);
> +		break;
> +	case 4:
> +		u32offset = (PRU_CAN_RX_MAILBOX4);
> +		break;
> +	case 5:
> +		u32offset = (PRU_CAN_RX_MAILBOX5);
> +		break;
> +	case 6:
> +		u32offset = (PRU_CAN_RX_MAILBOX6);
> +		break;
> +	case 7:
> +		u32offset = (PRU_CAN_RX_MAILBOX7);
> +		break;
> +	case 8:
> +		u32offset = (PRU_CAN_RX_MAILBOX8);
> +		break;
> +	default:
> +		return -1;
> +	}
> +
> +	s16subrtnretval =
> +	    pruss_readl(dev, u32offset,
> +		  (u32 *) &(pstremuapphndl->strcanmailbox),
> +				  4);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * pru_can_receive_id_map()
> + * Receive mailboxes ID Mapping of PRU0  of OMAP L138.
> + * This API will be called by the Application
> + * to map the IDs  to receive mailboxes of PRU0
> + *
> + * param  u32nodeid		Can node ID
> + *
> + * param  ecanmailboxno		Mailbox to be mapped
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_rx_id_map(struct device *dev, u32 u32nodeid,
> +		can_mailbox_number ecanmailboxno)
> +{
> +
> +	pruss_writel(dev, (PRU_CAN_ID_MAP +
> +		(((u8) ecanmailboxno) * 4)), (u32 *) &u32nodeid, 1);
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_intr_status()
> + * Gets the interrupts status register value.
> + * This API will be called by the Application
> + * to get the interrupts status register value
> + *
> + * param  u8prunumber	PRU number for which IntStatusReg
> + * has to be read
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_intr_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	s16 s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER);
> +	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER);
> +	} else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32interruptstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_global_status()	Gets the globalstatus
> + * register value. This API will be called by the Application
> + * to  get the global status register value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_global_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	int s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
> +	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
> +	} else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32globalstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_get_mailbox_status()		Gets the mailbox status
> + * register value. This API will be called by the Application
> + * to get the mailbox status register value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_mailbox_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	s16 s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		switch (pstremuapphndl->ecanmailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER);
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER);
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER);
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER);
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER);
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER);
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER);
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER);
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +
> +	else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		switch (pstremuapphndl->ecanmailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER);
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER);
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER);
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER);
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER);
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER);
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER);
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER);
> +			break;
> +		case 8:
> +			u32offset = (PRU_CAN_RX_MAILBOX8_STATUS_REGISTER);
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +
> +	else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32mailboxstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag,
> +				can_transfer_direction ecan_trx)
> +{
> +	u32 u32offset;
> +	u32 u32value;
> +
> +	if (ecan_trx == ecantransmit) {
> +		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
> +		pruss_readl(dev, u32offset, &u32value, 1);
> +		if (btransfer_flag == true) {
> +			u32value &= 0x1F;
> +			u32value |= 0x80;
> +		} else {
> +			u32value &= 0x7F;
> +		}
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +	} else if (ecan_trx == ecanreceive) {
> +		u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER);
> +		pruss_readl(dev, u32offset, &u32value, 1);
> +		if (btransfer_flag == true) {
> +			u32value &= 0x1F;
> +			u32value |= 0x40;
> +		} else {
> +			u32value &= 0xBF;
> +		}
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +		u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER);
> +		pruss_writel(dev, u32offset, &u32value, 1);
> +	} else
> +		return -1;
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_config_mode_set()		Sets the timing value
> + * for data transfer. This API will be called by the Application
> + * to set timing valus for data transfer
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_config_mode_set(struct device *dev, bool bconfigmodeflag)
> +{
> +
> +	u32 u32bitrateprescaler;
> +	u32 u32canbittiming;
> +
> +	pruss_readl(dev, (PRU_CAN_TX_CLOCK_BRP_REGISTER),
> +			(u32 *) &u32bitrateprescaler, 1);
> +	pruss_readl(dev, (PRU_CAN_TX_TIMING_REGISTER),
> +			(u32 *) &u32canbittiming, 1);
> +
> +	if (bconfigmodeflag == 1) {
> +		pru_can_calc_timing(dev, u32canbittiming, u32bitrateprescaler);
> +	}
> +
> +	else {
> +		pru_can_calc_timing(dev, 0, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * pru_can_emu_init()		Initializes the Can
> + * Emulation Parameters. This API will be called by the Application
> + * to Initialize the Can Emulation Parameters
> + *
> + * param    u32pruclock         PRU Clock value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_init(struct device *dev, u32 u32pruclock)
> +{
> +	u32 u32offset;
> +	u32 u32value;
> +	s16 s16subrtnretval = -1;
> +	u8 u8loop;
> +
> +	for (u8loop = 0; u8loop < (u8) ecanmaxinst; u8loop++) {
> +		gstr_can_inst[u8loop].bcaninststate = (bool) 0;
> +		gstr_can_inst[u8loop].ecantransferdirection =
> +		    (can_transfer_direction) 0;
> +		gstr_can_inst[u8loop].u32apphandlerptr = 0;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_INTERRUPT_MASK_REGISTER & 0xFFFF);
> +	u32value = 0x00004000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval =
> +	    pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000001;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_TIMING_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_POLARITY0 & 0xFFFF);
> +	u32value = 0xFFFFFFFF;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_POLARITY1 & 0xFFFF);
> +	u32value = 0xFFFFFFFF;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_TYPE0 & 0xFFFF);
> +	u32value = 0x1C000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_TYPE1 & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HSTINTENIDXCLR & 0xFFFF);
> +	u32value = 0x0;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_GLBLEN & 0xFFFF);
> +	u32value = 0x1;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	/* tx intr map arm->pru */
> +	u32offset = (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
> +	u32value = 0x0;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTMAP0 & 0xFFFF);
> +	u32value = 0x03020100;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTMAP1 & 0xFFFF);
> +	u32value = 0x07060504;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTMAP2 & 0xFFFF);
> +	u32value = 0x0000908;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_CHANMAP0 & 0xFFFF);
> +	u32value = 0;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_CHANMAP8 & 0xFFFF);
> +	u32value = 0x00020200;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 19;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 19;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 18;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 18;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 34;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 34;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRUSS_INTC_HOSTINTEN & 0xFFFF);
> +	u32value = 0x5;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +/* PRU0 - Rx Internal Registers Initializations */
> +
> +	u32offset = (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_INTERRUPT_MASK_REGISTER & 0xFFFF);
> +	u32value = 0x00004000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x0000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_ERROR_COUNTER_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_TIMING_REGISTER & 0xFFFF);
> +	u32value = 0x0000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +
> +/*
> + * pru_can_emu_open()		Opens the can emu for
> + * application to use. This API will be called by the Application
> + * to Open the can emu for application to use.
> + *
> + * param	pstremuapphndl	Pointer to application handler
> + * structure
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_open(struct device *dev, can_emu_app_hndl *pstremuapphndl)
> +{
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +
> +	if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 1) {
> +		return -1;
> +	}
> +
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].
> +					bcaninststate = (bool)1;
> +	gstr_can_inst[(u8) pstremuapphndl->
> +		ecaninstance].ecantransferdirection =
> +		(can_transfer_direction)(u8)pstremuapphndl->ecantransferdirection;
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].
> +		u32apphandlerptr = (u32) pstremuapphndl;
> +
> +	return 0;
> +}
> +
> +
> +/*
> + * brief    pru_can_emu_close()	Closes the can emu for other
> + * applications to use. This API will be called by the Application to Close
> + * the can emu for other applications to use
> + *
> + * param	pstremuapphndl	Pointer to application handler structure
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_close(struct device *dev, can_emu_app_hndl *pstremuapphndl)
> +{
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}
> +	if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 0) {
> +		return -1;
> +	}
> +	if ((u32) pstremuapphndl != gstr_can_inst[(u8) pstremuapphndl->
> +			ecaninstance].u32apphandlerptr){
> +		return -1;
> +	}
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].bcaninststate
> +		= (bool) 0;
> +	gstr_can_inst[(u8) pstremuapphndl->
> +	ecaninstance].ecantransferdirection = (can_transfer_direction) 0;
> +	gstr_can_inst[(u8) pstremuapphndl->ecaninstance].u32apphandlerptr = 0;
> +
> +	return 0;
> +}
> +
> +/*
> + * brief    pru_can_emu_exit()	Diables all the PRUs
> + * This API will be called by the Application to disable all PRUs
> + * param	None
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_exit(struct device *dev)
> +{
> +	s16 s16subrtnretval;
> +
> +	s16subrtnretval = pruss_disable(dev, CAN_RX_PRU_0);
> +	if (s16subrtnretval == -1)
> +		return -1;
> +	s16subrtnretval = pruss_disable(dev, CAN_TX_PRU_1);
> +	if (s16subrtnretval == -1)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +s16 pru_can_emu_sreset(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +s16 pru_can_tx(struct device *dev, u8 u8mailboxnumber, u8 u8prunumber)
> +{
> +	u32 u32offset = 0;
> +	u32 u32value = 0;
> +	s16 s16subrtnretval = -1;
> +
> +	if (DA8XX_PRUCORE_1 == u8prunumber) {
> +		switch (u8mailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		default:
> +			return -1;
> +		}
> +	} else {
> +
> +		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF);
> +		u32value = 0x00000000;
> +		s16subrtnretval = pruss_readl(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +		if (s16subrtnretval == -1) {
> +			return -1;
> +		}
> +		u32value = u32value & ~(1 << u8mailboxnumber);
> +		s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +		if (s16subrtnretval == -1) {
> +			return -1;
> +		}
> +
> +		switch (u8mailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 3:
> +			u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 4:
> +			u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 5:
> +			u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 6:
> +			u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 7:
> +			u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000000;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		default:
> +			return -1;
> +		}
> +	}
> +	return 0;
> +}
> +
> +s16 pru_can_start_abort_tx(struct device *dev, bool bcantransmitabortflag)
> +{
> +	u32 u32offset;
> +	u32 u32value;
> +	s16 s16subrtnretval;
> +	u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +
> +	u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +
> +	u32offset = (PRUSS_INTC_STATIDXSET & 0xFFFF);
> +	u32value = 32;
> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +s16 pru_can_mask_ints(struct device *dev, u32 int_mask)
> +{
> +	return 0;
> +}
> +
> +int pru_can_get_error_cnt(struct device *dev, u8 u8prunumber)
> +{
> +	return 0;
> +}
> +
> +int pru_can_get_intc_status(struct device *dev)
> +{
> +	u32 u32offset = 0;
> +	u32 u32getvalue = 0;
> +	u32 u32clrvalue = 0;
> +
> +	u32offset = (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
> +	pruss_readl(dev, u32offset, (u32 *) &u32getvalue, 1);
> +
> +	if (u32getvalue & 4)
> +		u32clrvalue = 34;	/* CLR Event 34 */
> +
> +	if (u32getvalue & 2)
> +		u32clrvalue = 33;	/* CLR Event 33  */
> +
> +	if (u32clrvalue) {
> +		u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +		pruss_writel(dev, u32offset, &u32clrvalue, 1);
> +	} else
> +		return -1;
> +
> +	return u32getvalue;
> +}
> diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.h b/drivers/net/can/da8xx_pruss/pruss_can_api.h
> new file mode 100644
> index 0000000..7550456
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.h
> @@ -0,0 +1,290 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Ganeshan N
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as  published by the
> + * Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
> + * whether express or implied; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#ifndef _PRU_CAN_API_H_
> +#define _PRU_CAN_API_H_
> +
> +#include <linux/types.h>
> +#include <linux/mfd/pruss/da8xx_pru.h>
> +
> +
> +#define CAN_BIT_TIMINGS			(0x273)
> +
> +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */
> +#define	TIMER_CLK_FREQ			132000000

any change to get this from a clk_dev?

> +
> +#define TIMER_SETUP_DELAY		14
> +#define GPIO_SETUP_DELAY		150
> +
> +#define CAN_RX_PRU_0			PRUSS_NUM0
> +#define CAN_TX_PRU_1			PRUSS_NUM1
> +
> +/* Number of Instruction in the Delay loop */
> +#define DELAY_LOOP_LENGTH		2

please create a struct describing your register layout.

> +
> +#define PRU1_BASE_ADDR			0x2000
> +
> +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER		(PRU1_BASE_ADDR)
> +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x04)
> +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER		(PRU1_BASE_ADDR	+ 0x08)
> +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x0C)
> +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x10)
> +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x14)
> +#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x18)
> +#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x1C)
> +#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x20)
> +#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x24)
> +#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x28)
> +#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x2C)

please use an array for the mailbox status register.

> +#define PRU_CAN_TX_ERROR_COUNTER_REGISTER		(PRU1_BASE_ADDR	+ 0x30)
> +#define PRU_CAN_TX_TIMING_REGISTER			(PRU1_BASE_ADDR	+ 0x34)
> +#define PRU_CAN_TX_CLOCK_BRP_REGISTER			(PRU1_BASE_ADDR	+ 0x38)
> +
> +#define PRU_CAN_TX_MAILBOX0				(PRU1_BASE_ADDR	+ 0x40)
> +#define PRU_CAN_TX_MAILBOX1				(PRU1_BASE_ADDR	+ 0x50)
> +#define PRU_CAN_TX_MAILBOX2				(PRU1_BASE_ADDR	+ 0x60)
> +#define PRU_CAN_TX_MAILBOX3				(PRU1_BASE_ADDR	+ 0x70)
> +#define PRU_CAN_TX_MAILBOX4				(PRU1_BASE_ADDR	+ 0x80)
> +#define PRU_CAN_TX_MAILBOX5				(PRU1_BASE_ADDR	+ 0x90)
> +#define PRU_CAN_TX_MAILBOX6				(PRU1_BASE_ADDR	+ 0xA0)
> +#define PRU_CAN_TX_MAILBOX7				(PRU1_BASE_ADDR	+ 0xB0)

also use an array here

> +
> +#define PRU_CAN_TIMING_VAL_TX				(PRU1_BASE_ADDR	+ 0xC0)
> +#define PRU_CAN_TIMING_VAL_TX_SJW			(PRU1_BASE_ADDR	+ 0xC4)
> +#define PRU_CAN_TRANSMIT_FRAME				(PRU1_BASE_ADDR	+ 0xE0)
> +
> +#define PRU0_BASE_ADDR					0
> +
> +#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER		(PRU0_BASE_ADDR)
> +#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x04)
> +#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER		(PRU0_BASE_ADDR	+ 0x08)
> +#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x0C)
> +#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x10)
> +#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x14)
> +#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x18)
> +#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x1C)
> +#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x20)
> +#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x24)
> +#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x28)
> +#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x2C)
> +#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER		(PRU0_BASE_ADDR	+ 0x30)

...array

> +#define PRU_CAN_RX_ERROR_COUNTER_REGISTER		(PRU0_BASE_ADDR	+ 0x34)
> +#define PRU_CAN_RX_TIMING_REGISTER			(PRU0_BASE_ADDR	+ 0x38)
> +#define PRU_CAN_RX_CLOCK_BRP_REGISTER			(PRU0_BASE_ADDR	+ 0x3C)
> +
> +#define PRU_CAN_RX_MAILBOX0				(PRU0_BASE_ADDR	+ 0x40)
> +#define PRU_CAN_RX_MAILBOX1				(PRU0_BASE_ADDR	+ 0x50)
> +#define PRU_CAN_RX_MAILBOX2				(PRU0_BASE_ADDR	+ 0x60)
> +#define PRU_CAN_RX_MAILBOX3				(PRU0_BASE_ADDR	+ 0x70)
> +#define PRU_CAN_RX_MAILBOX4				(PRU0_BASE_ADDR	+ 0x80)
> +#define PRU_CAN_RX_MAILBOX5				(PRU0_BASE_ADDR	+ 0x90)
> +#define PRU_CAN_RX_MAILBOX6				(PRU0_BASE_ADDR	+ 0xA0)
> +#define PRU_CAN_RX_MAILBOX7				(PRU0_BASE_ADDR	+ 0xB0)
> +#define PRU_CAN_RX_MAILBOX8				(PRU0_BASE_ADDR	+ 0xC0)

..array

The rx and tx register set look quite similar. Is it intended that you
have 8 tx but 9 rx mailboxes? Anyway....make a struct descriing the
register set and use it twice, one for rx and one for tx.

> +
> +#define PRU_CAN_TIMING_VAL_RX				(PRU0_BASE_ADDR	+ 0xD0)
> +#define PRU_CAN_RECEIVE_FRAME				(PRU0_BASE_ADDR	+ 0xD4)
> +#define PRU_CAN_ID_MAP					(PRU0_BASE_ADDR	+ 0xF0)
> +
> +#define PRU_CAN_ERROR_ACTIVE				128
> +
> +#define CAN_ACK_FAILED					0xE
> +#define CAN_ARBTR_FAIL					0xD
> +#define CAN_BIT_ERROR					0xC
> +#define CAN_TRANSMISSION_SUCCESS			0xA
> +
> +#define STD_DATA_FRAME					0x1
> +#define EXTD_DATA_FRAME					0x2
> +#define STD_REMOTE_FRAME				0x3
> +#define EXTD_REMOTE_FRAME				0x4
> +
> +#define PRU_CAN_MAX_SJW					8
> +#define PRU_CAN_MAX_PHSEG1				25
> +#define PRU_CAN_MAX_PHSEG2				25
> +
> +#define DA8XX_PRUCANCORE_0_REGS				0x7000
> +#define DA8XX_PRUCANCORE_1_REGS				0x7800
> +#define PRU0_PROG_RAM_START_OFFSET			0x8000
> +#define PRU1_PROG_RAM_START_OFFSET			0xC000
> +#define PRU_CAN_INIT_MAX_TIMEOUT			0xFF
> +
> +typedef enum {
> +	ecaninst0 = 0,
> +	ecaninst1,
> +	ecanmaxinst
> +} can_instance_enum;

seens unused
> +
> +typedef enum {
> +	ecanmailbox0 = 0,
> +	ecanmailbox1,
> +	ecanmailbox2,
> +	ecanmailbox3,
> +	ecanmailbox4,
> +	ecanmailbox5,
> +	ecanmailbox6,
> +	ecanmailbox7
> +} can_mailbox_number;

unused, too
> +
> +typedef enum {
> +	ecandirectioninit = 0,
> +	ecantransmit,
> +	ecanreceive
> +} can_transfer_direction;

please add a common prefix and please write them uppsercase.

> +
> +typedef struct {
> +	u16 u16extendedidentifier;
> +	u16 u16baseidentifier;
> +	u8 u8data7;
> +	u8 u8data6;
> +	u8 u8data5;
> +	u8 u8data4;
> +	u8 u8data3;
> +	u8 u8data2;
> +	u8 u8data1;
> +	u8 u8data0;

use an array for the data.

> +	u16 u16datalength;
> +	u16 u16crc;
> +} can_mail_box_structure;
> +
> +typedef struct {
> +	can_transfer_direction ecantransferdirection;
> +} can_mailbox_config;
> +
> +typedef struct {
> +	can_instance_enum ecaninstance;
> +	can_transfer_direction ecantransferdirection;
> +	can_mail_box_structure strcanmailbox;
> +	can_mailbox_number ecanmailboxnumber;
> +	u8 u8prunumber;
> +	u32 u32globalstatus;
> +	u32 u32interruptstatus;
> +	u32 u32mailboxstatus;
> +} can_emu_app_hndl;

You already have defines your priv. No need for further structs.

> +
> +typedef struct {
> +	bool bcaninststate;
> +	can_transfer_direction ecantransferdirection;
> +	u32 u32apphandlerptr;
> +} can_emu_drv_inst;

dito

> +
> +typedef struct {
> +	u8 u8syncjumpwidth;
> +	u8 u8phseg1;
> +	u8 u8phseg2;
> +} can_bit_timing_consts;
> +
> +/* Field Definition Macros  */
> +
> +/* CONTROL */
>

get rid of all the following functions, you don't need that extra layer
in the can driver.

> +/*
> + * pru_can_set_brp() Updates the  BRP register of PRU.
> + */
> +s16 pru_can_set_brp(struct device *dev, u16 u16prescaler);
> +
> +/*
> + * pru_can_set_bit_timing() Updates the  timing register of PRU
> + */
> +s16 pru_can_set_bit_timing(struct device *dev,
> +			can_bit_timing_consts *pstrbittiming);
> +
> +/*
> + * pru_can_calc_timing() Updates the timing values of PRU
> + */
> +s16 pru_can_calc_timing(struct device *dev,
> +			u32 u32bittiming, u32 u32bitrateprescaler);
> +
> +/*
> + * pru_can_write_data_to_mailbox() Updates the transmit mailboxes of PRU1
> + */
> +s16 pru_can_write_data_to_mailbox(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +/*
> + * pru_can_get_data_from_mailbox() Receive data from receive mailboxes
> + */
> +s16 pru_can_get_data_from_mailbox(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +/*
> + * pru_can_rx_id_map() Receive mailboxes ID Mapping of PRU0
> + */
> +s16 pru_can_rx_id_map(struct device *dev,
> +			u32 u32nodeid, can_mailbox_number ecanmailboxno);
> +
> +/*
> + *pru_can_get_intr_status() Get interrupts status register value
> + */
> +s16 pru_can_get_intr_status(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +
> +/*
> + * pru_can_get_global_status() Get the globalstatus register value
> + */
> +s16 pru_can_get_global_status(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +/*
> + * pru_can_get_mailbox_status() Get mailbox status reg value
> + */
> +s16 pru_can_get_mailbox_status(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +/*
> + * pru_can_configuration_mode_set() Sets timing val for data transfer
> + */
> +s16 pru_can_config_mode_set(struct device *dev,
> +			bool bconfig_modeflag);
> +
> +/*
> + * pru_can_emu_init() Initializes Can Emulation Parameters
> + */
> +s16 pru_can_emu_init(struct device *dev,
> +			u32 u32pruclock);
> +
> +/*
> + * pru_can_emu_open() Opens can emu for application to use
> + */
> +s16 pru_can_emu_open(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +/*
> + * pru_can_emu_close() Closes can emu for applications to use
> + */
> +s16 pru_can_emu_close(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl);
> +
> +/*
> + * pru_can_emu_exit() Diables all the PRUs
> + */
> +s16 pru_can_emu_exit(struct device *dev);
> +
> +s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag,
> +			 can_transfer_direction ecan_trx);
> +
> +s16 pru_can_emu_sreset(struct device *dev);
> +
> +s16 pru_can_tx(struct device *dev,
> +			u8 u8mailboxnumber, u8 u8prunumber);
> +
> +s16 pru_can_start_abort_tx(struct device *dev,
> +			bool btxabort_flag);
> +
> +s16 pru_can_mask_ints(struct device *dev, u32 int_mask);
> +
> +s32 pru_can_get_error_cnt(struct device *dev, u8 u8prunumber);
> +
> +s32 pru_can_get_intc_status(struct device *dev);
> +#endif

regards, Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-11 15:06     ` Kurt Van Dijck
@ 2011-02-14  4:54       ` Subhasish Ghosh
  2011-02-14  7:23         ` Wolfgang Grandegger
  0 siblings, 1 reply; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-14  4:54 UTC (permalink / raw)
  To: Kurt Van Dijck
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Wolfgang Grandegger, open list:CAN NETWORK DRIVERS,
	open list:CAN NETWORK DRIVERS, open list

Hello,

I had a discussion regarding this with Wolfgang:

http://www.mail-archive.com/socketcan-users@lists.berlios.de/msg00324.html

The problem here is that we must configure the mailbox ID's and this support 
is not available in the socketCan sub-system.

--------------------------------------------------
From: "Kurt Van Dijck" <kurt.van.dijck@eia.be>
Sent: Friday, February 11, 2011 8:36 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<linux-arm-kernel@lists.infradead.org>; <m-watkins@ti.com>; 
<nsekhar@ti.com>; <sachi@mistralsolutions.com>; "Wolfgang Grandegger" 
<wg@grandegger.com>; "open list:CAN NETWORK DRIVERS" 
<socketcan-core@lists.berlios.de>; "open list:CAN NETWORK DRIVERS" 
<netdev@vger.kernel.org>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.

> On Fri, Feb 11, 2011 at 08:21:28PM +0530, Subhasish Ghosh wrote:
>> +config DA8XX_PRU_CANID_MBX0
>> + hex "CANID for mailbox 0"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 0
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX1
>> + hex "CANID for mailbox 1"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 1
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX2
>> + hex "CANID for mailbox 2"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 2
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX3
>> + hex "CANID for mailbox 3"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 3
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX4
>> + hex "CANID for mailbox 4"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 4
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX5
>> + hex "CANID for mailbox 5"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 5
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX6
>> + hex "CANID for mailbox 6"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 6
>> + Default value is set to 0x123, change this as required.
>> +
>> +config DA8XX_PRU_CANID_MBX7
>> + hex "CANID for mailbox 7"
>> + depends on CAN_TI_DA8XX_PRU
>> + default "0x123"
>> + ---help---
>> + Enter the CANID for mailbox 7
>> + Default value is set to 0x123, change this as required.
> Why is filling the mailboxes the job of kernel config?
>
> Regards,
> Kurt 

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  4:54       ` Subhasish Ghosh
@ 2011-02-14  7:23         ` Wolfgang Grandegger
       [not found]           ` <4D58D854.5090503-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
  2011-02-14  8:45           ` Subhasish Ghosh
  0 siblings, 2 replies; 21+ messages in thread
From: Wolfgang Grandegger @ 2011-02-14  7:23 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/14/2011 05:54 AM, Subhasish Ghosh wrote:
> Hello,
> 
> I had a discussion regarding this with Wolfgang:
> 
> http://www.mail-archive.com/socketcan-users-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org/msg00324.html
> 
> The problem here is that we must configure the mailbox ID's and this
> support is not available in the socketCan sub-system.

To understand you correctly. A mailbox (or message object) can *only*
receive messages with the pre-programmed CAN id? Isn't there a chance to
receive all or a range of CAN ids? That's a very unusual piece of
hardware. Anyway, using kernel configuration parameters to define the
CAN id's would be the less flexible method. The user will not have a
chance to change them at run-time. Using SysFS files would already be
much better.

Wolfgang.

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]           ` <4D58D854.5090503-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
@ 2011-02-14  7:42             ` Kurt Van Dijck
  0 siblings, 0 replies; 21+ messages in thread
From: Kurt Van Dijck @ 2011-02-14  7:42 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	Subhasish Ghosh, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, Feb 14, 2011 at 08:23:00AM +0100, Wolfgang Grandegger wrote:
> On 02/14/2011 05:54 AM, Subhasish Ghosh wrote:
> > Hello,
> > 
> > I had a discussion regarding this with Wolfgang:
> > 
> > http://www.mail-archive.com/socketcan-users-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org/msg00324.html
> > 
> > The problem here is that we must configure the mailbox ID's and this
> > support is not available in the socketCan sub-system.
> 
> Using SysFS files would already be much better.
Ack.

Kurt

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  7:23         ` Wolfgang Grandegger
       [not found]           ` <4D58D854.5090503-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
@ 2011-02-14  8:45           ` Subhasish Ghosh
  2011-02-14  9:28             ` Wolfgang Grandegger
  2011-02-14  9:35             ` Marc Kleine-Budde
  1 sibling, 2 replies; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-14  8:45 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: Kurt Van Dijck, davinci-linux-open-source, linux-arm-kernel,
	m-watkins, nsekhar, sachi, open list:CAN NETWORK DRIVERS,
	open list:CAN NETWORK DRIVERS, open list

That is correct, we receive only pre-programmed CAN ids and "all" or "range" 
implementation is not there in the PRU firmware.
Will check the sysfs option and update.

--------------------------------------------------
From: "Wolfgang Grandegger" <wg@grandegger.com>
Sent: Monday, February 14, 2011 12:53 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: "Kurt Van Dijck" <kurt.van.dijck@eia.be>; 
<davinci-linux-open-source@linux.davincidsp.com>; 
<linux-arm-kernel@lists.infradead.org>; <m-watkins@ti.com>; 
<nsekhar@ti.com>; <sachi@mistralsolutions.com>; "open list:CAN NETWORK 
DRIVERS" <socketcan-core@lists.berlios.de>; "open list:CAN NETWORK DRIVERS" 
<netdev@vger.kernel.org>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.

> On 02/14/2011 05:54 AM, Subhasish Ghosh wrote:
>> Hello,
>>
>> I had a discussion regarding this with Wolfgang:
>>
>> http://www.mail-archive.com/socketcan-users@lists.berlios.de/msg00324.html
>>
>> The problem here is that we must configure the mailbox ID's and this
>> support is not available in the socketCan sub-system.
>
> To understand you correctly. A mailbox (or message object) can *only*
> receive messages with the pre-programmed CAN id? Isn't there a chance to
> receive all or a range of CAN ids? That's a very unusual piece of
> hardware. Anyway, using kernel configuration parameters to define the
> CAN id's would be the less flexible method. The user will not have a
> chance to change them at run-time. Using SysFS files would already be
> much better.
>
> Wolfgang. 


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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  8:45           ` Subhasish Ghosh
@ 2011-02-14  9:28             ` Wolfgang Grandegger
  2011-02-14  9:35             ` Marc Kleine-Budde
  1 sibling, 0 replies; 21+ messages in thread
From: Wolfgang Grandegger @ 2011-02-14  9:28 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi Subhasish,

On 02/14/2011 09:45 AM, Subhasish Ghosh wrote:
> That is correct, we receive only pre-programmed CAN ids and "all" or
> "range" implementation is not there in the PRU firmware.

I'm curious about that CAN hardware and firmware. I found a nice block
diagram in [PATCH 0/13]:

http://marc.info/?l=linux-arm-kernel&m=129743511311286&w=4

So, one PRU is used for TX and the second for RX. Who is providing the
firmware you are using? Wouldn't it be possible to provide a firmware
for RX using just one message object (mailbox) with some buffering or
fifo? That would fit much better the SocketCAN approach favoring Basic
CAN controllers (in contrast to Full CAN [1]). And such an
implementation seems even simpler too me requiring less PRU resources.
And how about RTR and Extended CAN IDs? Is that supported?

Thanks,

Wolfgang.

[1] http://www.kvaser.com/en/about-can/the-can-protocol/18.html

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  8:45           ` Subhasish Ghosh
  2011-02-14  9:28             ` Wolfgang Grandegger
@ 2011-02-14  9:35             ` Marc Kleine-Budde
       [not found]               ` <4D58F77B.9080005-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  1 sibling, 1 reply; 21+ messages in thread
From: Marc Kleine-Budde @ 2011-02-14  9:35 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, Wolfgang Grandegger, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


[-- Attachment #1.1: Type: text/plain, Size: 613 bytes --]

Hello,

On 02/14/2011 09:45 AM, Subhasish Ghosh wrote:
> That is correct, we receive only pre-programmed CAN ids and "all" or
> "range" implementation is not there in the PRU firmware.

I'd really like to see that you add a "all" implementation to the
firmware. Or even better use the standard id/mask approach.

cheers, Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]               ` <4D58F77B.9080005-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2011-02-14 13:15                 ` Subhasish Ghosh
  2011-02-14 13:33                   ` Marc Kleine-Budde
  2011-02-14 13:42                   ` Wolfgang Grandegger
  0 siblings, 2 replies; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-14 13:15 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	open list:CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	open list:CAN NETWORK DRIVERS, Wolfgang Grandegger,
	m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hello,

The problem with the "all" implementation is that it hogs the ARM/DSP 
heavily and that's the reason why we specifically avoided this in our 
firmware design.
Hence, implementing this condition spoils the whole purpose of the PRU!!

--------------------------------------------------
From: "Marc Kleine-Budde" <mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Sent: Monday, February 14, 2011 3:05 PM
To: "Subhasish Ghosh" <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
Cc: "Wolfgang Grandegger" <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>; "Kurt Van Dijck" 
<kurt.van.dijck-/BeEPy95v10@public.gmane.org>; <davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org>; 
<linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>; <m-watkins-l0cyMroinI0@public.gmane.org>; 
<nsekhar-l0cyMroinI0@public.gmane.org>; <sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>; "open list:CAN NETWORK 
DRIVERS" <socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org>; "open list:CAN NETWORK DRIVERS" 
<netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>; "open list" <linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.

Hello,

On 02/14/2011 09:45 AM, Subhasish Ghosh wrote:
> That is correct, we receive only pre-programmed CAN ids and "all" or
> "range" implementation is not there in the PRU firmware.

I'd really like to see that you add a "all" implementation to the
firmware. Or even better use the standard id/mask approach.

cheers, Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   | 

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14 13:15                 ` Subhasish Ghosh
@ 2011-02-14 13:33                   ` Marc Kleine-Budde
  2011-02-14 13:42                   ` Wolfgang Grandegger
  1 sibling, 0 replies; 21+ messages in thread
From: Marc Kleine-Budde @ 2011-02-14 13:33 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, Wolfgang Grandegger, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


[-- Attachment #1.1: Type: text/plain, Size: 1296 bytes --]

On 02/14/2011 02:15 PM, Subhasish Ghosh wrote:
> Hello,
> 
> The problem with the "all" implementation is that it hogs the ARM/DSP
> heavily and that's the reason why we specifically avoided this in our
> firmware design.
> Hence, implementing this condition spoils the whole purpose of the PRU!!

What about implementing the standard id/mask approach?

if (canid & mask == id & mask)
	aceept();
else
	discard();

To keep the hot-path as small as possible, the id & mask operation is
done during setup, only one. This is probably just an additional "and"
operation (the "& mask"). This opens the way to act like a normal can
controller.

As long as we don't have any support for hardware filters in socketcan,
it's a good choice to use sysfs to configure your filters.

Have a look at [1] and [2] for how to use sysfs files.

cheers, Marc

[1]
http://git.kernel.org/linus/3a5655a5b545e9647c3437473ee3d815fe1b9050

[2]
http://git.kernel.org/linus/fef52b0171dfd7dd9b85c9cc201bd433b42a8ded

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14 13:15                 ` Subhasish Ghosh
  2011-02-14 13:33                   ` Marc Kleine-Budde
@ 2011-02-14 13:42                   ` Wolfgang Grandegger
  1 sibling, 0 replies; 21+ messages in thread
From: Wolfgang Grandegger @ 2011-02-14 13:42 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, Marc Kleine-Budde, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/14/2011 02:15 PM, Subhasish Ghosh wrote:
> Hello,
> 
> The problem with the "all" implementation is that it hogs the ARM/DSP
> heavily and that's the reason why we specifically avoided this in our
> firmware design.
> Hence, implementing this condition spoils the whole purpose of the PRU!!

Well, I doubt that a CAN controller just supporting 8 CAN identifiers
will make many CAN users happy. Anyway, the CAN identifiers could/should
be configured via SysFS files (as Marc suggested).

Wolfgang.

> --------------------------------------------------
> From: "Marc Kleine-Budde" <mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Sent: Monday, February 14, 2011 3:05 PM
> To: "Subhasish Ghosh" <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
> Cc: "Wolfgang Grandegger" <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>; "Kurt Van Dijck"
> <kurt.van.dijck-/BeEPy95v10@public.gmane.org>;
> <davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org>;
> <linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>; <m-watkins-l0cyMroinI0@public.gmane.org>;
> <nsekhar-l0cyMroinI0@public.gmane.org>; <sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>; "open list:CAN NETWORK
> DRIVERS" <socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org>; "open list:CAN NETWORK
> DRIVERS" <netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>; "open list"
> <linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
> Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.
> 
> Hello,
> 
> On 02/14/2011 09:45 AM, Subhasish Ghosh wrote:
>> That is correct, we receive only pre-programmed CAN ids and "all" or
>> "range" implementation is not there in the PRU firmware.
> 
> I'd really like to see that you add a "all" implementation to the
> firmware. Or even better use the standard id/mask approach.
> 
> cheers, Marc
> 

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]       ` <20110211152026.GC373-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
@ 2011-02-18  7:07         ` Subhasish Ghosh
  2011-02-18  7:53           ` Wolfgang Grandegger
  0 siblings, 1 reply; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:07 UTC (permalink / raw)
  To: Kurt Van Dijck
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	open list:CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	open list:CAN NETWORK DRIVERS,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	m-watkins-l0cyMroinI0, Wolfgang Grandegger

--------------------------------------------------
From: "Kurt Van Dijck" <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
Sent: Friday, February 11, 2011 8:50 PM
To: "Subhasish Ghosh" <subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
Cc: <davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/@public.gmane.org>; 
<linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>; <m-watkins-l0cyMroinI0@public.gmane.org>; 
<nsekhar-l0cyMroinI0@public.gmane.org>; <sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>; "Wolfgang Grandegger" 
<wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>; "open list:CAN NETWORK DRIVERS" 
<socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org>; "open list:CAN NETWORK DRIVERS" 
<netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>; "open list" <linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH v2 09/13] can: pruss CAN driver.

> Hi,
>
> I looked a bit at the TX path:
>
> On Fri, Feb 11, 2011 at 08:21:28PM +0530, Subhasish Ghosh wrote:
>> +static int omapl_pru_can_set_bittiming(struct net_device *ndev)
>> +{
>> + struct omapl_pru_can_priv *priv = netdev_priv(ndev);
>> + struct can_bittiming *bt = &priv->can.bittiming;
>> + long bit_error = 0;
>> +
>> + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) {
>> + dev_warn(priv->dev, "WARN: Triple"
>> + "sampling not set due to h/w limitations");
> You should not have enabled CAN_CTRLMODE_3_SAMPLES in the first place?

SG - Ok Will remove.
>> + }
>> + if (pru_can_calc_timing(priv->dev, priv->can.clock.freq,
>> + bt->bitrate) != 0)
>> + return -EINVAL;
>> + bit_error =
>> +     (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
>> +       bt->bitrate) * 1000) / bt->bitrate;
>> + if (bit_error) {
>> + bit_error =
>> +     (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) -
>> +       bt->bitrate) * 1000000) / bt->bitrate;
>> + printk(KERN_INFO "\nBitrate error %ld.%ld%%\n",
>> + bit_error / 10000, bit_error % 1000);
>> + } else
>> + printk(KERN_INFO "\nBitrate error 0.0%%\n");
>> +
>> + return 0;
>> +}
> I wonder how much of this code is duplicated from drivers/net/can/dev.c ?
SG - Well, I just followed ti_hecc.c :-)

>
>> +static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb,
>> +     struct net_device *ndev)
>> +{
>> + struct omapl_pru_can_priv *priv = netdev_priv(ndev);
>> + struct can_frame *cf = (struct can_frame *)skb->data;
>> + int count;
>> + u8 *data = cf->data;
>> + u8 dlc = cf->can_dlc;
>> + u8 *ptr8data = NULL;
>> +
> most drivers start with:
> if (can_dropped_invalid_skb(dev, skb))
> return NETDEV_TX_OK;

SG - Will do.
>
>> + netif_stop_queue(ndev);
> why would you stop when you just resumed the queue?

SG - I do not want more than one transmit request at one time. Hence, on 
entering the transmit
I am using netif_stop_queue to disable tx.

>> + if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
>> + *((u32 *) &priv->can_tx_hndl.strcanmailbox) =
>> +     (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE;
>> + else /* Standard frame format */
>> + *((u32 *) &priv->can_tx_hndl.strcanmailbox) =
>> +     (cf->can_id & CAN_SFF_MASK) << 18;
>> +
>> + if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
>> + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG;
>> +
>> + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1);
>> + for (count = 0; count < (u8) dlc; count++) {
>> + *ptr8data-- = *data++;
>> + }
>> + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc;
>> +/*
>> + * search for the next available mbx
>> + * if the next mbx is busy, then try the next + 1
>> + * do this until the head is reached.
>> + * if still unable to tx, stop accepting any packets
>> + * if able to tx and the head is reached, then reset next to tail, i.e 
>> mbx0
>> + * if head is not reached, then just point to the next mbx
>> + */
>> + for (; priv->tx_next <= priv->tx_head; priv->tx_next++) {
>> + priv->can_tx_hndl.ecanmailboxnumber =
>> +     (can_mailbox_number) priv->tx_next;
>> + if (-1 == pru_can_write_data_to_mailbox(priv->dev,
>> + &priv->can_tx_hndl)) {
>> + if (priv->tx_next == priv->tx_head) {
>> + priv->tx_next = priv->tx_tail;
>> + if (!netif_queue_stopped(ndev))
> If you get here, the queue is not stopped. This test is therefore useless.

SG -Ok, will remove
>> + netif_stop_queue(ndev); /* IF stalled */
>> + dev_err(priv->dev,
>> + "%s: no tx mbx available", __func__);
>> + return NETDEV_TX_BUSY;
>> + } else
>> + continue;
>> + } else {
>> + /* set transmit request */
>> + pru_can_tx(priv->dev, priv->tx_next, CAN_TX_PRU_1);
>> + pru_can_tx_mode_set(priv->dev, false, ecanreceive);
>> + pru_can_tx_mode_set(priv->dev, true, ecantransmit);
>> + pru_can_start_abort_tx(priv->dev, PRU_CAN_START);
>> + priv->tx_next++;
>> + can_put_echo_skb(skb, ndev, 0);
>> + break;
>> + }
>> + }
>> + if (priv->tx_next > priv->tx_head) {
>> + priv->tx_next = priv->tx_tail;
>> + }
>> + return NETDEV_TX_OK;
>> +}
>> +
>> +
>
>> +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id)
>> +{
>> + struct net_device *ndev = dev_id;
>> + struct omapl_pru_can_priv *priv = netdev_priv(ndev);
>> + struct net_device_stats *stats = &ndev->stats;
>> + u32 bit_set, mbxno;
>> +
>> + pru_can_get_intr_status(priv->dev, &priv->can_tx_hndl);
>> + if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus)
>> +     || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) {
>> + __can_debug("tx_int_status = 0x%X\n",
>> +     priv->can_tx_hndl.u32interruptstatus);
>> + can_free_echo_skb(ndev, 0);
>> + } else {
>> + for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF)
>> + >> bit_set != 0); bit_set++)
>> + ;
>> + if (0 == bit_set) {
>> + __can_err("%s: invalid mailbox number\n", __func__);
>> + can_free_echo_skb(ndev, 0);
>> + } else {
>> + mbxno = bit_set - 1; /* mail box numbering starts from 0 */
>> + if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl.
>> +     u32interruptstatus) {
>> + /* read gsr and ack pru */
>> + pru_can_get_global_status(priv->dev, &priv->can_tx_hndl);
>> + omapl_pru_can_err(ndev,
>> +   priv->can_tx_hndl.
>> +   u32interruptstatus,
>> +   priv->can_tx_hndl.
>> +   u32globalstatus);
>> + } else {
>> + stats->tx_packets++;
>> + /* stats->tx_bytes += dlc; */
>> + /*can_get_echo_skb(ndev, 0);*/
>> + }
>> + }
>> + }
>> + if (netif_queue_stopped(ndev))
> you can call netif_wake_queue(ndev) multiple times, so there is no need
> for netif_queue_stopped()

SG -Ok, will remove

>> + netif_wake_queue(ndev);
>> +
>> + can_get_echo_skb(ndev, 0);
>> + pru_can_tx_mode_set(priv->dev, true, ecanreceive);
>> + return IRQ_HANDLED;
>> +}
>> +
>> +static int omapl_pru_can_open(struct net_device *ndev)
>> +{
>> + struct omapl_pru_can_priv *priv = netdev_priv(ndev);
>> + int err;
>> +
>> + /* register interrupt handler */
>> + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
>> +   "pru_can_irq", ndev);
> you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
>
SG -Ok, will do

>> +static int omapl_pru_can_close(struct net_device *ndev)
>> +{
>> + struct omapl_pru_can_priv *priv = netdev_priv(ndev);
>> +
>> + if (!netif_queue_stopped(ndev))
> check is not needed.

SG -Ok, will remove

>> + netif_stop_queue(ndev);
>> +
>> + close_candev(ndev);
>> +
>> + free_irq(priv->trx_irq, ndev);
>> + return 0;
>> +}
>> +
>
> Regards,
> Kurt 

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-18  7:07         ` Subhasish Ghosh
@ 2011-02-18  7:53           ` Wolfgang Grandegger
       [not found]             ` <4D5E2570.10108-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Wolfgang Grandegger @ 2011-02-18  7:53 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 02/18/2011 08:07 AM, Subhasish Ghosh wrote:
> --------------------------------------------------
> From: "Kurt Van Dijck" <kurt.van.dijck-/BeEPy95v10@public.gmane.org>

...
>>> + /* register interrupt handler */
>>> + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
>>> +   "pru_can_irq", ndev);
>> you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
>>
> SG -Ok, will do

No, please use NAPI instead.

Wolfgang

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]             ` <4D5E2570.10108-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
@ 2011-02-18  8:15               ` Subhasish Ghosh
  2011-02-18  8:36                 ` Marc Kleine-Budde
  0 siblings, 1 reply; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  8:15 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	open list:CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	open list:CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

> On 02/18/2011 08:07 AM, Subhasish Ghosh wrote:
>> --------------------------------------------------
>> From: "Kurt Van Dijck" <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
>
> ...
>>>> + /* register interrupt handler */
>>>> + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
>>>> +   "pru_can_irq", ndev);
>>> you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
>>>
>> SG -Ok, will do
>
> No, please use NAPI instead.

We are using h/w filters, so the number of interrupts coming into the 
processor are not hogging it.
I feel that we may not require an interrupt mitigation.

-Subhasish 

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-18  8:15               ` Subhasish Ghosh
@ 2011-02-18  8:36                 ` Marc Kleine-Budde
       [not found]                   ` <4D5E2F86.1020400-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Marc Kleine-Budde @ 2011-02-18  8:36 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, LKML,
	CAN NETWORK DRIVERS,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	m-watkins-l0cyMroinI0, Wolfgang Grandegger


[-- Attachment #1.1: Type: text/plain, Size: 1058 bytes --]

On 02/18/2011 09:15 AM, Subhasish Ghosh wrote:
>> On 02/18/2011 08:07 AM, Subhasish Ghosh wrote:
>>> --------------------------------------------------
>>> From: "Kurt Van Dijck" <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
>>
>> ...
>>>>> + /* register interrupt handler */
>>>>> + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
>>>>> +   "pru_can_irq", ndev);
>>>> you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
>>>>
>>> SG -Ok, will do
>>
>> No, please use NAPI instead.
> 
> We are using h/w filters, so the number of interrupts coming into the
> processor are not hogging it.
> I feel that we may not require an interrupt mitigation.

As davem stated the other day, all new drivers should use NAPI.

regards, Marc
-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]                   ` <4D5E2F86.1020400-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
@ 2011-02-18  9:09                     ` Subhasish Ghosh
  0 siblings, 0 replies; 21+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  9:09 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, LKML,
	CAN NETWORK DRIVERS,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	m-watkins-l0cyMroinI0, Wolfgang Grandegger

Ok, will do NAPI


On 02/18/2011 09:15 AM, Subhasish Ghosh wrote:
>> On 02/18/2011 08:07 AM, Subhasish Ghosh wrote:
>>> --------------------------------------------------
>>> From: "Kurt Van Dijck" <kurt.van.dijck-/BeEPy95v10@public.gmane.org>
>>
>> ...
>>>>> + /* register interrupt handler */
>>>>> + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED,
>>>>> +   "pru_can_irq", ndev);
>>>> you're doing a lot of work _in_ the irq handler. Maybe threaded irq?
>>>>
>>> SG -Ok, will do
>>
>> No, please use NAPI instead.
> 
> We are using h/w filters, so the number of interrupts coming into the
> processor are not hogging it.
> I feel that we may not require an interrupt mitigation.

As davem stated the other day, all new drivers should use NAPI.

regards, Marc
-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 | 

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-11 14:51 ` [PATCH v2 09/13] can: pruss CAN driver Subhasish Ghosh
       [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
@ 2011-02-18 15:07   ` Arnd Bergmann
       [not found]     ` <201102181607.20787.arnd-r2nGTMty4D4@public.gmane.org>
  1 sibling, 1 reply; 21+ messages in thread
From: Arnd Bergmann @ 2011-02-18 15:07 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Subhasish Ghosh, davinci-linux-open-source, sachi, nsekhar,
	open list, open list:CAN NETWORK DRIVERS,
	open list:CAN NETWORK DRIVERS, m-watkins, Wolfgang Grandegger

On Friday 11 February 2011, Subhasish Ghosh wrote:
> This patch adds support for the CAN device emulated on PRUSS.

Hi Subhasish,

This is a detailed walk through the can driver. The pruss_can.c
file mostly looks good, there are very tiny changes that I'm
suggesting to improve the code. I assume that you wrote that file.

The pruss_can_api.c is a bit of a mess and looks like it was copied
from some other code base and just barely changed to follow Linux
coding style. I can tell from the main driver file that you can do
better than that.

My recommendation for that would be to throw it away and reimplement
the few parts that you actually need, in proper coding style.
You can also try to fix the file according to the comments I give
you below, but I assume that would be signficantly more work.

Moving everything into one file also makes things easier to read
here and lets you identifer more quickly what is unused.

	Arnd

> +#ifdef __CAN_DEBUG
> +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args)
> +#else
> +#define __can_debug(fmt, args...)
> +#endif
> +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args)

Better use the existing dev_dbg() and dev_err() macros that provide the
same functionality in a more standard way. You already use them in
some places, as I noticed.

If you don't have a way to pass a meaningful device, you can use
pr_debug/pr_err.

> +void omapl_pru_can_rx_wQ(struct work_struct *work)
> +{

This is only used in the same file, so better make it static.

> +	if (-1 == pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
> +		return;

Don't make up your own return values, just use the standard error codes,
e.g. -EIO or -EAGAIN, whatever fits.

The more common way to write the comparison would be the other way round,

	if (pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl) == -EAGAIN)
		return;

or, simpler

	if (pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
		return;

> +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id)
> +{

This also should be static

> +		for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF)
> +						>> bit_set != 0); bit_set++)
> +		;

	bit_set = fls(priv->can_tx_hndl.u32interruptstatus & 0xFF); ?

> +irqreturn_t omapl_rx_can_intr(int irq, void *dev_id)

static

> diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.c b/drivers/net/can/da8xx_pruss/pruss_can_api.c
> new file mode 100644
> index 0000000..2f7438a
> --- /dev/null
> +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.c

A lot of code in this file seems to be unused. Is that right?
I would suggest adding only the code that is actually being
used. If you add more functionality later, you can always
add back the low-level functions, but dead code usually
turns into broken code quickly.

> +static can_emu_drv_inst gstr_can_inst[ecanmaxinst];

This is global data and probably needs some for of locking

> +/*
> + * pru_can_set_brp()	Updates the  BRP register of PRU0
> + * and PRU1 of OMAP L138. This API will be called by the
> + * Application to updtae the BRP register of PRU0 and PRU1
> + *
> + * param	u16bitrateprescaler		The can bus bitrate
> + * prescaler value be set
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_set_brp(struct device *dev, u16 u16bitrateprescaler)
> +{

unused.

> +	u32 u32offset;
> +
> +	if (u16bitrateprescaler > 255) {
> +		return -1;
> +	}

non-standard error code. It also doesn't match the comment, which
claims it is SUCCESS or FAILURE, both of which are (rightfully)
not defined.

> +	u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
> +
> +	u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
> +	pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);

You pass a 32 bit pointer to a 16 bit local variable here.
This has an undefined effect, and if you build this code on
a big-endian platform, it cannot possibly do anything good.

pruss_writel() is defined in a funny way if it takes a thirty-two bit
input argument by reference, rather than by value. What is going
on there?

> +s16 pru_can_set_bit_timing(struct device *dev,
> +		can_bit_timing_consts *pstrbittiming)

unused.

> +	u32 u32offset;
> +	u32 u32serregister;

It's a bit silly to put the name of the type into the name
of a variable. You already spell it out in the definition.

> +s16 pru_can_write_data_to_mailbox(struct device *dev,
> +			can_emu_app_hndl *pstremuapphndl)
> +{
> +	s16 s16subrtnretval;
> +	u32 u32offset;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}

nonstandard error code. Also, why the heck is type function
return type s16 when the only possible return values are 0
and -1? Just make this an int.

> +	switch ((u8) pstremuapphndl->ecanmailboxnumber) {
> +	case 0:
> +		u32offset = (PRU_CAN_TX_MAILBOX0);
> +		break;
> +	case 1:
> +		u32offset = (PRU_CAN_TX_MAILBOX1);
> +		break;
> +	case 2:
> +		u32offset = (PRU_CAN_TX_MAILBOX2);
> +		break;
> +	case 3:
> +		u32offset = (PRU_CAN_TX_MAILBOX3);
> +		break;
> +	case 4:
> +		u32offset = (PRU_CAN_TX_MAILBOX4);
> +		break;
> +	case 5:
> +		u32offset = (PRU_CAN_TX_MAILBOX5);
> +		break;
> +	case 6:
> +		u32offset = (PRU_CAN_TX_MAILBOX6);
> +		break;
> +	case 7:
> +		u32offset = (PRU_CAN_TX_MAILBOX7);
> +		break;
> +	default:
> +		return -1;
> +	}

Lovely switch statement. I'm sure you find a better way to express this ;-)

> +	s16subrtnretval = pruss_writel(dev, u32offset,
> +		(u32 *) &(pstremuapphndl->strcanmailbox), 4);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	return 0;
> +}

return pruss_writel(...) ?

> +
> +/*
> + * pru_can_get_intr_status()
> + * Gets the interrupts status register value.
> + * This API will be called by the Application
> + * to get the interrupts status register value
> + *
> + * param  u8prunumber	PRU number for which IntStatusReg
> + * has to be read
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_intr_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)
> +{
> +	u32 u32offset;
> +	s16 s16subrtnretval = -1;
> +
> +	if (pstremuapphndl == NULL) {
> +		return -1;
> +	}

In every function you check that pstremuapphndl is present. This seems
rather pointless. How about just making sure you never pass a NULL
value to these functions? That should not be hard at all from the
high-level driver.

> +	if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
> +		u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER);
> +	} else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
> +		u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER);
> +	} else {
> +		return -1;
> +	}
> +
> +	s16subrtnretval = pruss_readl(dev, u32offset,
> +		(u32 *) &pstremuapphndl->u32interruptstatus, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}

You can also get rid of all these {} braces around one-line statements.

> +/*
> + * pru_can_get_mailbox_status()		Gets the mailbox status
> + * register value. This API will be called by the Application
> + * to get the mailbox status register value
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_get_mailbox_status(struct device *dev,
> +		can_emu_app_hndl *pstremuapphndl)

unused.

> +/*
> + * pru_can_config_mode_set()		Sets the timing value
> + * for data transfer. This API will be called by the Application
> + * to set timing valus for data transfer
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_config_mode_set(struct device *dev, bool bconfigmodeflag)

unused.

> +	u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
> +	u32value = 0x00000000;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +
> +	u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}
> +	u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
> +	u32value = 0x00000040;
> +	s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
> +	if (s16subrtnretval == -1) {
> +		return -1;
> +	}

<skipping 50 (!) more of these>

After the third time of writing the same code, you should have noticed that
there is some duplication involved that can trivially be reduced. A good
way to express the same would be a table with the contents:

static struct pru_can_register_init {
	u16 offset;
	u32 value;
} = {
	{ PRU_CAN_TX_GLOBAL_CONTROL_REGISTER, 0, },
	{ PRU_CAN_TX_GLOBAL_STATUS_REGISTER, 0x40, },
	{ PRU_CAN_RX_GLOBAL_STATUS_REGISTER, 0x40, },
	...
};


> +
> +
> +/*
> + * pru_can_emu_open()		Opens the can emu for
> + * application to use. This API will be called by the Application
> + * to Open the can emu for application to use.
> + *
> + * param	pstremuapphndl	Pointer to application handler
> + * structure
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_open(struct device *dev, can_emu_app_hndl *pstremuapphndl)

unused.

> +/*
> + * brief    pru_can_emu_close()	Closes the can emu for other
> + * applications to use. This API will be called by the Application to Close
> + * the can emu for other applications to use
> + *
> + * param	pstremuapphndl	Pointer to application handler structure
> + *
> + * return   SUCCESS or FAILURE
> + */
> +s16 pru_can_emu_close(struct device *dev, can_emu_app_hndl *pstremuapphndl)

unused

> +s16 pru_can_emu_sreset(struct device *dev)
> +{
> +	return 0;
> +}

pointless.

> +s16 pru_can_tx(struct device *dev, u8 u8mailboxnumber, u8 u8prunumber)
> +{
> +	u32 u32offset = 0;
> +	u32 u32value = 0;
> +	s16 s16subrtnretval = -1;
> +
> +	if (DA8XX_PRUCORE_1 == u8prunumber) {
> +		switch (u8mailboxnumber) {
> +		case 0:
> +			u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +					(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 1:
> +			u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
> +			u32value = 0x00000080;
> +			s16subrtnretval = pruss_writel(dev, u32offset,
> +						(u32 *) &u32value, 1);
> +			if (s16subrtnretval == -1) {
> +				return -1;
> +			}
> +			break;
> +		case 2:
> +			u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);

Another pointless switch statement.

> +s16 pru_can_mask_ints(struct device *dev, u32 int_mask)
> +{
> +	return 0;
> +}
> +
> +int pru_can_get_error_cnt(struct device *dev, u8 u8prunumber)
> +{
> +	return 0;
> +}

useless.

> +int pru_can_get_intc_status(struct device *dev)
> +{
> +	u32 u32offset = 0;
> +	u32 u32getvalue = 0;
> +	u32 u32clrvalue = 0;
> +
> +	u32offset = (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
> +	pruss_readl(dev, u32offset, (u32 *) &u32getvalue, 1);
> +
> +	if (u32getvalue & 4)
> +		u32clrvalue = 34;	/* CLR Event 34 */
> +
> +	if (u32getvalue & 2)
> +		u32clrvalue = 33;	/* CLR Event 33  */
> +
> +	if (u32clrvalue) {
> +		u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +		pruss_writel(dev, u32offset, &u32clrvalue, 1);
> +	} else
> +		return -1;

Could the controller signal both event 34 and 33 simultaneously?
The only user of this function looks at the individual bits
of the return value again, which looks wrong for all possible
return values here.

> +#ifndef _PRU_CAN_API_H_
> +#define CAN_BIT_TIMINGS			(0x273)
> +
> +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */
> +#define	TIMER_CLK_FREQ			132000000
> +
> +#define TIMER_SETUP_DELAY		14
> +#define GPIO_SETUP_DELAY		150
> +
> +#define CAN_RX_PRU_0			PRUSS_NUM0
> +#define CAN_TX_PRU_1			PRUSS_NUM1
> +
> +/* Number of Instruction in the Delay loop */
> +#define DELAY_LOOP_LENGTH		2
> +
> +#define PRU1_BASE_ADDR			0x2000
> +
> +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER		(PRU1_BASE_ADDR)
> +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x04)
> +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER		(PRU1_BASE_ADDR	+ 0x08)
> +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x0C)
> +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x10)
> +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER		(PRU1_BASE_ADDR	+ 0x14)

The header file should be used for interfaces between the two .c files,
don't mix that with hardware specific definitions. Sometimes you may want
to have register number lists in a header, if that list is going to be
used in multiple places. In this case, there is just one user, so better
move all those definitions over there.

> +typedef enum {
> +	ecaninst0 = 0,
> +	ecaninst1,
> +	ecanmaxinst
> +} can_instance_enum;
> +
> +typedef enum {
> +	ecanmailbox0 = 0,
> +	ecanmailbox1,
> +	ecanmailbox2,
> +	ecanmailbox3,
> +	ecanmailbox4,
> +	ecanmailbox5,
> +	ecanmailbox6,
> +	ecanmailbox7
> +} can_mailbox_number;
> +
> +typedef enum {
> +	ecandirectioninit = 0,
> +	ecantransmit,
> +	ecanreceive
> +} can_transfer_direction;

The values are all unused, you only use the typedefs.
IMHO it would be more sensible to just pass these as unsigned int
or u32 values, but if you prefer, there is no reason to just do 

typedef u32 can_mailbox_number;

etc.

> +typedef struct {
> +	u16 u16extendedidentifier;
> +	u16 u16baseidentifier;
> +	u8 u8data7;
> +	u8 u8data6;
> +	u8 u8data5;
> +	u8 u8data4;
> +	u8 u8data3;
> +	u8 u8data2;
> +	u8 u8data1;
> +	u8 u8data0;
> +	u16 u16datalength;
> +	u16 u16crc;
> +} can_mail_box_structure;

Please don't use typedef for complex data structures, and learn about
better naming of identifiers. I would suggest writing this as

struct pru_can_mailbox {
	u16	ext_id;
	u16	base_id;
	u8	data[8]; /* note: reverse order */
	u16	len;
	u16	crc;
};

Sames rules apply to the other structures.

	Arnd

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
       [not found]     ` <201102181607.20787.arnd-r2nGTMty4D4@public.gmane.org>
@ 2011-03-22  7:30       ` Subhasish Ghosh
  0 siblings, 0 replies; 21+ messages in thread
From: Subhasish Ghosh @ 2011-03-22  7:30 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: sachi-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/,
	davinci-linux-open-source-VycZQUHpC/PFrsHnngEfi1aTQe2KTcn/,
	open list:CAN NETWORK DRIVERS, nsekhar-l0cyMroinI0, open list,
	open list:CAN NETWORK DRIVERS, m-watkins-l0cyMroinI0,
	Wolfgang Grandegger

Hello,

> This is a detailed walk through the can driver. The pruss_can.c
> file mostly looks good, there are very tiny changes that I'm
> suggesting to improve the code. I assume that you wrote that file.
>
> The pruss_can_api.c is a bit of a mess and looks like it was copied
> from some other code base and just barely changed to follow Linux
> coding style. I can tell from the main driver file that you can do
> better than that.
> My recommendation for that would be to throw it away and reimplement
> the few parts that you actually need, in proper coding style.
> You can also try to fix the file according to the comments I give
> you below, but I assume that would be signficantly more work.
>
> Moving everything into one file also makes things easier to read
> here and lets you identifer more quickly what is unused.

SG - I have almost re-implemented the API layer, will be merging with the 
driver file itself.


>> +#ifdef __CAN_DEBUG
>> +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, 
>> ## args)
>> +#else
>> +#define __can_debug(fmt, args...)
>> +#endif
>> +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## 
>> args)
>
> Better use the existing dev_dbg() and dev_err() macros that provide the
> same functionality in a more standard way. You already use them in
> some places, as I noticed.
>
> If you don't have a way to pass a meaningful device, you can use
> pr_debug/pr_err.
>
SG - Ok

>> +void omapl_pru_can_rx_wQ(struct work_struct *work)
>> +{
>
> This is only used in the same file, so better make it static.

SG - This is removed, used NAPI as recommended.

>
>> + if (-1 == pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
>> + return;
>
> Don't make up your own return values, just use the standard error codes,
> e.g. -EIO or -EAGAIN, whatever fits.

SG - Ok

>
> The more common way to write the comparison would be the other way round,
>
> if (pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl) == -EAGAIN)
> return;
>
> or, simpler
>
> if (pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl))
> return;

SG - Ok

>
>> +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id)
>> +{
>
> This also should be static

SG - Ok

>
>> + for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF)
>> + >> bit_set != 0); bit_set++)
>> + ;
>
> bit_set = fls(priv->can_tx_hndl.u32interruptstatus & 0xFF); ?
>

SG - Ok

>> +irqreturn_t omapl_rx_can_intr(int irq, void *dev_id)
>
> static

SG - Ok


>
>> diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.c 
>> b/drivers/net/can/da8xx_pruss/pruss_can_api.c
>> new file mode 100644
>> index 0000000..2f7438a
>> --- /dev/null
>> +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.c
>
> A lot of code in this file seems to be unused. Is that right?
> I would suggest adding only the code that is actually being
> used. If you add more functionality later, you can always
> add back the low-level functions, but dead code usually
> turns into broken code quickly.
>

SG - Ok

>> +static can_emu_drv_inst gstr_can_inst[ecanmaxinst];
>
> This is global data and probably needs some for of locking

SG - Ok

>
>> +/*
>> + * pru_can_set_brp() Updates the  BRP register of PRU0
>> + * and PRU1 of OMAP L138. This API will be called by the
>> + * Application to updtae the BRP register of PRU0 and PRU1
>> + *
>> + * param u16bitrateprescaler The can bus bitrate
>> + * prescaler value be set
>> + *
>> + * return   SUCCESS or FAILURE
>> + */
>> +s16 pru_can_set_brp(struct device *dev, u16 u16bitrateprescaler)
>> +{
>
> unused.

SG - Ok

>
>> + u32 u32offset;
>> +
>> + if (u16bitrateprescaler > 255) {
>> + return -1;
>> + }
>
> non-standard error code. It also doesn't match the comment, which
> claims it is SUCCESS or FAILURE, both of which are (rightfully)
> not defined.

SG - Ok

>
>> + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER);
>> + pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
>> +
>> + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER);
>> + pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1);
>

SG - Ok


> You pass a 32 bit pointer to a 16 bit local variable here.
> This has an undefined effect, and if you build this code on
> a big-endian platform, it cannot possibly do anything good.
>
> pruss_writel() is defined in a funny way if it takes a thirty-two bit
> input argument by reference, rather than by value. What is going
> on there?
>
>> +s16 pru_can_set_bit_timing(struct device *dev,
>> + can_bit_timing_consts *pstrbittiming)
>
> unused.
>

SG - Ok


>> + u32 u32offset;
>> + u32 u32serregister;
>
> It's a bit silly to put the name of the type into the name
> of a variable. You already spell it out in the definition.

SG - Ok

>
>> +s16 pru_can_write_data_to_mailbox(struct device *dev,
>> + can_emu_app_hndl *pstremuapphndl)
>> +{
>> + s16 s16subrtnretval;
>> + u32 u32offset;
>> +
>> + if (pstremuapphndl == NULL) {
>> + return -1;
>> + }
>
> nonstandard error code. Also, why the heck is type function
> return type s16 when the only possible return values are 0
> and -1? Just make this an int.

SG - Ok

>
>> + switch ((u8) pstremuapphndl->ecanmailboxnumber) {
>> + case 0:
>> + u32offset = (PRU_CAN_TX_MAILBOX0);
>> + break;
>> + case 1:
>> + u32offset = (PRU_CAN_TX_MAILBOX1);
>> + break;
>> + case 2:
>> + u32offset = (PRU_CAN_TX_MAILBOX2);
>> + break;
>> + case 3:
>> + u32offset = (PRU_CAN_TX_MAILBOX3);
>> + break;
>> + case 4:
>> + u32offset = (PRU_CAN_TX_MAILBOX4);
>> + break;
>> + case 5:
>> + u32offset = (PRU_CAN_TX_MAILBOX5);
>> + break;
>> + case 6:
>> + u32offset = (PRU_CAN_TX_MAILBOX6);
>> + break;
>> + case 7:
>> + u32offset = (PRU_CAN_TX_MAILBOX7);
>> + break;
>> + default:
>> + return -1;
>> + }
>
> Lovely switch statement. I'm sure you find a better way to express this 
> ;-)

SG - Ok.

>
>> + s16subrtnretval = pruss_writel(dev, u32offset,
>> + (u32 *) &(pstremuapphndl->strcanmailbox), 4);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>> + return 0;
>> +}
>
> return pruss_writel(...) ?

SG - Ok.

>
>> +
>> +/*
>> + * pru_can_get_intr_status()
>> + * Gets the interrupts status register value.
>> + * This API will be called by the Application
>> + * to get the interrupts status register value
>> + *
>> + * param  u8prunumber PRU number for which IntStatusReg
>> + * has to be read
>> + *
>> + * return   SUCCESS or FAILURE
>> + */
>> +s16 pru_can_get_intr_status(struct device *dev,
>> + can_emu_app_hndl *pstremuapphndl)
>> +{
>> + u32 u32offset;
>> + s16 s16subrtnretval = -1;
>> +
>> + if (pstremuapphndl == NULL) {
>> + return -1;
>> + }
>
> In every function you check that pstremuapphndl is present. This seems
> rather pointless. How about just making sure you never pass a NULL
> value to these functions? That should not be hard at all from the
> high-level driver.

SG - OK.


>
>> + if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) {
>> + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER);
>> + } else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) {
>> + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER);
>> + } else {
>> + return -1;
>> + }
>> +
>> + s16subrtnretval = pruss_readl(dev, u32offset,
>> + (u32 *) &pstremuapphndl->u32interruptstatus, 1);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>
> You can also get rid of all these {} braces around one-line statements.

SG - OK.

>
>> +/*
>> + * pru_can_get_mailbox_status() Gets the mailbox status
>> + * register value. This API will be called by the Application
>> + * to get the mailbox status register value
>> + *
>> + * return   SUCCESS or FAILURE
>> + */
>> +s16 pru_can_get_mailbox_status(struct device *dev,
>> + can_emu_app_hndl *pstremuapphndl)
>
> unused
.
SG - OK.

>
>> +/*
>> + * pru_can_config_mode_set() Sets the timing value
>> + * for data transfer. This API will be called by the Application
>> + * to set timing valus for data transfer
>> + *
>> + * return   SUCCESS or FAILURE
>> + */
>> +s16 pru_can_config_mode_set(struct device *dev, bool bconfigmodeflag)
>
> unused.

SG - OK.

>
>> + u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & 0xFFFF);
>> + u32value = 0x00000000;
>> + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>> +
>> + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & 0xFFFF);
>> + u32value = 0x00000040;
>> + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>> + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF);
>> + u32value = 0x00000040;
>> + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>
> <skipping 50 (!) more of these>
>
> After the third time of writing the same code, you should have noticed 
> that
> there is some duplication involved that can trivially be reduced. A good
> way to express the same would be a table with the contents:
>

SG - OK.
                 Thanks for taking the pain to review this. But, the good 
part is that
                 everything works fine. All this got cluttered as 
development &
                 design changes happened. Hopefully, the cleaned up code 
will
                also work as well :-)

> static struct pru_can_register_init {
> u16 offset;
> u32 value;
> } = {
> { PRU_CAN_TX_GLOBAL_CONTROL_REGISTER, 0, },
> { PRU_CAN_TX_GLOBAL_STATUS_REGISTER, 0x40, },
> { PRU_CAN_RX_GLOBAL_STATUS_REGISTER, 0x40, },
> ...
> };
>
>
>> +
>> +
>> +/*
>> + * pru_can_emu_open() Opens the can emu for
>> + * application to use. This API will be called by the Application
>> + * to Open the can emu for application to use.
>> + *
>> + * param pstremuapphndl Pointer to application handler
>> + * structure
>> + *
>> + * return   SUCCESS or FAILURE
>> + */
>> +s16 pru_can_emu_open(struct device *dev, can_emu_app_hndl 
>> *pstremuapphndl)
>
> unused.

SG - OK.

>
>> +/*
>> + * brief    pru_can_emu_close() Closes the can emu for other
>> + * applications to use. This API will be called by the Application to 
>> Close
>> + * the can emu for other applications to use
>> + *
>> + * param pstremuapphndl Pointer to application handler structure
>> + *
>> + * return   SUCCESS or FAILURE
>> + */
>> +s16 pru_can_emu_close(struct device *dev, can_emu_app_hndl 
>> *pstremuapphndl)
>
> unused

SG - OK.

>
>> +s16 pru_can_emu_sreset(struct device *dev)
>> +{
>> + return 0;
>> +}
>
> pointless.

SG - OK.

>
>> +s16 pru_can_tx(struct device *dev, u8 u8mailboxnumber, u8 u8prunumber)
>> +{
>> + u32 u32offset = 0;
>> + u32 u32value = 0;
>> + s16 s16subrtnretval = -1;
>> +
>> + if (DA8XX_PRUCORE_1 == u8prunumber) {
>> + switch (u8mailboxnumber) {
>> + case 0:
>> + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF);
>> + u32value = 0x00000080;
>> + s16subrtnretval = pruss_writel(dev, u32offset,
>> + (u32 *) &u32value, 1);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>> + break;
>> + case 1:
>> + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF);
>> + u32value = 0x00000080;
>> + s16subrtnretval = pruss_writel(dev, u32offset,
>> + (u32 *) &u32value, 1);
>> + if (s16subrtnretval == -1) {
>> + return -1;
>> + }
>> + break;
>> + case 2:
>> + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF);
>
> Another pointless switch statement.

SG - OK.

>
>> +s16 pru_can_mask_ints(struct device *dev, u32 int_mask)
>> +{
>> + return 0;
>> +}
>> +
>> +int pru_can_get_error_cnt(struct device *dev, u8 u8prunumber)
>> +{
>> + return 0;
>> +}
>
> useless.

SG - OK.

>
>> +int pru_can_get_intc_status(struct device *dev)
>> +{
>> + u32 u32offset = 0;
>> + u32 u32getvalue = 0;
>> + u32 u32clrvalue = 0;
>> +
>> + u32offset = (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
>> + pruss_readl(dev, u32offset, (u32 *) &u32getvalue, 1);
>> +
>> + if (u32getvalue & 4)
>> + u32clrvalue = 34; /* CLR Event 34 */
>> +
>> + if (u32getvalue & 2)
>> + u32clrvalue = 33; /* CLR Event 33  */
>> +
>> + if (u32clrvalue) {
>> + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF);
>> + pruss_writel(dev, u32offset, &u32clrvalue, 1);
>> + } else
>> + return -1;
>
> Could the controller signal both event 34 and 33 simultaneously?
> The only user of this function looks at the individual bits
> of the return value again, which looks wrong for all possible
> return values here.
>

SG - OK. The System Events are mapped to 10 host interrupts (PRU to 
ARM/DSP),
                   as I our case two system events can be mapped to a single 
host interrupt.


>> +#ifndef _PRU_CAN_API_H_
>> +#define CAN_BIT_TIMINGS (0x273)
>> +
>> +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */
>> +#define TIMER_CLK_FREQ 132000000
>> +
>> +#define TIMER_SETUP_DELAY 14
>> +#define GPIO_SETUP_DELAY 150
>> +
>> +#define CAN_RX_PRU_0 PRUSS_NUM0
>> +#define CAN_TX_PRU_1 PRUSS_NUM1
>> +
>> +/* Number of Instruction in the Delay loop */
>> +#define DELAY_LOOP_LENGTH 2
>> +
>> +#define PRU1_BASE_ADDR 0x2000
>> +
>> +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR)
>> +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04)
>> +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08)
>> +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C)
>> +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10)
>> +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14)
>
> The header file should be used for interfaces between the two .c files,
> don't mix that with hardware specific definitions. Sometimes you may want
> to have register number lists in a header, if that list is going to be
> used in multiple places. In this case, there is just one user, so better
> move all those definitions over there.

SG - OK.

>
>> +typedef enum {
>> + ecaninst0 = 0,
>> + ecaninst1,
>> + ecanmaxinst
>> +} can_instance_enum;
>> +
>> +typedef enum {
>> + ecanmailbox0 = 0,
>> + ecanmailbox1,
>> + ecanmailbox2,
>> + ecanmailbox3,
>> + ecanmailbox4,
>> + ecanmailbox5,
>> + ecanmailbox6,
>> + ecanmailbox7
>> +} can_mailbox_number;
>> +
>> +typedef enum {
>> + ecandirectioninit = 0,
>> + ecantransmit,
>> + ecanreceive
>> +} can_transfer_direction;
>
> The values are all unused, you only use the typedefs.
> IMHO it would be more sensible to just pass these as unsigned int
> or u32 values, but if you prefer, there is no reason to just do
>
> typedef u32 can_mailbox_number;
>
> etc.

SG - OK.

>
>> +typedef struct {
>> + u16 u16extendedidentifier;
>> + u16 u16baseidentifier;
>> + u8 u8data7;
>> + u8 u8data6;
>> + u8 u8data5;
>> + u8 u8data4;
>> + u8 u8data3;
>> + u8 u8data2;
>> + u8 u8data1;
>> + u8 u8data0;
>> + u16 u16datalength;
>> + u16 u16crc;
>> +} can_mail_box_structure;
>
> Please don't use typedef for complex data structures, and learn about
> better naming of identifiers. I would suggest writing this as
>
> struct pru_can_mailbox {
> u16 ext_id;
> u16 base_id;
> u8 data[8]; /* note: reverse order */
> u16 len;
> u16 crc;
> };
>
> Sames rules apply to the other structures.

SG - OK.

>
> Arnd 

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

end of thread, other threads:[~2011-03-22  7:30 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1297435892-28278-1-git-send-email-subhasish@mistralsolutions.com>
2011-02-11 14:51 ` [PATCH v2 09/13] can: pruss CAN driver Subhasish Ghosh
     [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
2011-02-11 15:06     ` Kurt Van Dijck
2011-02-14  4:54       ` Subhasish Ghosh
2011-02-14  7:23         ` Wolfgang Grandegger
     [not found]           ` <4D58D854.5090503-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
2011-02-14  7:42             ` Kurt Van Dijck
2011-02-14  8:45           ` Subhasish Ghosh
2011-02-14  9:28             ` Wolfgang Grandegger
2011-02-14  9:35             ` Marc Kleine-Budde
     [not found]               ` <4D58F77B.9080005-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2011-02-14 13:15                 ` Subhasish Ghosh
2011-02-14 13:33                   ` Marc Kleine-Budde
2011-02-14 13:42                   ` Wolfgang Grandegger
2011-02-11 15:20     ` Kurt Van Dijck
     [not found]       ` <20110211152026.GC373-MxZ6Iy/zr/UdbCeoMzGj59i2O/JbrIOy@public.gmane.org>
2011-02-18  7:07         ` Subhasish Ghosh
2011-02-18  7:53           ` Wolfgang Grandegger
     [not found]             ` <4D5E2570.10108-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
2011-02-18  8:15               ` Subhasish Ghosh
2011-02-18  8:36                 ` Marc Kleine-Budde
     [not found]                   ` <4D5E2F86.1020400-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2011-02-18  9:09                     ` Subhasish Ghosh
2011-02-11 20:33     ` Wolfgang Grandegger
2011-02-11 21:33     ` Marc Kleine-Budde
2011-02-18 15:07   ` Arnd Bergmann
     [not found]     ` <201102181607.20787.arnd-r2nGTMty4D4@public.gmane.org>
2011-03-22  7:30       ` Subhasish Ghosh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).