All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/13] pruss mfd drivers
@ 2011-02-11 14:51 Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                   ` (12 more replies)
  0 siblings, 13 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel


                           PRUSS Functional Block Diagram
               /----------------------------------------------------\
               |                                                    |
               |                      |------|                      |
     32GPO<------->PRU CORE-0 <------>|      |<------> DRAM 0       |
     30GPI<------->(4KB IRAM)         |  S   |       (512 Bytes)    |
               |                      |      |                      |
     32GPO<------->PRU CORE-1 <------>|  C   |<------> DRAM 1       |
     30GPI<------->(4KB IRAM)         |      |       (512 Bytes)    |
               |                      |  R   |                      |
               |                      |      |                      |
 Ints to ARM/  |    Interrupt <------>|      |-------------------------> Master I/F (to SCR2)
 DSP INTC <------->Controller         |      |<------------------------- Slave I/F (from SCR2)
 Events from   |     (INTC)           |------|                      |
 Periph + PRUs |                                                    |
               \----------------------------------------------------/

Programmable Realtime Unit (PRU) is basically a 32-bit RISC
processor available within TI's DA8XX SOCs. It consists of local
instruction and data RAM and also has access to SOC resources
via a Switched Central Resource (SCR).

There are two PRU's available within DA8XX SOC's PRUSS, hence providing
two execution cores. Devices/Protocols can be emulated on these utilizing
either both or only one of the PRUs independently.

The rational behind the MFD driver being the fact that multiple devices can
be implemented on the cores independently.
It's also possible, as in our case, to implement a single device on both
the PRU's resulting in improved load sharing.

A detailed description is also available here:
http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem

version 2:
==========
* added pruss TTY Soft-UART driver.
* added pruss Soft-UART board and platform changes.
* fixed previous review comments.
* reordered patch sequence.

version 1:
==========
* added pruss mfd driver.
* added pruss mfd board and platform changes.
* added pruss SocketCAN driver.
* added pruss SocketCAN board and platform changes.
* added pruss SocketCAN GPIOs.
* added previous review comments.

Subhasish Ghosh (13):
  mfd: pruss mfd driver.
  da850: pruss platform specific additions.
  da850: pruss board specific additions.
  mfd: pruss CAN private data.
  da850: pruss CAN platform specific additions.
  da850: pruss CAN board specific additions.
  da850: pruss CAN platform specific changes for gpios.
  da850: pruss CAN board specific changes for gpios.
  can: pruss CAN driver.
  mfd: pruss SUART private data.
  da850: pruss SUART board specific additions.
  da850: pruss SUART platform specific additions.
  tty: pruss SUART driver

 arch/arm/mach-davinci/board-da850-evm.c            |  105 +
 arch/arm/mach-davinci/da850.c                      |   12 +
 arch/arm/mach-davinci/devices-da8xx.c              |   76 +
 arch/arm/mach-davinci/include/mach/da8xx.h         |    2 +
 arch/arm/mach-davinci/include/mach/mux.h           |    5 +
 drivers/mfd/Kconfig                                |   10 +
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/da8xx_pru.c                            |  446 ++++
 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 +++
 drivers/tty/serial/Kconfig                         |    2 +
 drivers/tty/serial/Makefile                        |    1 +
 drivers/tty/serial/da8xx_pruss/Kconfig             |   19 +
 drivers/tty/serial/da8xx_pruss/Makefile            |    9 +
 drivers/tty/serial/da8xx_pruss/pruss_suart.c       | 1014 +++++++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c   | 2350 ++++++++++++++++++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h   |  345 +++
 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h |   58 +
 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h   |   48 +
 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h |  526 +++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h  |  153 ++
 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c |  384 ++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h |   63 +
 include/linux/mfd/pruss/da8xx_pru.h                |  131 ++
 include/linux/mfd/pruss/da8xx_prucore.h            |   74 +
 include/linux/serial_core.h                        |    2 +
 31 files changed, 8193 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/da8xx_pru.c
 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
 create mode 100644 drivers/tty/serial/da8xx_pruss/Kconfig
 create mode 100644 drivers/tty/serial/da8xx_pruss/Makefile
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
 create mode 100644 include/linux/mfd/pruss/da8xx_pru.h
 create mode 100644 include/linux/mfd/pruss/da8xx_prucore.h

-- 
1.7.2.3

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

* [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Samuel Ortiz, open list

This patch adds the pruss MFD driver and associated include files.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/mfd/Kconfig                     |   10 +
 drivers/mfd/Makefile                    |    1 +
 drivers/mfd/da8xx_pru.c                 |  446 +++++++++++++++++++++++++++++++
 include/linux/mfd/pruss/da8xx_pru.h     |  122 +++++++++
 include/linux/mfd/pruss/da8xx_prucore.h |   74 +++++
 5 files changed, 653 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/da8xx_pru.c
 create mode 100644 include/linux/mfd/pruss/da8xx_pru.h
 create mode 100644 include/linux/mfd/pruss/da8xx_prucore.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fd01836..6c437df 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
 	  boards.  MSP430 firmware manages resets and power sequencing,
 	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
 
+config MFD_DA8XX_PRUSS
+	tristate "Texas Instruments DA8XX PRUSS support"
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	select MFD_CORE
+	help
+	    This driver provides support api's for the programmable
+		realtime unit (PRU) present on TI's da8xx processors. It
+		provides basic read, write, config, enable, disable
+		routines to facilitate devices emulated on it.
+
 config HTC_EGPIO
 	bool "HTC EGPIO support"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a54e2c7..670d6b0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
 obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
+obj-$(CONFIG_MFD_DA8XX_PRUSS)	+= da8xx_pru.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 
 obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
diff --git a/drivers/mfd/da8xx_pru.c b/drivers/mfd/da8xx_pru.c
new file mode 100644
index 0000000..f7868a4
--- /dev/null
+++ b/drivers/mfd/da8xx_pru.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mfd/pruss/da8xx_prucore.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+#include <linux/mfd/core.h>
+#include <linux/io.h>
+#include <mach/da8xx.h>
+
+struct da8xx_pruss {
+	struct device *dev;
+	struct resource *res;
+	struct clk *clk;
+	u32 clk_freq;
+	void __iomem *ioaddr;
+};
+
+u32 pruss_get_clk_freq(struct device *dev)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+
+	return pruss->clk_freq;
+}
+EXPORT_SYMBOL(pruss_get_clk_freq);
+
+u32 pruss_disable(struct device *dev, u8 pruss_num)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+	u32 temp_reg;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* Disable PRU0  */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_ENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		/* Reset PRU0 */
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
+				&h_pruss->CONTROL);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* Disable PRU1 */
+		h_pruss = (da8xx_prusscore_regs)
+		((u32) pruss->ioaddr + 0x7800);
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_ENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		/* Reset PRU1 */
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, &h_pruss->CONTROL);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(pruss_disable);
+
+u32 pruss_enable(struct device *dev, u8 pruss_num)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* Reset PRU0 */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
+			&h_pruss->CONTROL);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* Reset PRU1  */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7800);
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
+			&h_pruss->CONTROL);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(pruss_enable);
+
+/* Load the specified PRU with code */
+u32 pruss_load(struct device *dev, u8 pruss_num,
+			u32 *pruss_code, u32 code_size_in_words)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pruss_iram;
+	u32 i;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		pruss_iram = (u32 *) ((u32) pruss->ioaddr + 0x8000);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		pruss_iram = (u32 *) ((u32) pruss->ioaddr + 0xc000);
+	} else
+		return -EINVAL;
+
+	pruss_enable(dev, pruss_num);
+
+	/* Copy dMAX code to its instruction RAM  */
+	for (i = 0; i < code_size_in_words; i++) {
+		__raw_writel(pruss_code[i], (pruss_iram + i));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pruss_load);
+
+u32 pruss_run(struct device *dev, u8 pruss_num)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+
+	u32 temp_reg;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* DA8XX_PRUCORE_0_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* DA8XX_PRUCORE_1_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7800);
+	} else
+		return -EINVAL;
+
+	/* Enable dMAX, let it execute the code we just copied */
+	temp_reg = __raw_readl(&h_pruss->CONTROL);
+	temp_reg = (temp_reg &
+			~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) |
+			((DA8XX_PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
+			DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+			DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK);
+	__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+	temp_reg = __raw_readl(&h_pruss->CONTROL);
+	temp_reg = (temp_reg &
+			~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) |
+			((DA8XX_PRUCORE_CONTROL_ENABLE_ENABLE <<
+			DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) &
+			DA8XX_PRUCORE_CONTROL_ENABLE_MASK);
+	__raw_writel(temp_reg, &h_pruss->CONTROL);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_run);
+
+u32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+	u32 temp_reg;
+	u32 cnt = timeout;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* DA8XX_PRUCORE_0_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* DA8XX_PRUCORE_1_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7800);
+	} else
+		return -EINVAL;
+
+	while (cnt--) {
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		if (((temp_reg & DA8XX_PRUCORE_CONTROL_RUNSTATE_MASK) >>
+				DA8XX_PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
+					DA8XX_PRUCORE_CONTROL_RUNSTATE_HALT)
+			break;
+	}
+	if (cnt == 0)
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL(pruss_wait_for_halt);
+
+s16 pruss_writeb(struct device *dev, u32 u32offset,
+		u8 *pu8datatowrite, u16 u16bytestowrite)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u8 *pu8addresstowrite;
+	u16 u16loop;
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu8addresstowrite = (u8 *) (u32offset);
+
+	for (u16loop = 0; u16loop < u16bytestowrite; u16loop++)
+		__raw_writeb(*pu8datatowrite++, pu8addresstowrite++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_writeb);
+
+s16 pruss_readb(struct device *dev, u32 u32offset,
+		u8 *pu8datatoread, u16 u16bytestoread)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u8 *pu8addresstoread;
+	u16 u16loop;
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu8addresstoread = (u8 *) (u32offset);
+
+	for (u16loop = 0; u16loop < u16bytestoread; u16loop++)
+		*pu8datatoread++ = __raw_readb(pu8addresstoread++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_readb);
+
+s16 pruss_writel(struct device *dev, u32 u32offset,
+		u32 *pu32datatowrite, s16 u16wordstowrite)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstowrite;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstowrite = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstowrite; u16loop++)
+		__raw_writel(*pu32datatowrite++, pu32addresstowrite++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_writel);
+
+s16 pruss_readl(struct device *dev, u32 u32offset,
+		u32 *pu32datatoread, s16 u16wordstoread)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstoread;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstoread = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstoread; u16loop++)
+		*pu32datatoread++ = __raw_readl(pu32addresstoread++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_readl);
+
+s16 pruss_writew(struct device *dev, u32 u32offset,
+		u16 *pu16datatowrite, s16 u16wordstowrite)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstowrite;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstowrite = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) {
+		__raw_writew(*(pu16datatowrite++), (pu32addresstowrite++));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pruss_writew);
+
+s16 pruss_readw(struct device *dev, u32 u32offset,
+			u16 *pu16datatoread, s16 u16wordstoread)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstoread;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstoread = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstoread; u16loop++)
+		*pu16datatoread++ = __raw_readw(pu32addresstoread++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_readw);
+
+static int pruss_mfd_add_devices(struct platform_device *pdev)
+{
+	struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct mfd_cell cell;
+	u32 err, count;
+
+	for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
+		memset(&cell, 0, sizeof(struct mfd_cell));
+		cell.id			= count;
+		cell.name		= (dev_data + count)->dev_name;
+		cell.platform_data	= (dev_data + count)->pdata;
+		cell.data_size		= (dev_data + count)->pdata_size;
+
+		err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
+		if (err) {
+			dev_err(dev, "cannot add mfd cells\n");
+			return err;
+		}
+	}
+	return err;
+}
+
+static int __devinit da8xx_pruss_probe(struct platform_device *pdev)
+{
+	struct da8xx_pruss *pruss_dev = NULL;
+	u32 err;
+
+	pruss_dev = kzalloc(sizeof(struct da8xx_pruss), GFP_KERNEL);
+	if (!pruss_dev)
+		return -ENOMEM;
+
+	pruss_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!pruss_dev->res) {
+		dev_err(&pdev->dev,
+		"unable to get pruss memory resources!\n");
+		err = -ENODEV;
+		goto probe_exit_kfree;
+	}
+
+	if (!request_mem_region(pruss_dev->res->start, resource_size(pruss_dev->res),
+		dev_name(&pdev->dev))) {
+		dev_err(&pdev->dev, "pruss memory region already claimed!\n");
+		err = -EBUSY;
+		goto probe_exit_kfree;
+	}
+
+	pruss_dev->ioaddr = ioremap(pruss_dev->res->start,
+	resource_size(pruss_dev->res));
+	if (!pruss_dev->ioaddr) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		err = -ENOMEM;
+		goto probe_exit_free_region;
+	}
+
+	pruss_dev->clk = clk_get(NULL, "pruss");
+	if (IS_ERR(pruss_dev->clk)) {
+		dev_err(&pdev->dev, "no clock available: pruss\n");
+		err = -ENODEV;
+		pruss_dev->clk = NULL;
+		goto probe_exit_iounmap;
+	}
+
+	clk_enable(pruss_dev->clk);
+	pruss_dev->clk_freq = clk_get_rate(pruss_dev->clk);
+
+	err = pruss_mfd_add_devices(pdev);
+	if (err)
+		goto probe_exit_clock;
+
+	platform_set_drvdata(pdev, pruss_dev);
+	pruss_dev->dev = &pdev->dev;
+	return 0;
+
+probe_exit_clock:
+	clk_put(pruss_dev->clk);
+	clk_disable(pruss_dev->clk);
+probe_exit_iounmap:
+	iounmap(pruss_dev->ioaddr);
+probe_exit_free_region:
+	release_mem_region(pruss_dev->res->start, resource_size(pruss_dev->res));
+probe_exit_kfree:
+	kfree(pruss_dev);
+	return err;
+}
+
+static int __devexit da8xx_pruss_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev);
+
+	mfd_remove_devices(dev);
+	clk_disable(pruss->clk);
+	clk_put(pruss->clk);
+	iounmap(pruss->ioaddr);
+	release_mem_region(pruss->res->start, resource_size(pruss->res));
+	kfree(pruss);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static struct platform_driver da8xx_pruss_driver = {
+	.probe	= da8xx_pruss_probe,
+	.remove	= __devexit_p(da8xx_pruss_remove),
+	.driver	= {
+		.name	= "da8xx_pruss",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init da8xx_pruss_init(void)
+{
+	return platform_driver_register(&da8xx_pruss_driver);
+}
+module_init(da8xx_pruss_init);
+
+static void __exit da8xx_pruss_exit(void)
+{
+	platform_driver_unregister(&da8xx_pruss_driver);
+}
+module_exit(da8xx_pruss_exit);
+
+MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
+MODULE_AUTHOR("Subhasish Ghosh");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
new file mode 100644
index 0000000..68d8421
--- /dev/null
+++ b/include/linux/mfd/pruss/da8xx_pru.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _PRUSS_H_
+#define _PRUSS_H_
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include "da8xx_prucore.h"
+
+#define PRUSS_NUM0			DA8XX_PRUCORE_0
+#define PRUSS_NUM1			DA8XX_PRUCORE_1
+
+#define PRUSS_PRU0_BASE_ADDRESS		0
+#define PRUSS_INTC_BASE_ADDRESS		(PRUSS_PRU0_BASE_ADDRESS + 0x4000)
+#define PRUSS_INTC_GLBLEN		(PRUSS_INTC_BASE_ADDRESS + 0x10)
+#define PRUSS_INTC_GLBLNSTLVL		(PRUSS_INTC_BASE_ADDRESS + 0x1C)
+#define PRUSS_INTC_STATIDXSET		(PRUSS_INTC_BASE_ADDRESS + 0x20)
+#define PRUSS_INTC_STATIDXCLR		(PRUSS_INTC_BASE_ADDRESS + 0x24)
+#define PRUSS_INTC_ENIDXSET		(PRUSS_INTC_BASE_ADDRESS + 0x28)
+#define PRUSS_INTC_ENIDXCLR		(PRUSS_INTC_BASE_ADDRESS + 0x2C)
+#define PRUSS_INTC_HSTINTENIDXSET	(PRUSS_INTC_BASE_ADDRESS + 0x34)
+#define PRUSS_INTC_HSTINTENIDXCLR	(PRUSS_INTC_BASE_ADDRESS + 0x38)
+#define PRUSS_INTC_GLBLPRIIDX		(PRUSS_INTC_BASE_ADDRESS + 0x80)
+#define PRUSS_INTC_STATSETINT0		(PRUSS_INTC_BASE_ADDRESS + 0x200)
+#define PRUSS_INTC_STATSETINT1		(PRUSS_INTC_BASE_ADDRESS + 0x204)
+#define PRUSS_INTC_STATCLRINT0		(PRUSS_INTC_BASE_ADDRESS + 0x280)
+#define PRUSS_INTC_STATCLRINT1		(PRUSS_INTC_BASE_ADDRESS + 0x284)
+#define PRUSS_INTC_ENABLESET0		(PRUSS_INTC_BASE_ADDRESS + 0x300)
+#define PRUSS_INTC_ENABLESET1		(PRUSS_INTC_BASE_ADDRESS + 0x304)
+#define PRUSS_INTC_ENABLECLR0		(PRUSS_INTC_BASE_ADDRESS + 0x380)
+#define PRUSS_INTC_ENABLECLR1		(PRUSS_INTC_BASE_ADDRESS + 0x384)
+#define PRUSS_INTC_CHANMAP0		(PRUSS_INTC_BASE_ADDRESS + 0x400)
+#define PRUSS_INTC_CHANMAP1		(PRUSS_INTC_BASE_ADDRESS + 0x404)
+#define PRUSS_INTC_CHANMAP2		(PRUSS_INTC_BASE_ADDRESS + 0x408)
+#define PRUSS_INTC_CHANMAP3		(PRUSS_INTC_BASE_ADDRESS + 0x40C)
+#define PRUSS_INTC_CHANMAP4		(PRUSS_INTC_BASE_ADDRESS + 0x410)
+#define PRUSS_INTC_CHANMAP5		(PRUSS_INTC_BASE_ADDRESS + 0x414)
+#define PRUSS_INTC_CHANMAP6		(PRUSS_INTC_BASE_ADDRESS + 0x418)
+#define PRUSS_INTC_CHANMAP7		(PRUSS_INTC_BASE_ADDRESS + 0x41C)
+#define PRUSS_INTC_CHANMAP8		(PRUSS_INTC_BASE_ADDRESS + 0x420)
+#define PRUSS_INTC_CHANMAP9		(PRUSS_INTC_BASE_ADDRESS + 0x424)
+#define PRUSS_INTC_CHANMAP10		(PRUSS_INTC_BASE_ADDRESS + 0x428)
+#define PRUSS_INTC_CHANMAP11		(PRUSS_INTC_BASE_ADDRESS + 0x42C)
+#define PRUSS_INTC_CHANMAP12		(PRUSS_INTC_BASE_ADDRESS + 0x430)
+#define PRUSS_INTC_CHANMAP13		(PRUSS_INTC_BASE_ADDRESS + 0x434)
+#define PRUSS_INTC_CHANMAP14		(PRUSS_INTC_BASE_ADDRESS + 0x438)
+#define PRUSS_INTC_CHANMAP15		(PRUSS_INTC_BASE_ADDRESS + 0x43C)
+#define PRUSS_INTC_HOSTMAP0		(PRUSS_INTC_BASE_ADDRESS + 0x800)
+#define PRUSS_INTC_HOSTMAP1		(PRUSS_INTC_BASE_ADDRESS + 0x804)
+#define PRUSS_INTC_HOSTMAP2		(PRUSS_INTC_BASE_ADDRESS + 0x808)
+#define PRUSS_INTC_POLARITY0		(PRUSS_INTC_BASE_ADDRESS + 0xD00)
+#define PRUSS_INTC_POLARITY1		(PRUSS_INTC_BASE_ADDRESS + 0xD04)
+#define PRUSS_INTC_TYPE0		(PRUSS_INTC_BASE_ADDRESS + 0xD80)
+#define PRUSS_INTC_TYPE1		(PRUSS_INTC_BASE_ADDRESS + 0xD84)
+#define PRUSS_INTC_HOSTINTEN		(PRUSS_INTC_BASE_ADDRESS + 0x1500)
+#define PRUSS_INTC_HOSTINTLVL_MAX	9
+
+#define PRU_INTC_CHAN_123_HOST		(0x03020100)
+#define PRU_INTC_CHAN_4567_HOST		(0x07060504)
+#define PRU_INTC_CHAN_89_HOST		(0x00000908)
+
+#define PRU_INTC_CHAN_0_SYSEVT_31	(0x00000000)
+#define PRU_INTC_CHAN_12_SYSEVT		(0x02020100)
+#define PRU_INTC_CHAN_34_SYSEVT_36_39	(0x04040303)
+#define PRU_INTC_CHAN_56_SYSEVT_40_43	(0x06060505)
+#define PRU_INTC_CHAN_78_SYSEVT_44_47	(0x08080707)
+#define PRU_INTC_CHAN_9_SYSEVT_48_49	(0x00010909)
+#define PRU_INTC_CHAN_0123_SYSEVT_32_35	(0x03020100)
+#define PRU_INTC_CHAN_4567_SYSEVT_36_39	(0x07060504)
+#define PRU_INTC_CHAN_8923_SYSEVT_40_43	(0x03020908)
+#define PRU_INTC_CHAN_4567_SYSEVT_44_47	(0x07060504)
+
+struct da8xx_pruss_devices {
+	const char *dev_name;
+	void *pdata;
+	size_t pdata_size;
+	int (*setup)(void);
+};
+
+u32 pruss_get_clk_freq(struct device *dev);
+
+u32 pruss_enable(struct device *dev, u8 pruss_num);
+
+u32 pruss_load(struct device *dev, u8 pruss_num, u32 *pruss_code,
+			u32 code_size_in_words);
+
+u32 pruss_run(struct device *dev, u8 pruss_num);
+
+u32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout);
+
+u32 pruss_disable(struct device *dev, u8 pruss_num);
+
+s16 pruss_writeb(struct device *dev, u32 u32offset,
+			u8 *pu8datatowrite, u16 u16wordstowrite);
+
+s16 pruss_readb(struct device *dev, u32 u32offset,
+			u8 *pu8datatoread, u16 u16wordstoread);
+
+s16 pruss_readl(struct device *dev, u32 u32offset,
+			u32 *pu32datatoread, s16 s16wordstoread);
+
+s16 pruss_writel(struct device *dev, u32 u32offset,
+			u32 *pu32datatoread, s16 s16wordstoread);
+
+s16 pruss_writew(struct device *dev, u32 u32offset,
+			u16 *u16datatowrite, s16 u16wordstowrite);
+
+s16 pruss_readw(struct device *dev, u32 u32offset,
+			u16 *pu32datatoread, s16 u16wordstoread);
+#endif	/* End _PRUSS_H_ */
diff --git a/include/linux/mfd/pruss/da8xx_prucore.h b/include/linux/mfd/pruss/da8xx_prucore.h
new file mode 100644
index 0000000..81f2ff9
--- /dev/null
+++ b/include/linux/mfd/pruss/da8xx_prucore.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _DA8XX_PRUCORE_H_
+#define _DA8XX_PRUCORE_H_
+
+#include <linux/types.h>
+
+#define DA8XX_PRUCORE_0		(0)
+#define DA8XX_PRUCORE_1		(1)
+
+#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_MASK			(0xFFFF0000u)
+#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_SHIFT			(0x00000010u)
+#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_MASK			(0x00008000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_SHIFT			(0x0000000Fu)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_RESETVAL			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_HALT			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_RUN			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_MASK			(0x00000100u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_SHIFT			(0x00000008u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_FREERUN		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_SINGLE			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK			(0x00000008u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT			(0x00000003u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_ENABLE		(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_MASK			(0x00000004u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_SHIFT			(0x00000002u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_RESETVAL			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_NOTASLEEP		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_ASLEEP			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_MASK			(0x00000002u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_RESETVAL			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_ENABLE			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_MASK			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_SHIFT			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_RESET			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET		(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_RESETVAL				(0x00000000u)
+
+typedef struct {
+	u32 CONTROL;
+	u32 STATUS;
+	u32 WAKEUP;
+	u32 CYCLECNT;
+	u32 STALLCNT;
+	u8  RSVD0[12];
+	u32 CONTABBLKIDX0;
+	u32 CONTABBLKIDX1;
+	u32 CONTABPROPTR0;
+	u32 CONTABPROPTR1;
+	u8  RSVD1[976];
+	u32 INTGPR[32];
+	u32 INTCTER[32];
+} *da8xx_prusscore_regs;
+
+#endif
-- 
1.7.2.3


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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the pruss MFD driver and associated include files.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/mfd/Kconfig                     |   10 +
 drivers/mfd/Makefile                    |    1 +
 drivers/mfd/da8xx_pru.c                 |  446 +++++++++++++++++++++++++++++++
 include/linux/mfd/pruss/da8xx_pru.h     |  122 +++++++++
 include/linux/mfd/pruss/da8xx_prucore.h |   74 +++++
 5 files changed, 653 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/da8xx_pru.c
 create mode 100644 include/linux/mfd/pruss/da8xx_pru.h
 create mode 100644 include/linux/mfd/pruss/da8xx_prucore.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fd01836..6c437df 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
 	  boards.  MSP430 firmware manages resets and power sequencing,
 	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
 
+config MFD_DA8XX_PRUSS
+	tristate "Texas Instruments DA8XX PRUSS support"
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	select MFD_CORE
+	help
+	    This driver provides support api's for the programmable
+		realtime unit (PRU) present on TI's da8xx processors. It
+		provides basic read, write, config, enable, disable
+		routines to facilitate devices emulated on it.
+
 config HTC_EGPIO
 	bool "HTC EGPIO support"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a54e2c7..670d6b0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
 obj-$(CONFIG_HTC_I2CPLD)	+= htc-i2cpld.o
 
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
+obj-$(CONFIG_MFD_DA8XX_PRUSS)	+= da8xx_pru.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 
 obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
diff --git a/drivers/mfd/da8xx_pru.c b/drivers/mfd/da8xx_pru.c
new file mode 100644
index 0000000..f7868a4
--- /dev/null
+++ b/drivers/mfd/da8xx_pru.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mfd/pruss/da8xx_prucore.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+#include <linux/mfd/core.h>
+#include <linux/io.h>
+#include <mach/da8xx.h>
+
+struct da8xx_pruss {
+	struct device *dev;
+	struct resource *res;
+	struct clk *clk;
+	u32 clk_freq;
+	void __iomem *ioaddr;
+};
+
+u32 pruss_get_clk_freq(struct device *dev)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+
+	return pruss->clk_freq;
+}
+EXPORT_SYMBOL(pruss_get_clk_freq);
+
+u32 pruss_disable(struct device *dev, u8 pruss_num)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+	u32 temp_reg;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* Disable PRU0  */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_ENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		/* Reset PRU0 */
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
+				&h_pruss->CONTROL);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* Disable PRU1 */
+		h_pruss = (da8xx_prusscore_regs)
+		((u32) pruss->ioaddr + 0x7800);
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		temp_reg = (temp_reg &
+				~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) |
+				((DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE <<
+				DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) &
+				DA8XX_PRUCORE_CONTROL_ENABLE_MASK);
+		__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+		/* Reset PRU1 */
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, &h_pruss->CONTROL);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(pruss_disable);
+
+u32 pruss_enable(struct device *dev, u8 pruss_num)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* Reset PRU0 */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
+			&h_pruss->CONTROL);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* Reset PRU1  */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7800);
+		__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
+			&h_pruss->CONTROL);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(pruss_enable);
+
+/* Load the specified PRU with code */
+u32 pruss_load(struct device *dev, u8 pruss_num,
+			u32 *pruss_code, u32 code_size_in_words)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pruss_iram;
+	u32 i;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		pruss_iram = (u32 *) ((u32) pruss->ioaddr + 0x8000);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		pruss_iram = (u32 *) ((u32) pruss->ioaddr + 0xc000);
+	} else
+		return -EINVAL;
+
+	pruss_enable(dev, pruss_num);
+
+	/* Copy dMAX code to its instruction RAM  */
+	for (i = 0; i < code_size_in_words; i++) {
+		__raw_writel(pruss_code[i], (pruss_iram + i));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pruss_load);
+
+u32 pruss_run(struct device *dev, u8 pruss_num)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+
+	u32 temp_reg;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* DA8XX_PRUCORE_0_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* DA8XX_PRUCORE_1_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7800);
+	} else
+		return -EINVAL;
+
+	/* Enable dMAX, let it execute the code we just copied */
+	temp_reg = __raw_readl(&h_pruss->CONTROL);
+	temp_reg = (temp_reg &
+			~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) |
+			((DA8XX_PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
+			DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+			DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK);
+	__raw_writel(temp_reg, &h_pruss->CONTROL);
+
+	temp_reg = __raw_readl(&h_pruss->CONTROL);
+	temp_reg = (temp_reg &
+			~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) |
+			((DA8XX_PRUCORE_CONTROL_ENABLE_ENABLE <<
+			DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) &
+			DA8XX_PRUCORE_CONTROL_ENABLE_MASK);
+	__raw_writel(temp_reg, &h_pruss->CONTROL);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_run);
+
+u32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	da8xx_prusscore_regs h_pruss;
+	u32 temp_reg;
+	u32 cnt = timeout;
+
+	if (pruss_num == DA8XX_PRUCORE_0) {
+		/* DA8XX_PRUCORE_0_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7000);
+	} else if (pruss_num == DA8XX_PRUCORE_1) {
+		/* DA8XX_PRUCORE_1_REGS; */
+		h_pruss = (da8xx_prusscore_regs)
+			((u32) pruss->ioaddr + 0x7800);
+	} else
+		return -EINVAL;
+
+	while (cnt--) {
+		temp_reg = __raw_readl(&h_pruss->CONTROL);
+		if (((temp_reg & DA8XX_PRUCORE_CONTROL_RUNSTATE_MASK) >>
+				DA8XX_PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
+					DA8XX_PRUCORE_CONTROL_RUNSTATE_HALT)
+			break;
+	}
+	if (cnt == 0)
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL(pruss_wait_for_halt);
+
+s16 pruss_writeb(struct device *dev, u32 u32offset,
+		u8 *pu8datatowrite, u16 u16bytestowrite)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u8 *pu8addresstowrite;
+	u16 u16loop;
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu8addresstowrite = (u8 *) (u32offset);
+
+	for (u16loop = 0; u16loop < u16bytestowrite; u16loop++)
+		__raw_writeb(*pu8datatowrite++, pu8addresstowrite++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_writeb);
+
+s16 pruss_readb(struct device *dev, u32 u32offset,
+		u8 *pu8datatoread, u16 u16bytestoread)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u8 *pu8addresstoread;
+	u16 u16loop;
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu8addresstoread = (u8 *) (u32offset);
+
+	for (u16loop = 0; u16loop < u16bytestoread; u16loop++)
+		*pu8datatoread++ = __raw_readb(pu8addresstoread++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_readb);
+
+s16 pruss_writel(struct device *dev, u32 u32offset,
+		u32 *pu32datatowrite, s16 u16wordstowrite)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstowrite;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstowrite = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstowrite; u16loop++)
+		__raw_writel(*pu32datatowrite++, pu32addresstowrite++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_writel);
+
+s16 pruss_readl(struct device *dev, u32 u32offset,
+		u32 *pu32datatoread, s16 u16wordstoread)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstoread;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstoread = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstoread; u16loop++)
+		*pu32datatoread++ = __raw_readl(pu32addresstoread++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_readl);
+
+s16 pruss_writew(struct device *dev, u32 u32offset,
+		u16 *pu16datatowrite, s16 u16wordstowrite)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstowrite;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstowrite = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstowrite; u16loop++) {
+		__raw_writew(*(pu16datatowrite++), (pu32addresstowrite++));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pruss_writew);
+
+s16 pruss_readw(struct device *dev, u32 u32offset,
+			u16 *pu16datatoread, s16 u16wordstoread)
+{
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
+	u32 *pu32addresstoread;
+	s16 u16loop;
+
+	/* TODO: Get all the driver API's fixed */
+	u32offset = (u32)pruss->ioaddr + u32offset;
+	pu32addresstoread = (u32 *)(u32offset);
+
+	for (u16loop = 0; u16loop < u16wordstoread; u16loop++)
+		*pu16datatoread++ = __raw_readw(pu32addresstoread++);
+	return 0;
+}
+EXPORT_SYMBOL(pruss_readw);
+
+static int pruss_mfd_add_devices(struct platform_device *pdev)
+{
+	struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct mfd_cell cell;
+	u32 err, count;
+
+	for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
+		memset(&cell, 0, sizeof(struct mfd_cell));
+		cell.id			= count;
+		cell.name		= (dev_data + count)->dev_name;
+		cell.platform_data	= (dev_data + count)->pdata;
+		cell.data_size		= (dev_data + count)->pdata_size;
+
+		err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
+		if (err) {
+			dev_err(dev, "cannot add mfd cells\n");
+			return err;
+		}
+	}
+	return err;
+}
+
+static int __devinit da8xx_pruss_probe(struct platform_device *pdev)
+{
+	struct da8xx_pruss *pruss_dev = NULL;
+	u32 err;
+
+	pruss_dev = kzalloc(sizeof(struct da8xx_pruss), GFP_KERNEL);
+	if (!pruss_dev)
+		return -ENOMEM;
+
+	pruss_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!pruss_dev->res) {
+		dev_err(&pdev->dev,
+		"unable to get pruss memory resources!\n");
+		err = -ENODEV;
+		goto probe_exit_kfree;
+	}
+
+	if (!request_mem_region(pruss_dev->res->start, resource_size(pruss_dev->res),
+		dev_name(&pdev->dev))) {
+		dev_err(&pdev->dev, "pruss memory region already claimed!\n");
+		err = -EBUSY;
+		goto probe_exit_kfree;
+	}
+
+	pruss_dev->ioaddr = ioremap(pruss_dev->res->start,
+	resource_size(pruss_dev->res));
+	if (!pruss_dev->ioaddr) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		err = -ENOMEM;
+		goto probe_exit_free_region;
+	}
+
+	pruss_dev->clk = clk_get(NULL, "pruss");
+	if (IS_ERR(pruss_dev->clk)) {
+		dev_err(&pdev->dev, "no clock available: pruss\n");
+		err = -ENODEV;
+		pruss_dev->clk = NULL;
+		goto probe_exit_iounmap;
+	}
+
+	clk_enable(pruss_dev->clk);
+	pruss_dev->clk_freq = clk_get_rate(pruss_dev->clk);
+
+	err = pruss_mfd_add_devices(pdev);
+	if (err)
+		goto probe_exit_clock;
+
+	platform_set_drvdata(pdev, pruss_dev);
+	pruss_dev->dev = &pdev->dev;
+	return 0;
+
+probe_exit_clock:
+	clk_put(pruss_dev->clk);
+	clk_disable(pruss_dev->clk);
+probe_exit_iounmap:
+	iounmap(pruss_dev->ioaddr);
+probe_exit_free_region:
+	release_mem_region(pruss_dev->res->start, resource_size(pruss_dev->res));
+probe_exit_kfree:
+	kfree(pruss_dev);
+	return err;
+}
+
+static int __devexit da8xx_pruss_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da8xx_pruss *pruss = dev_get_drvdata(dev);
+
+	mfd_remove_devices(dev);
+	clk_disable(pruss->clk);
+	clk_put(pruss->clk);
+	iounmap(pruss->ioaddr);
+	release_mem_region(pruss->res->start, resource_size(pruss->res));
+	kfree(pruss);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static struct platform_driver da8xx_pruss_driver = {
+	.probe	= da8xx_pruss_probe,
+	.remove	= __devexit_p(da8xx_pruss_remove),
+	.driver	= {
+		.name	= "da8xx_pruss",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init da8xx_pruss_init(void)
+{
+	return platform_driver_register(&da8xx_pruss_driver);
+}
+module_init(da8xx_pruss_init);
+
+static void __exit da8xx_pruss_exit(void)
+{
+	platform_driver_unregister(&da8xx_pruss_driver);
+}
+module_exit(da8xx_pruss_exit);
+
+MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
+MODULE_AUTHOR("Subhasish Ghosh");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
new file mode 100644
index 0000000..68d8421
--- /dev/null
+++ b/include/linux/mfd/pruss/da8xx_pru.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _PRUSS_H_
+#define _PRUSS_H_
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include "da8xx_prucore.h"
+
+#define PRUSS_NUM0			DA8XX_PRUCORE_0
+#define PRUSS_NUM1			DA8XX_PRUCORE_1
+
+#define PRUSS_PRU0_BASE_ADDRESS		0
+#define PRUSS_INTC_BASE_ADDRESS		(PRUSS_PRU0_BASE_ADDRESS + 0x4000)
+#define PRUSS_INTC_GLBLEN		(PRUSS_INTC_BASE_ADDRESS + 0x10)
+#define PRUSS_INTC_GLBLNSTLVL		(PRUSS_INTC_BASE_ADDRESS + 0x1C)
+#define PRUSS_INTC_STATIDXSET		(PRUSS_INTC_BASE_ADDRESS + 0x20)
+#define PRUSS_INTC_STATIDXCLR		(PRUSS_INTC_BASE_ADDRESS + 0x24)
+#define PRUSS_INTC_ENIDXSET		(PRUSS_INTC_BASE_ADDRESS + 0x28)
+#define PRUSS_INTC_ENIDXCLR		(PRUSS_INTC_BASE_ADDRESS + 0x2C)
+#define PRUSS_INTC_HSTINTENIDXSET	(PRUSS_INTC_BASE_ADDRESS + 0x34)
+#define PRUSS_INTC_HSTINTENIDXCLR	(PRUSS_INTC_BASE_ADDRESS + 0x38)
+#define PRUSS_INTC_GLBLPRIIDX		(PRUSS_INTC_BASE_ADDRESS + 0x80)
+#define PRUSS_INTC_STATSETINT0		(PRUSS_INTC_BASE_ADDRESS + 0x200)
+#define PRUSS_INTC_STATSETINT1		(PRUSS_INTC_BASE_ADDRESS + 0x204)
+#define PRUSS_INTC_STATCLRINT0		(PRUSS_INTC_BASE_ADDRESS + 0x280)
+#define PRUSS_INTC_STATCLRINT1		(PRUSS_INTC_BASE_ADDRESS + 0x284)
+#define PRUSS_INTC_ENABLESET0		(PRUSS_INTC_BASE_ADDRESS + 0x300)
+#define PRUSS_INTC_ENABLESET1		(PRUSS_INTC_BASE_ADDRESS + 0x304)
+#define PRUSS_INTC_ENABLECLR0		(PRUSS_INTC_BASE_ADDRESS + 0x380)
+#define PRUSS_INTC_ENABLECLR1		(PRUSS_INTC_BASE_ADDRESS + 0x384)
+#define PRUSS_INTC_CHANMAP0		(PRUSS_INTC_BASE_ADDRESS + 0x400)
+#define PRUSS_INTC_CHANMAP1		(PRUSS_INTC_BASE_ADDRESS + 0x404)
+#define PRUSS_INTC_CHANMAP2		(PRUSS_INTC_BASE_ADDRESS + 0x408)
+#define PRUSS_INTC_CHANMAP3		(PRUSS_INTC_BASE_ADDRESS + 0x40C)
+#define PRUSS_INTC_CHANMAP4		(PRUSS_INTC_BASE_ADDRESS + 0x410)
+#define PRUSS_INTC_CHANMAP5		(PRUSS_INTC_BASE_ADDRESS + 0x414)
+#define PRUSS_INTC_CHANMAP6		(PRUSS_INTC_BASE_ADDRESS + 0x418)
+#define PRUSS_INTC_CHANMAP7		(PRUSS_INTC_BASE_ADDRESS + 0x41C)
+#define PRUSS_INTC_CHANMAP8		(PRUSS_INTC_BASE_ADDRESS + 0x420)
+#define PRUSS_INTC_CHANMAP9		(PRUSS_INTC_BASE_ADDRESS + 0x424)
+#define PRUSS_INTC_CHANMAP10		(PRUSS_INTC_BASE_ADDRESS + 0x428)
+#define PRUSS_INTC_CHANMAP11		(PRUSS_INTC_BASE_ADDRESS + 0x42C)
+#define PRUSS_INTC_CHANMAP12		(PRUSS_INTC_BASE_ADDRESS + 0x430)
+#define PRUSS_INTC_CHANMAP13		(PRUSS_INTC_BASE_ADDRESS + 0x434)
+#define PRUSS_INTC_CHANMAP14		(PRUSS_INTC_BASE_ADDRESS + 0x438)
+#define PRUSS_INTC_CHANMAP15		(PRUSS_INTC_BASE_ADDRESS + 0x43C)
+#define PRUSS_INTC_HOSTMAP0		(PRUSS_INTC_BASE_ADDRESS + 0x800)
+#define PRUSS_INTC_HOSTMAP1		(PRUSS_INTC_BASE_ADDRESS + 0x804)
+#define PRUSS_INTC_HOSTMAP2		(PRUSS_INTC_BASE_ADDRESS + 0x808)
+#define PRUSS_INTC_POLARITY0		(PRUSS_INTC_BASE_ADDRESS + 0xD00)
+#define PRUSS_INTC_POLARITY1		(PRUSS_INTC_BASE_ADDRESS + 0xD04)
+#define PRUSS_INTC_TYPE0		(PRUSS_INTC_BASE_ADDRESS + 0xD80)
+#define PRUSS_INTC_TYPE1		(PRUSS_INTC_BASE_ADDRESS + 0xD84)
+#define PRUSS_INTC_HOSTINTEN		(PRUSS_INTC_BASE_ADDRESS + 0x1500)
+#define PRUSS_INTC_HOSTINTLVL_MAX	9
+
+#define PRU_INTC_CHAN_123_HOST		(0x03020100)
+#define PRU_INTC_CHAN_4567_HOST		(0x07060504)
+#define PRU_INTC_CHAN_89_HOST		(0x00000908)
+
+#define PRU_INTC_CHAN_0_SYSEVT_31	(0x00000000)
+#define PRU_INTC_CHAN_12_SYSEVT		(0x02020100)
+#define PRU_INTC_CHAN_34_SYSEVT_36_39	(0x04040303)
+#define PRU_INTC_CHAN_56_SYSEVT_40_43	(0x06060505)
+#define PRU_INTC_CHAN_78_SYSEVT_44_47	(0x08080707)
+#define PRU_INTC_CHAN_9_SYSEVT_48_49	(0x00010909)
+#define PRU_INTC_CHAN_0123_SYSEVT_32_35	(0x03020100)
+#define PRU_INTC_CHAN_4567_SYSEVT_36_39	(0x07060504)
+#define PRU_INTC_CHAN_8923_SYSEVT_40_43	(0x03020908)
+#define PRU_INTC_CHAN_4567_SYSEVT_44_47	(0x07060504)
+
+struct da8xx_pruss_devices {
+	const char *dev_name;
+	void *pdata;
+	size_t pdata_size;
+	int (*setup)(void);
+};
+
+u32 pruss_get_clk_freq(struct device *dev);
+
+u32 pruss_enable(struct device *dev, u8 pruss_num);
+
+u32 pruss_load(struct device *dev, u8 pruss_num, u32 *pruss_code,
+			u32 code_size_in_words);
+
+u32 pruss_run(struct device *dev, u8 pruss_num);
+
+u32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout);
+
+u32 pruss_disable(struct device *dev, u8 pruss_num);
+
+s16 pruss_writeb(struct device *dev, u32 u32offset,
+			u8 *pu8datatowrite, u16 u16wordstowrite);
+
+s16 pruss_readb(struct device *dev, u32 u32offset,
+			u8 *pu8datatoread, u16 u16wordstoread);
+
+s16 pruss_readl(struct device *dev, u32 u32offset,
+			u32 *pu32datatoread, s16 s16wordstoread);
+
+s16 pruss_writel(struct device *dev, u32 u32offset,
+			u32 *pu32datatoread, s16 s16wordstoread);
+
+s16 pruss_writew(struct device *dev, u32 u32offset,
+			u16 *u16datatowrite, s16 u16wordstowrite);
+
+s16 pruss_readw(struct device *dev, u32 u32offset,
+			u16 *pu32datatoread, s16 u16wordstoread);
+#endif	/* End _PRUSS_H_ */
diff --git a/include/linux/mfd/pruss/da8xx_prucore.h b/include/linux/mfd/pruss/da8xx_prucore.h
new file mode 100644
index 0000000..81f2ff9
--- /dev/null
+++ b/include/linux/mfd/pruss/da8xx_prucore.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _DA8XX_PRUCORE_H_
+#define _DA8XX_PRUCORE_H_
+
+#include <linux/types.h>
+
+#define DA8XX_PRUCORE_0		(0)
+#define DA8XX_PRUCORE_1		(1)
+
+#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_MASK			(0xFFFF0000u)
+#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_SHIFT			(0x00000010u)
+#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_MASK			(0x00008000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_SHIFT			(0x0000000Fu)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_RESETVAL			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_HALT			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_RUNSTATE_RUN			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_MASK			(0x00000100u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_SHIFT			(0x00000008u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_FREERUN		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_SINGLE			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK			(0x00000008u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT			(0x00000003u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_ENABLE		(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_MASK			(0x00000004u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_SHIFT			(0x00000002u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_RESETVAL			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_NOTASLEEP		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SLEEPING_ASLEEP			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_MASK			(0x00000002u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_RESETVAL			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_ENABLE_ENABLE			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_MASK			(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_SHIFT			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_RESETVAL		(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_RESET			(0x00000000u)
+#define DA8XX_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET		(0x00000001u)
+#define DA8XX_PRUCORE_CONTROL_RESETVAL				(0x00000000u)
+
+typedef struct {
+	u32 CONTROL;
+	u32 STATUS;
+	u32 WAKEUP;
+	u32 CYCLECNT;
+	u32 STALLCNT;
+	u8  RSVD0[12];
+	u32 CONTABBLKIDX0;
+	u32 CONTABBLKIDX1;
+	u32 CONTABPROPTR0;
+	u32 CONTABPROPTR1;
+	u8  RSVD1[976];
+	u32 INTGPR[32];
+	u32 INTCTER[32];
+} *da8xx_prusscore_regs;
+
+#endif
-- 
1.7.2.3

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

* [PATCH v2 02/13] da850: pruss platform specific additions.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, Michael Williamson,
	Cyril Chemparathy, Sergei Shtylyov, open list

This patch adds the platform device and assignes the platform resources
for the PRUSS mfd driver.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/da850.c              |    7 +++
 arch/arm/mach-davinci/devices-da8xx.c      |   65 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    2 +
 3 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 8a4de97..a098263 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -238,6 +238,12 @@ static struct clk tptc2_clk = {
 	.flags		= ALWAYS_ENABLED,
 };
 
+static struct clk pruss_clk = {
+	.name		= "pruss",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA8XX_LPSC0_PRUSS,
+};
+
 static struct clk uart0_clk = {
 	.name		= "uart0",
 	.parent		= &pll0_sysclk2,
@@ -387,6 +393,7 @@ static struct clk_lookup da850_clks[] = {
 	CLK(NULL,		"tpcc1",	&tpcc1_clk),
 	CLK(NULL,		"tptc2",	&tptc2_clk),
 	CLK(NULL,		"uart0",	&uart0_clk),
+	CLK(NULL,		"pruss",	&pruss_clk),
 	CLK(NULL,		"uart1",	&uart1_clk),
 	CLK(NULL,		"uart2",	&uart2_clk),
 	CLK(NULL,		"aintc",	&aintc_clk),
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index beda8a4..e15de72 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -20,6 +20,7 @@
 #include <mach/time.h>
 #include <mach/da8xx.h>
 #include <mach/cpuidle.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
 
 #include "clock.h"
 
@@ -499,6 +500,70 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 	}
 }
 
+#define DA8XX_PRUSS_MEM_BASE		0x01C30000
+
+static struct resource da8xx_pruss_resources[] = {
+	{
+		.name	= "da8xx_pruss",
+		.start	= DA8XX_PRUSS_MEM_BASE,
+		.end	= DA8XX_PRUSS_MEM_BASE + 0xFFFF,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT0,
+		.end	= IRQ_DA8XX_EVTOUT0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT1,
+		.end	= IRQ_DA8XX_EVTOUT1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT2,
+		.end	= IRQ_DA8XX_EVTOUT2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT3,
+		.end	= IRQ_DA8XX_EVTOUT3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT4,
+		.end	= IRQ_DA8XX_EVTOUT4,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT5,
+		.end	= IRQ_DA8XX_EVTOUT5,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT6,
+		.end	= IRQ_DA8XX_EVTOUT6,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT7,
+		.end	= IRQ_DA8XX_EVTOUT7,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device da8xx_pruss_dev = {
+	.name		= "da8xx_pruss",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(da8xx_pruss_resources),
+	.resource	= da8xx_pruss_resources,
+};
+
+int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
+{
+	da8xx_pruss_dev.dev.platform_data = pruss_device;
+	return platform_device_register(&da8xx_pruss_dev);
+}
+
 static const struct display_panel disp_panel = {
 	QVGA,
 	16,
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index c3c3339..2c400d4 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -15,6 +15,7 @@
 
 #include <linux/platform_device.h>
 #include <linux/davinci_emac.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
 
 #include <mach/serial.h>
 #include <mach/edma.h>
@@ -82,6 +83,7 @@ int da8xx_register_watchdog(void);
 int da8xx_register_usb20(unsigned mA, unsigned potpgt);
 int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
 int da8xx_register_emac(void);
+int da8xx_register_pruss(struct da8xx_pruss_devices *);
 int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
 int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
 int da850_register_mmcsd1(struct davinci_mmc_config *config);
-- 
1.7.2.3


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

* [PATCH v2 02/13] da850: pruss platform specific additions.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the platform device and assignes the platform resources
for the PRUSS mfd driver.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/da850.c              |    7 +++
 arch/arm/mach-davinci/devices-da8xx.c      |   65 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    2 +
 3 files changed, 74 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 8a4de97..a098263 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -238,6 +238,12 @@ static struct clk tptc2_clk = {
 	.flags		= ALWAYS_ENABLED,
 };
 
+static struct clk pruss_clk = {
+	.name		= "pruss",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA8XX_LPSC0_PRUSS,
+};
+
 static struct clk uart0_clk = {
 	.name		= "uart0",
 	.parent		= &pll0_sysclk2,
@@ -387,6 +393,7 @@ static struct clk_lookup da850_clks[] = {
 	CLK(NULL,		"tpcc1",	&tpcc1_clk),
 	CLK(NULL,		"tptc2",	&tptc2_clk),
 	CLK(NULL,		"uart0",	&uart0_clk),
+	CLK(NULL,		"pruss",	&pruss_clk),
 	CLK(NULL,		"uart1",	&uart1_clk),
 	CLK(NULL,		"uart2",	&uart2_clk),
 	CLK(NULL,		"aintc",	&aintc_clk),
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index beda8a4..e15de72 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -20,6 +20,7 @@
 #include <mach/time.h>
 #include <mach/da8xx.h>
 #include <mach/cpuidle.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
 
 #include "clock.h"
 
@@ -499,6 +500,70 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 	}
 }
 
+#define DA8XX_PRUSS_MEM_BASE		0x01C30000
+
+static struct resource da8xx_pruss_resources[] = {
+	{
+		.name	= "da8xx_pruss",
+		.start	= DA8XX_PRUSS_MEM_BASE,
+		.end	= DA8XX_PRUSS_MEM_BASE + 0xFFFF,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT0,
+		.end	= IRQ_DA8XX_EVTOUT0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT1,
+		.end	= IRQ_DA8XX_EVTOUT1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT2,
+		.end	= IRQ_DA8XX_EVTOUT2,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT3,
+		.end	= IRQ_DA8XX_EVTOUT3,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT4,
+		.end	= IRQ_DA8XX_EVTOUT4,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT5,
+		.end	= IRQ_DA8XX_EVTOUT5,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT6,
+		.end	= IRQ_DA8XX_EVTOUT6,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= IRQ_DA8XX_EVTOUT7,
+		.end	= IRQ_DA8XX_EVTOUT7,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device da8xx_pruss_dev = {
+	.name		= "da8xx_pruss",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(da8xx_pruss_resources),
+	.resource	= da8xx_pruss_resources,
+};
+
+int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
+{
+	da8xx_pruss_dev.dev.platform_data = pruss_device;
+	return platform_device_register(&da8xx_pruss_dev);
+}
+
 static const struct display_panel disp_panel = {
 	QVGA,
 	16,
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index c3c3339..2c400d4 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -15,6 +15,7 @@
 
 #include <linux/platform_device.h>
 #include <linux/davinci_emac.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
 
 #include <mach/serial.h>
 #include <mach/edma.h>
@@ -82,6 +83,7 @@ int da8xx_register_watchdog(void);
 int da8xx_register_usb20(unsigned mA, unsigned potpgt);
 int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
 int da8xx_register_emac(void);
+int da8xx_register_pruss(struct da8xx_pruss_devices *);
 int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
 int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
 int da850_register_mmcsd1(struct davinci_mmc_config *config);
-- 
1.7.2.3

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

* [PATCH v2 03/13] da850: pruss board specific additions.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, open list

This patch adds board specific initializations and setup routines.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 11f986b..242d1ed 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static struct da8xx_pruss_devices pruss_devices[] = {
+	{.dev_name = NULL,},
+};
+
+static int __init da8xx_evm_setup_pruss(void)
+{
+	u32 ret = 0;
+	u32 count;
+
+	for (count = 0; count < ARRAY_SIZE(pruss_devices); count++) {
+		if (pruss_devices[count].setup != NULL) {
+			ret = pruss_devices[count].setup();
+			if (ret)
+				return ret;
+		}
+	}
+
+	return da8xx_register_pruss(pruss_devices);
+}
+
 static __init void da850_evm_init(void)
 {
 	int ret;
@@ -1127,6 +1147,11 @@ static __init void da850_evm_init(void)
 
 	da8xx_register_mcasp(0, &da850_evm_snd_data);
 
+	ret = da8xx_evm_setup_pruss();
+	if (ret)
+		pr_warning("%s: pruss initialization failed: %d\n",
+				__func__, ret);
+
 	ret = davinci_cfg_reg_list(da850_lcdcntl_pins);
 	if (ret)
 		pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
-- 
1.7.2.3


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

* [PATCH v2 03/13] da850: pruss board specific additions.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds board specific initializations and setup routines.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 11f986b..242d1ed 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static struct da8xx_pruss_devices pruss_devices[] = {
+	{.dev_name = NULL,},
+};
+
+static int __init da8xx_evm_setup_pruss(void)
+{
+	u32 ret = 0;
+	u32 count;
+
+	for (count = 0; count < ARRAY_SIZE(pruss_devices); count++) {
+		if (pruss_devices[count].setup != NULL) {
+			ret = pruss_devices[count].setup();
+			if (ret)
+				return ret;
+		}
+	}
+
+	return da8xx_register_pruss(pruss_devices);
+}
+
 static __init void da850_evm_init(void)
 {
 	int ret;
@@ -1127,6 +1147,11 @@ static __init void da850_evm_init(void)
 
 	da8xx_register_mcasp(0, &da850_evm_snd_data);
 
+	ret = da8xx_evm_setup_pruss();
+	if (ret)
+		pr_warning("%s: pruss initialization failed: %d\n",
+				__func__, ret);
+
 	ret = davinci_cfg_reg_list(da850_lcdcntl_pins);
 	if (ret)
 		pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
-- 
1.7.2.3

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

* [PATCH v2 04/13] mfd: pruss CAN private data.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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, open list

This patch adds the PRUSS CAN data.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 include/linux/mfd/pruss/da8xx_pru.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
index 68d8421..50f2ede 100644
--- a/include/linux/mfd/pruss/da8xx_pru.h
+++ b/include/linux/mfd/pruss/da8xx_pru.h
@@ -89,6 +89,10 @@ struct da8xx_pruss_devices {
 	int (*setup)(void);
 };
 
+struct da8xx_pruss_can_data {
+	u32 version;
+};
+
 u32 pruss_get_clk_freq(struct device *dev);
 
 u32 pruss_enable(struct device *dev, u8 pruss_num);
-- 
1.7.2.3


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

* [PATCH v2 04/13] mfd: pruss CAN private data.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the PRUSS CAN data.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 include/linux/mfd/pruss/da8xx_pru.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
index 68d8421..50f2ede 100644
--- a/include/linux/mfd/pruss/da8xx_pru.h
+++ b/include/linux/mfd/pruss/da8xx_pru.h
@@ -89,6 +89,10 @@ struct da8xx_pruss_devices {
 	int (*setup)(void);
 };
 
+struct da8xx_pruss_can_data {
+	u32 version;
+};
+
 u32 pruss_get_clk_freq(struct device *dev);
 
 u32 pruss_enable(struct device *dev, u8 pruss_num);
-- 
1.7.2.3

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

* [PATCH v2 05/13] da850: pruss CAN platform specific additions.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, Thomas Koeller, Cyril Chemparathy,
	Victor Rodriguez, open list

This patch adds the necessary pins for the pruss CAN.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/da850.c            |    4 ++++
 arch/arm/mach-davinci/include/mach/mux.h |    4 ++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a098263..4862c28 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -565,6 +565,10 @@ static const struct mux_config da850_pins[] = {
 	MUX_CFG(DA850, EMA_CLK,		6,	0,	15,	1,	false)
 	MUX_CFG(DA850, EMA_WAIT_1,	6,	24,	15,	1,	false)
 	MUX_CFG(DA850, NEMA_CS_2,	7,	0,	15,	1,	false)
+	/* PRU functions for soft CAN */
+	MUX_CFG(DA850, PRUSS_PRU0_R31_0,	7,	28,	15,	0,	false)
+	MUX_CFG(DA850, PRUSS_PRU1_R30_15,	12,	0,	15,	4,	false)
+	MUX_CFG(DA850, PRUSS_PRU1_R31_18,	11,	20,	15,	0,	false)
 	/* GPIO function */
 	MUX_CFG(DA850, GPIO2_4,		6,	12,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_6,		6,	4,	15,	8,	false)
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index 5d4e0fe..10f49f2 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -906,6 +906,10 @@ enum davinci_da850_index {
 	DA850_EMA_CLK,
 	DA850_EMA_WAIT_1,
 	DA850_NEMA_CS_2,
+	/* PRU I/O */
+	DA850_PRUSS_PRU0_R31_0,
+	DA850_PRUSS_PRU1_R30_15,
+	DA850_PRUSS_PRU1_R31_18,
 
 	/* GPIO function */
 	DA850_GPIO2_4,
-- 
1.7.2.3


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

* [PATCH v2 05/13] da850: pruss CAN platform specific additions.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the necessary pins for the pruss CAN.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/da850.c            |    4 ++++
 arch/arm/mach-davinci/include/mach/mux.h |    4 ++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a098263..4862c28 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -565,6 +565,10 @@ static const struct mux_config da850_pins[] = {
 	MUX_CFG(DA850, EMA_CLK,		6,	0,	15,	1,	false)
 	MUX_CFG(DA850, EMA_WAIT_1,	6,	24,	15,	1,	false)
 	MUX_CFG(DA850, NEMA_CS_2,	7,	0,	15,	1,	false)
+	/* PRU functions for soft CAN */
+	MUX_CFG(DA850, PRUSS_PRU0_R31_0,	7,	28,	15,	0,	false)
+	MUX_CFG(DA850, PRUSS_PRU1_R30_15,	12,	0,	15,	4,	false)
+	MUX_CFG(DA850, PRUSS_PRU1_R31_18,	11,	20,	15,	0,	false)
 	/* GPIO function */
 	MUX_CFG(DA850, GPIO2_4,		6,	12,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_6,		6,	4,	15,	8,	false)
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index 5d4e0fe..10f49f2 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -906,6 +906,10 @@ enum davinci_da850_index {
 	DA850_EMA_CLK,
 	DA850_EMA_WAIT_1,
 	DA850_NEMA_CS_2,
+	/* PRU I/O */
+	DA850_PRUSS_PRU0_R31_0,
+	DA850_PRUSS_PRU1_R30_15,
+	DA850_PRUSS_PRU1_R31_18,
 
 	/* GPIO function */
 	DA850_GPIO2_4,
-- 
1.7.2.3

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

* [PATCH v2 06/13] da850: pruss CAN board specific additions.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, open list

This patch adds the pruss CAN pin mux and registers the device
with the pruss mfd driver.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   37 ++++++++++++++++++++++++++++++-
 1 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 242d1ed..2ce5536 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+const short da850_evm_pruss_can_pins[] = {
+	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
+	DA850_PRUSS_PRU1_R31_18,
+	-1
+};
+
+static int __init da850_evm_setup_pruss_can(void)
+{
+	int ret, val = 0;
+	void __iomem *cfg_chip3_reg;
+
+	ret = davinci_cfg_reg_list(da850_evm_pruss_can_pins);
+	if (ret)
+		pr_warning("%s: da850_evm_pruss_can_pins mux setup "
+					"failed:%d\n", __func__, ret);
+	cfg_chip3_reg = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+	val = __raw_readl(cfg_chip3_reg);
+	val |= BIT(3);
+	__raw_writel(val, cfg_chip3_reg);
+
+	return ret;
+}
+
+static struct da8xx_pruss_can_data can_data = {
+	.version	= 1,
+};
+
 static struct da8xx_pruss_devices pruss_devices[] = {
-	{.dev_name = NULL,},
+	{
+		.dev_name	= "da8xx_pruss_can",
+		.pdata		= &can_data,
+		.pdata_size	= sizeof(can_data),
+		.setup		= da850_evm_setup_pruss_can,
+	},
+	{
+		.dev_name	= NULL,
+	},
 };
 
 static int __init da8xx_evm_setup_pruss(void)
-- 
1.7.2.3


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

* [PATCH v2 06/13] da850: pruss CAN board specific additions.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the pruss CAN pin mux and registers the device
with the pruss mfd driver.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   37 ++++++++++++++++++++++++++++++-
 1 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 242d1ed..2ce5536 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+const short da850_evm_pruss_can_pins[] = {
+	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
+	DA850_PRUSS_PRU1_R31_18,
+	-1
+};
+
+static int __init da850_evm_setup_pruss_can(void)
+{
+	int ret, val = 0;
+	void __iomem *cfg_chip3_reg;
+
+	ret = davinci_cfg_reg_list(da850_evm_pruss_can_pins);
+	if (ret)
+		pr_warning("%s: da850_evm_pruss_can_pins mux setup "
+					"failed:%d\n", __func__, ret);
+	cfg_chip3_reg = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+	val = __raw_readl(cfg_chip3_reg);
+	val |= BIT(3);
+	__raw_writel(val, cfg_chip3_reg);
+
+	return ret;
+}
+
+static struct da8xx_pruss_can_data can_data = {
+	.version	= 1,
+};
+
 static struct da8xx_pruss_devices pruss_devices[] = {
-	{.dev_name = NULL,},
+	{
+		.dev_name	= "da8xx_pruss_can",
+		.pdata		= &can_data,
+		.pdata_size	= sizeof(can_data),
+		.setup		= da850_evm_setup_pruss_can,
+	},
+	{
+		.dev_name	= NULL,
+	},
 };
 
 static int __init da8xx_evm_setup_pruss(void)
-- 
1.7.2.3

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

* [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, Thomas Koeller, Cyril Chemparathy,
	Victor Rodriguez, open list

This patch adds the GPIOs for the pruss CAN device.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/da850.c            |    1 +
 arch/arm/mach-davinci/include/mach/mux.h |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 4862c28..a15571d 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -570,6 +570,7 @@ static const struct mux_config da850_pins[] = {
 	MUX_CFG(DA850, PRUSS_PRU1_R30_15,	12,	0,	15,	4,	false)
 	MUX_CFG(DA850, PRUSS_PRU1_R31_18,	11,	20,	15,	0,	false)
 	/* GPIO function */
+	MUX_CFG(DA850, GPIO2_0,		6,	28,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_4,		6,	12,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_6,		6,	4,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_8,		5,	28,	15,	8,	false)
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index 10f49f2..85b3a0d 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -912,6 +912,7 @@ enum davinci_da850_index {
 	DA850_PRUSS_PRU1_R31_18,
 
 	/* GPIO function */
+	DA850_GPIO2_0,
 	DA850_GPIO2_4,
 	DA850_GPIO2_6,
 	DA850_GPIO2_8,
-- 
1.7.2.3


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

* [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the GPIOs for the pruss CAN device.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/da850.c            |    1 +
 arch/arm/mach-davinci/include/mach/mux.h |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 4862c28..a15571d 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -570,6 +570,7 @@ static const struct mux_config da850_pins[] = {
 	MUX_CFG(DA850, PRUSS_PRU1_R30_15,	12,	0,	15,	4,	false)
 	MUX_CFG(DA850, PRUSS_PRU1_R31_18,	11,	20,	15,	0,	false)
 	/* GPIO function */
+	MUX_CFG(DA850, GPIO2_0,		6,	28,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_4,		6,	12,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_6,		6,	4,	15,	8,	false)
 	MUX_CFG(DA850, GPIO2_8,		5,	28,	15,	8,	false)
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index 10f49f2..85b3a0d 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -912,6 +912,7 @@ enum davinci_da850_index {
 	DA850_PRUSS_PRU1_R31_18,
 
 	/* GPIO function */
+	DA850_GPIO2_0,
 	DA850_GPIO2_4,
 	DA850_GPIO2_6,
 	DA850_GPIO2_8,
-- 
1.7.2.3

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

* [PATCH v2 08/13] da850: pruss CAN board specific changes for gpios.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, open list

This patch adds the GPIO modifications required for the pruss CAN.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 2ce5536..f9c38f8 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -45,6 +45,7 @@
 
 #define DA850_MMCSD_CD_PIN		GPIO_TO_PIN(4, 0)
 #define DA850_MMCSD_WP_PIN		GPIO_TO_PIN(4, 1)
+#define DA850_PRUSS_CAN_TRX_PIN	GPIO_TO_PIN(2, 0)
 
 #define DA850_MII_MDIO_CLKEN_PIN	GPIO_TO_PIN(2, 6)
 
@@ -1055,7 +1056,7 @@ static __init int da850_evm_init_cpufreq(void) { return 0; }
 
 const short da850_evm_pruss_can_pins[] = {
 	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
-	DA850_PRUSS_PRU1_R31_18,
+	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
 	-1
 };
 
@@ -1073,6 +1074,14 @@ static int __init da850_evm_setup_pruss_can(void)
 	val |= BIT(3);
 	__raw_writel(val, cfg_chip3_reg);
 
+	/* value = 0 to enable the CAN transceiver */
+	ret = gpio_request_one(DA850_PRUSS_CAN_TRX_PIN,
+					GPIOF_OUT_INIT_LOW, "pruss_can_en");
+	if (ret) {
+		pr_warning("Cannot setup GPIO %d\n", DA850_PRUSS_CAN_TRX_PIN);
+		gpio_free(DA850_PRUSS_CAN_TRX_PIN);
+	}
+
 	return ret;
 }
 
-- 
1.7.2.3


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

* [PATCH v2 08/13] da850: pruss CAN board specific changes for gpios.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the GPIO modifications required for the pruss CAN.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 2ce5536..f9c38f8 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -45,6 +45,7 @@
 
 #define DA850_MMCSD_CD_PIN		GPIO_TO_PIN(4, 0)
 #define DA850_MMCSD_WP_PIN		GPIO_TO_PIN(4, 1)
+#define DA850_PRUSS_CAN_TRX_PIN	GPIO_TO_PIN(2, 0)
 
 #define DA850_MII_MDIO_CLKEN_PIN	GPIO_TO_PIN(2, 6)
 
@@ -1055,7 +1056,7 @@ static __init int da850_evm_init_cpufreq(void) { return 0; }
 
 const short da850_evm_pruss_can_pins[] = {
 	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
-	DA850_PRUSS_PRU1_R31_18,
+	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
 	-1
 };
 
@@ -1073,6 +1074,14 @@ static int __init da850_evm_setup_pruss_can(void)
 	val |= BIT(3);
 	__raw_writel(val, cfg_chip3_reg);
 
+	/* value = 0 to enable the CAN transceiver */
+	ret = gpio_request_one(DA850_PRUSS_CAN_TRX_PIN,
+					GPIOF_OUT_INIT_LOW, "pruss_can_en");
+	if (ret) {
+		pr_warning("Cannot setup GPIO %d\n", DA850_PRUSS_CAN_TRX_PIN);
+		gpio_free(DA850_PRUSS_CAN_TRX_PIN);
+	}
+
 	return ret;
 }
 
-- 
1.7.2.3

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

* [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

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 at 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] 157+ messages in thread

* [PATCH v2 10/13] mfd: pruss SUART private data.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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, open list

This patch adds the PRUSS SUART data.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 include/linux/mfd/pruss/da8xx_pru.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
index 50f2ede..4230d10 100644
--- a/include/linux/mfd/pruss/da8xx_pru.h
+++ b/include/linux/mfd/pruss/da8xx_pru.h
@@ -93,6 +93,11 @@ struct da8xx_pruss_can_data {
 	u32 version;
 };
 
+struct da850_evm_pruss_suart_data {
+	u32 version;
+	struct resource resource;
+};
+
 u32 pruss_get_clk_freq(struct device *dev);
 
 u32 pruss_enable(struct device *dev, u8 pruss_num);
-- 
1.7.2.3


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

* [PATCH v2 10/13] mfd: pruss SUART private data.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the PRUSS SUART data.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 include/linux/mfd/pruss/da8xx_pru.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
index 50f2ede..4230d10 100644
--- a/include/linux/mfd/pruss/da8xx_pru.h
+++ b/include/linux/mfd/pruss/da8xx_pru.h
@@ -93,6 +93,11 @@ struct da8xx_pruss_can_data {
 	u32 version;
 };
 
+struct da850_evm_pruss_suart_data {
+	u32 version;
+	struct resource resource;
+};
+
 u32 pruss_get_clk_freq(struct device *dev);
 
 u32 pruss_enable(struct device *dev, u8 pruss_num);
-- 
1.7.2.3

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

* [PATCH v2 11/13] da850: pruss SUART board specific additions.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, open list

This patch adds the pruss SUART pin mux and registers the device
with the pruss mfd driver.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   36 +++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index f9c38f8..3858516 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {
 	-1
 };
 
+const short da850_evm_pruss_suart_pins[] = {
+	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
+	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
+	DA850_AXR_13, DA850_AXR_9, DA850_AXR_7,
+	DA850_AXR_14, DA850_AXR_10, DA850_AXR_8,
+	-1
+};
+
+static int __init da850_evm_setup_pruss_suart(void)
+{
+	int ret;
+
+	ret = davinci_cfg_reg_list(da850_evm_pruss_suart_pins);
+	if (ret)
+		pr_warning("%s: da850_evm_pruss_suart_pins "
+			"mux setup failed: %d\n", __func__, ret);
+	return ret;
+}
+
 static int __init da850_evm_setup_pruss_can(void)
 {
 	int ret, val = 0;
@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
 	return ret;
 }
 
+static struct da850_evm_pruss_suart_data suart_data = {
+	.version	= 1,
+	.resource	= {
+			.name	= "da8xx_mcasp0_iomem",
+			.start	= DAVINCI_DA8XX_MCASP0_REG_BASE,
+			.end	= DAVINCI_DA8XX_MCASP0_REG_BASE +
+					(SZ_1K * 12) - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+};
+
 static struct da8xx_pruss_can_data can_data = {
 	.version	= 1,
 };
@@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] = {
 		.dev_name	= "da8xx_pruss_can",
 		.pdata		= &can_data,
 		.pdata_size	= sizeof(can_data),
+		.setup		= da850_evm_setup_pruss_suart,
+	},
+	{
+		.dev_name	= "da8xx_pruss_uart",
+		.pdata		= &suart_data,
+		.pdata_size	= sizeof(suart_data),
 		.setup		= da850_evm_setup_pruss_can,
 	},
 	{
-- 
1.7.2.3


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

* [PATCH v2 11/13] da850: pruss SUART board specific additions.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the pruss SUART pin mux and registers the device
with the pruss mfd driver.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/board-da850-evm.c |   36 +++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index f9c38f8..3858516 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {
 	-1
 };
 
+const short da850_evm_pruss_suart_pins[] = {
+	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
+	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
+	DA850_AXR_13, DA850_AXR_9, DA850_AXR_7,
+	DA850_AXR_14, DA850_AXR_10, DA850_AXR_8,
+	-1
+};
+
+static int __init da850_evm_setup_pruss_suart(void)
+{
+	int ret;
+
+	ret = davinci_cfg_reg_list(da850_evm_pruss_suart_pins);
+	if (ret)
+		pr_warning("%s: da850_evm_pruss_suart_pins "
+			"mux setup failed: %d\n", __func__, ret);
+	return ret;
+}
+
 static int __init da850_evm_setup_pruss_can(void)
 {
 	int ret, val = 0;
@@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
 	return ret;
 }
 
+static struct da850_evm_pruss_suart_data suart_data = {
+	.version	= 1,
+	.resource	= {
+			.name	= "da8xx_mcasp0_iomem",
+			.start	= DAVINCI_DA8XX_MCASP0_REG_BASE,
+			.end	= DAVINCI_DA8XX_MCASP0_REG_BASE +
+					(SZ_1K * 12) - 1,
+			.flags	= IORESOURCE_MEM,
+		},
+};
+
 static struct da8xx_pruss_can_data can_data = {
 	.version	= 1,
 };
@@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] = {
 		.dev_name	= "da8xx_pruss_can",
 		.pdata		= &can_data,
 		.pdata_size	= sizeof(can_data),
+		.setup		= da850_evm_setup_pruss_suart,
+	},
+	{
+		.dev_name	= "da8xx_pruss_uart",
+		.pdata		= &suart_data,
+		.pdata_size	= sizeof(suart_data),
 		.setup		= da850_evm_setup_pruss_can,
 	},
 	{
-- 
1.7.2.3

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

* [PATCH v2 12/13] da850: pruss SUART platform specific additions.
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Kevin Hilman, Russell King, open list

This patch adds the McASP clock alias.
The alias is used by the pruss suart driver
for enabling the McASP PSC.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/devices-da8xx.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index e15de72..f1cf605 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {
 
 int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
 {
+#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
+	int ret;
+#endif
+
 	da8xx_pruss_dev.dev.platform_data = pruss_device;
+
+#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
+	ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
+	NULL, &da850_mcasp_device.dev);
+	if (ret < 0)
+		return ret;
+#endif
 	return platform_device_register(&da8xx_pruss_dev);
 }
 
-- 
1.7.2.3


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

* [PATCH v2 12/13] da850: pruss SUART platform specific additions.
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the McASP clock alias.
The alias is used by the pruss suart driver
for enabling the McASP PSC.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 arch/arm/mach-davinci/devices-da8xx.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index e15de72..f1cf605 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {
 
 int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
 {
+#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
+	int ret;
+#endif
+
 	da8xx_pruss_dev.dev.platform_data = pruss_device;
+
+#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
+	ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
+	NULL, &da850_mcasp_device.dev);
+	if (ret < 0)
+		return ret;
+#endif
 	return platform_device_register(&da8xx_pruss_dev);
 }
 
-- 
1.7.2.3

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

* [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
@ 2011-02-11 14:51   ` Subhasish Ghosh
  2011-02-11 14:51   ` Subhasish Ghosh
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 157+ 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,
	Greg Kroah-Hartman, open list

This patch adds support for the TTY compliant
Soft-UART device emulated on PRUSS.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/tty/serial/Kconfig                         |    2 +
 drivers/tty/serial/Makefile                        |    1 +
 drivers/tty/serial/da8xx_pruss/Kconfig             |   19 +
 drivers/tty/serial/da8xx_pruss/Makefile            |    9 +
 drivers/tty/serial/da8xx_pruss/pruss_suart.c       | 1014 +++++++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c   | 2350 ++++++++++++++++++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h   |  345 +++
 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h |   58 +
 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h   |   48 +
 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h |  526 +++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h  |  153 ++
 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c |  384 ++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h |   63 +
 include/linux/serial_core.h                        |    2 +
 14 files changed, 4974 insertions(+), 0 deletions(-)
 create mode 100644 drivers/tty/serial/da8xx_pruss/Kconfig
 create mode 100644 drivers/tty/serial/da8xx_pruss/Makefile
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index b1682d7..68c40c2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1595,4 +1595,6 @@ config SERIAL_PCH_UART
 	  This driver is for PCH(Platform controller Hub) UART of Intel EG20T
 	  which is an IOH(Input/Output Hub) for x86 embedded processor.
 	  Enabling PCH_DMA, this PCH UART works as DMA mode.
+
+source "drivers/tty/serial/da8xx_pruss/Kconfig"
 endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 8ea92e9..51c89e9 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,3 +92,4 @@ obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
 obj-$(CONFIG_SERIAL_IFX6X60)  	+= ifx6x60.o
 obj-$(CONFIG_SERIAL_PCH_UART)	+= pch_uart.o
+obj-$(CONFIG_SERIAL_PRUSS_SUART)	+= da8xx_pruss/
diff --git a/drivers/tty/serial/da8xx_pruss/Kconfig b/drivers/tty/serial/da8xx_pruss/Kconfig
new file mode 100644
index 0000000..23ac53f
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/Kconfig
@@ -0,0 +1,19 @@
+#
+# SUART Kernel Configuration
+#
+
+config SERIAL_PRUSS_SUART
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	select SERIAL_CORE
+	tristate "PRUSS based SoftUART emulation on DA8XX"
+	---help---
+	Enable this to emulate a UART controller on the PRUSS of DA8XX.
+	If not sure, mark N
+
+config PRUSS_SUART_MCASP
+    int "McASP number"
+    depends on ARCH_DAVINCI && ARCH_DAVINCI_DA830 && SERIAL_PRUSS_SUART
+    default "0"
+    ---help---
+    Enter the McASP number to use with SUART (0, 1 or 2).
+	You will need to recompile the kernel if this is changed.
diff --git a/drivers/tty/serial/da8xx_pruss/Makefile b/drivers/tty/serial/da8xx_pruss/Makefile
new file mode 100644
index 0000000..34a5b1f
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for SoftUART emulation
+#
+
+suart_emu-objs :=       pruss_suart.o \
+                        pruss_suart_api.o \
+                        pruss_suart_utils.o
+
+obj-$(CONFIG_SERIAL_PRUSS_SUART)        += suart_emu.o
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart.c b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
new file mode 100644
index 0000000..d222e2e
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -0,0 +1,1014 @@
+/*
+ * PRUSS SUART Emulation device driver
+ * Author: subhasish@mistralsolutions.com
+ *
+ * This driver supports TI's PRU SUART 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/module.h>
+#include <mach/da8xx.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <mach/sram.h>
+#include "pruss_suart_board.h"
+#include "pruss_suart_api.h"
+#include "pruss_suart_utils.h"
+#include "pruss_suart_err.h"
+
+#define NR_SUART			8
+#define DRV_NAME			"da8xx_pruss_uart"
+#define DRV_DESC			"PRUSS SUART Driver v1.0"
+#define MAX_SUART_RETRIES		100
+#define SUART_CNTX_SZ			512
+#define SUART_FIFO_TIMEOUT_DFLT		5
+#define SUART_FIFO_TIMEOUT_MIN		4
+#define SUART_FIFO_TIMEOUT_MAX		500
+
+#ifdef __SUART_DEBUG
+#define __suart_debug(fmt, args...) \
+		printk(KERN_DEBUG "suart_debug: " fmt, ## args)
+#else
+#define __suart_debug(fmt, args...)
+#endif
+
+#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## args)
+
+/* Default timeout set to 5ms */
+static s16 suart_timeout = SUART_FIFO_TIMEOUT_DFLT;
+module_param(suart_timeout, short, S_IRUGO);
+MODULE_PARM_DESC(suart_timeout,
+		 "fifo timeout in milli seconds (min: 4; max: 500)");
+
+struct suart_fifo {
+	void *fifo_vaddr_buff_tx;
+	void *fifo_vaddr_buff_rx;
+	void *fifo_phys_addr_tx;
+	void *fifo_phys_addr_rx;
+};
+
+struct omapl_pru_suart {
+	struct uart_port port[NR_SUART];
+	struct device *dev; /* pdev->dev */
+	struct semaphore port_sem[NR_SUART];
+	struct clk *clk_mcasp;
+	struct suart_fifo suart_fifo_addr[NR_SUART];
+	const struct firmware *fw;
+	suart_struct_handle suart_hdl[NR_SUART];
+	pruss_suart_iomap suart_iomap;
+	u32 clk_freq_pru;
+	u32 clk_freq_mcasp;
+	u32 tx_loadsz;
+};
+
+static u32 suart_get_duplex(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	return soft_uart->suart_hdl[uart_no].uart_type;
+}
+
+static inline void __stop_tx(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct device *dev = soft_uart->dev;
+	u16 txready;
+	u32 i;
+
+	/* Check if any TX in progress */
+	for (i = 0, txready = 1; (i < 10000) && txready; i++) {
+		txready = (pru_softuart_get_tx_status
+			(dev, &soft_uart->suart_hdl[uart_no]) &
+				CHN_TXRX_STATUS_RDY);
+	}
+	/* To stop tx, disable the TX interrupt */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[uart_no].uart_num,
+				PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl[uart_no]);
+}
+
+static void pruss_suart_stop_tx(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	__stop_tx(soft_uart, port->line);
+}
+
+static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
+	struct device *dev = soft_uart->dev;
+	s32 count = 0;
+
+	if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
+		return;
+
+	if (down_trylock(&soft_uart->port_sem[uart_no]))
+		return;
+
+	if (uart_circ_empty(xmit) ||
+			uart_tx_stopped(&soft_uart->port[uart_no])) {
+		pruss_suart_stop_tx(&soft_uart->port[uart_no]);
+		up(&soft_uart->port_sem[uart_no]);
+		return;
+	}
+
+	for (count = 0; count <= soft_uart->tx_loadsz; count++) {
+		*((s8 *)soft_uart->suart_fifo_addr[uart_no].fifo_vaddr_buff_tx
+		+ count) = xmit->buf[xmit->tail];
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		soft_uart->port[uart_no].icount.tx++;
+		if (uart_circ_empty(xmit)) {
+			uart_circ_clear(xmit);
+			break;
+		}
+	}
+
+	if (count == (SUART_FIFO_LEN + 1))
+		count = SUART_FIFO_LEN;
+
+	/* Write the character to the data port */
+	if (SUART_SUCCESS != pru_softuart_write(dev,
+		&soft_uart->suart_hdl[uart_no],
+			(u32 *)&soft_uart->suart_fifo_addr
+				[uart_no].fifo_phys_addr_tx, count)) {
+		__suart_err("failed to tx data\n");
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&soft_uart->port[uart_no]);
+
+#if 0
+	if (uart_circ_empty(xmit))
+		__stop_tx(soft_uart, uart_no);
+#endif
+}
+
+static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct tty_struct *tty = soft_uart->port[uart_no].state->port.tty;
+	struct device *dev = soft_uart->dev;
+	s8 flags = TTY_NORMAL;
+	u16 rx_status, data_len = SUART_FIFO_LEN;
+	u32 data_len_read;
+	u8 suart_data[SUART_FIFO_LEN + 1];
+	s32 i = 0;
+
+	if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
+		return;
+	/* read the status */
+	rx_status = pru_softuart_get_rx_status(dev,
+			&soft_uart->suart_hdl[uart_no]);
+
+	/* check for errors */
+	if (rx_status & CHN_TXRX_STATUS_ERR) {
+		if (rx_status & CHN_TXRX_STATUS_FE)
+			soft_uart->port[uart_no].icount.frame++;
+		if (rx_status & CHN_TXRX_STATUS_OVRNERR)
+			soft_uart->port[uart_no].icount.overrun++;
+		if (rx_status & CHN_TXRX_STATUS_BI)
+			soft_uart->port[uart_no].icount.brk++;
+		rx_status &= soft_uart->port[uart_no].read_status_mask;
+		if (rx_status & CHN_TXRX_STATUS_FE)
+			flags = TTY_FRAME;
+		if (rx_status & CHN_TXRX_STATUS_OVRNERR)
+			flags = TTY_OVERRUN;
+		if (rx_status & CHN_TXRX_STATUS_BI)
+			flags = TTY_BREAK;
+
+#ifdef SUPPORT_SYSRQ
+		soft_uart->port[uart_no].sysrq = 0;
+#endif
+	} else {
+		pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
+				       suart_data, data_len + 1,
+				       &data_len_read);
+
+		for (i = 0; i <= data_len_read; i++) {
+			soft_uart->port[uart_no].icount.rx++;
+			/* check for sys rq */
+			if (uart_handle_sysrq_char
+			    (&soft_uart->port[uart_no], suart_data))
+				continue;
+		}
+		/* update the tty data structure */
+		tty_insert_flip_string(tty, suart_data, data_len_read);
+	}
+
+	/* push data into tty */
+	pru_softuart_clr_rx_status(dev, &soft_uart->suart_hdl[uart_no]);
+	spin_unlock(&soft_uart->port[uart_no].lock);
+	tty_flip_buffer_push(tty);
+	spin_lock(&soft_uart->port[uart_no].lock);
+}
+
+static irqreturn_t pruss_suart_interrupt(s32 irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	u16 txrx_flag;
+	u32 ret;
+	unsigned long flags = 0;
+	u16 uart_num = port->line + 1;
+
+	spin_lock_irqsave(&soft_uart->port[port->line].lock, flags);
+	do {
+		ret = pru_softuart_get_isrstatus(dev, uart_num, &txrx_flag);
+		if (PRU_SUART_SUCCESS != ret) {
+			__suart_err("suart%d: failed to get interrupt, ret:"
+				" 0x%X txrx_flag 0x%X\n",
+				port->line, ret, txrx_flag);
+			spin_unlock_irqrestore(&soft_uart->
+				port[port->line].lock, flags);
+			return IRQ_NONE;
+		}
+		if ((PRU_RX_INTR & txrx_flag) == PRU_RX_INTR) {
+			pru_intr_clr_isrstatus(dev, uart_num, PRU_RX_INTR);
+			if ((soft_uart->port[port->line].ignore_status_mask &
+				CHN_TXRX_STATUS_RDY) == CHN_TXRX_STATUS_RDY) {
+				pru_softuart_clr_rx_status(dev,
+					&soft_uart->suart_hdl
+				[port->line]);
+			} else {
+				omapl_pru_rx_chars(soft_uart, port->line);
+			}
+		}
+
+		if ((PRU_TX_INTR & txrx_flag) == PRU_TX_INTR) {
+			pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
+			pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl
+						 [port->line]);
+			up(&soft_uart->port_sem[port->line]);
+			omapl_pru_tx_chars(soft_uart, port->line);
+		}
+	} while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
+
+	spin_unlock_irqrestore(&soft_uart->port[port->line].lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void pruss_suart_stop_rx(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	/* disable rx interrupt */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+}
+
+static void pruss_suart_enable_ms(struct uart_port *port)
+{
+	__suart_err("modem control timer not supported\n");
+}
+
+static void pruss_suart_start_tx(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	/* unmask the tx interrupts */
+
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	omapl_pru_tx_chars(soft_uart, port->line);
+}
+
+static u32 pruss_suart_tx_empty(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+
+	return (pru_softuart_get_tx_status(dev,
+		&soft_uart->suart_hdl[port->line])
+		& CHN_TXRX_STATUS_RDY) ? 0 : TIOCSER_TEMT;
+}
+
+static u32 pruss_suart_get_mctrl(struct uart_port *port)
+{
+	return -ENOTSUPP;
+}
+
+static void pruss_suart_set_mctrl(struct uart_port *port, u32 mctrl)
+{
+	__suart_debug("modem control not supported\n");
+}
+
+static void pruss_suart_break_ctl(struct uart_port *port, s32 break_state)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (break_state == -1)
+		suart_intr_clrmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+	else
+		suart_intr_setmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void pruss_suart_set_termios(struct uart_port *port,
+				  struct ktermios *termios,
+				  struct ktermios *old)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	u8 cval = 0;
+	unsigned long flags = 0;
+	u32 baud = 0;
+	u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+/*
+ * Do not allow unsupported configurations to be set
+ */
+	if (1) {
+		termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
+				      | PARENB | PARODD | CMSPAR);
+		termios->c_cflag |= CLOCAL;
+	}
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS6:
+		cval = ePRU_SUART_DATA_BITS6;
+		break;
+	case CS7:
+		cval = ePRU_SUART_DATA_BITS7;
+		break;
+	default:
+	case CS8:
+		cval = ePRU_SUART_DATA_BITS8;
+		break;
+	}
+	/*
+	 * We do not support CS5.
+	 */
+	if ((termios->c_cflag & CSIZE) == CS5) {
+		termios->c_cflag &= ~CSIZE;
+		termios->c_cflag |= old_csize;
+	}
+	if (SUART_SUCCESS != pru_softuart_setdatabits
+		(dev, &soft_uart->suart_hdl[port->line], cval, cval))
+		__suart_err("failed to set data bits to: %d\n", cval);
+
+/*
+ * Ask the core to calculate the divisor for us.
+ */
+	baud = uart_get_baud_rate(port, termios, old,
+			  port->uartclk / 16 / 0xffff,
+			  port->uartclk / 16);
+
+/*
+ * Ok, we're now changing the port state.  Do it with
+ * interrupts disabled.
+ */
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Set the baud */
+	if (SUART_SUCCESS !=
+	    pru_softuart_setbaud(dev, &soft_uart->suart_hdl[port->line],
+				 SUART_DEFAULT_BAUD / baud,
+				 SUART_DEFAULT_BAUD / baud))
+		__suart_err("failed to set baud to: %d\n", baud);
+
+/*
+ * update port->read_config_mask and port->ignore_config_mask
+ * to indicate the events we are interested in receiving
+ */
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, SUART_GBL_INTR_ERR_MASK);
+	port->read_status_mask = 0;
+	if (termios->c_iflag & INPCK) {	/* Input parity check not supported,
+					just enabled FE */
+		port->read_status_mask |= CHN_TXRX_STATUS_FE;
+		suart_intr_setmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_FE);
+	}
+	if (termios->c_iflag & (BRKINT | PARMRK)) {
+		port->read_status_mask |= CHN_TXRX_STATUS_BI;
+		suart_intr_setmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+	}
+/*
+ * Characteres to ignore
+ */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= CHN_TXRX_STATUS_BI;
+		/*
+		 * If we're ignoring break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR) {
+			port->ignore_status_mask |=
+			    (CHN_TXRX_STATUS_OVRNERR | CHN_TXRX_STATUS_FE);
+			/*
+			 * Overrun in case of RX
+			 * Underrun in case of TX
+			 */
+			suart_intr_clrmask(dev, soft_uart->
+					   suart_hdl[port->line].uart_num,
+					   PRU_RX_INTR, CHN_TXRX_IE_MASK_FE);
+		}
+		suart_intr_clrmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+	}
+/*
+ * ignore all characters if CREAD is not set
+ */
+	if ((termios->c_cflag & CREAD) == 0) {
+		port->ignore_status_mask |= CHN_TXRX_STATUS_RDY;
+		pruss_suart_stop_rx(port);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+/*
+ *	Grab any interrupt resources and initialise any low level driver
+ *	state.  Enable the port for reception.  It should not activate
+ *	RTS nor DTR; this will be done via a separate call to set_mctrl.
+ *
+ *	This method will only be called when the port is initially opened.
+ *
+ *	Locking: port_sem taken.
+ *	Interrupts: globally disabled.
+ */
+static s32 pruss_suart_startup(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	s32 retval;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+
+	retval = request_irq(port->irq, pruss_suart_interrupt,
+			     port->irqflags, "suart_irq", port);
+	if (retval) {
+		free_irq(port->irq, port); /* should we free this if err */
+		goto out;
+	}
+	/*
+	 * enable interrupts from this port
+	 */
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, SUART_GBL_INTR_ERR_MASK);
+
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+
+	if ((suart_get_duplex(soft_uart, port->line) & ePRU_SUART_HALF_TX)
+	    == ePRU_SUART_HALF_TX) {
+		suart_pru_to_host_intr_enable(dev, soft_uart->
+			suart_hdl[port->line].uart_num, PRU_TX_INTR, true);
+	}
+	/* Seed RX if port is half-rx or full-duplex */
+	if ((suart_get_duplex(soft_uart, port->line) & ePRU_SUART_HALF_RX)
+		== ePRU_SUART_HALF_RX) {
+		suart_pru_to_host_intr_enable(dev, soft_uart->
+			suart_hdl[port->line].uart_num, PRU_RX_INTR, true);
+		pru_softuart_read(dev, &soft_uart->suart_hdl[port->line],
+			(u32 *)&soft_uart->suart_fifo_addr[port->line].
+			fifo_phys_addr_rx, SUART_FIFO_LEN);
+	}
+out:
+	return retval;
+}
+
+/*
+ * Disable the port, disable any break condition that may be in
+ * effect, and free any interrupt resources.  It should not disable
+ * RTS nor DTR; this will have already been done via a separate
+ * call to set_mctrl.
+ *
+ * Drivers must not access port->info once this call has completed.
+ *
+ * This method will only be called when there are no more users of
+ * this port.
+ *
+ * Locking: port_sem taken.
+ * Interrupts: caller dependent.
+ */
+
+static void pruss_suart_shutdown(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	/* Disable BI and FE intr */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+
+	/* free interrupts */
+	free_irq(port->irq, port);
+}
+
+/*
+ * Return a pointer to a string constant describing the specified
+ * port, or return NULL, in which case the string 'unknown' is
+ * substituted.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static const char *pruss_suart_type(struct uart_port *port)
+{
+	return "suart_tty";
+}
+
+/*
+ * Release any memory and IO region resources currently in use by
+ * the port.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static void pruss_suart_release_port(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct platform_device *pdev = to_platform_device(port->dev);
+
+	if (0 != pru_softuart_close(&soft_uart->suart_hdl[port->line]))
+		dev_err(&pdev->dev, "failed to close suart\n");
+
+	return;
+}
+
+/*
+ * Request any memory and IO region resources required by the port.
+ * If any fail, no resources should be registered when this function
+ * returns, and it should return -EBUSY on failure.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ *
+ * We need to d/l the f/w in probe and since this api
+ * is called per uart, the request_mem_region should
+ * be called in probe itself.
+ */
+static s32 pruss_suart_request_port(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct device *dev = soft_uart->dev;
+	suart_config pru_suart_config;
+	s16 timeout = 0;
+	u32 err = 0;
+
+	if (soft_uart == NULL) {
+		__suart_err("soft_uart ptr failed\n");
+		return -ENODEV;
+	}
+	err = pru_softuart_open(&soft_uart->suart_hdl[port->line]);
+	if (PRU_SUART_SUCCESS != err) {
+		dev_err(&pdev->dev, "failed to open suart: %d\n", err);
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* set fifo /timeout */
+	if (SUART_FIFO_TIMEOUT_MIN > suart_timeout) {
+		__suart_err("fifo timeout less than %d ms not supported\n",
+			    SUART_FIFO_TIMEOUT_MIN);
+		suart_timeout = SUART_FIFO_TIMEOUT_MIN;
+	} else if (SUART_FIFO_TIMEOUT_MAX < suart_timeout) {
+		__suart_err("fifo timeout more than %d ms not supported\n",
+			    SUART_FIFO_TIMEOUT_MAX);
+		suart_timeout = SUART_FIFO_TIMEOUT_MAX;
+	}
+
+	/* This is only for x8 */
+	timeout = (SUART_DEFAULT_BAUD * suart_timeout) / 1000;
+	pru_set_fifo_timeout(dev, timeout);
+
+	if (soft_uart->suart_hdl[port->line].uart_num == PRU_SUART_UART1) {
+		pru_suart_config.tx_serializer = PRU_SUART0_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART0_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART2) {
+		pru_suart_config.tx_serializer = PRU_SUART1_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART1_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART3) {
+		pru_suart_config.tx_serializer = PRU_SUART2_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART2_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART4) {
+		pru_suart_config.tx_serializer = PRU_SUART3_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART3_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART5) {
+		pru_suart_config.tx_serializer = PRU_SUART4_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART4_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART6) {
+		pru_suart_config.tx_serializer = PRU_SUART5_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART5_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART7) {
+		pru_suart_config.tx_serializer = PRU_SUART6_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART6_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART8) {
+		pru_suart_config.tx_serializer = PRU_SUART7_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART7_CONFIG_RX_SER;
+	} else {
+		return -ENOTSUPP;
+	}
+
+	/* Some defaults to startup. reconfigured by terimos later */
+	pru_suart_config.tx_clk_divisor = 1;
+	pru_suart_config.rx_clk_divisor = 1;
+	pru_suart_config.tx_bits_per_char = ePRU_SUART_DATA_BITS8;
+	pru_suart_config.rx_bits_per_char = ePRU_SUART_DATA_BITS8;
+	pru_suart_config.oversampling = SUART_DEFAULT_OVRSMPL;
+
+	if (PRU_SUART_SUCCESS !=
+		pru_softuart_setconfig(dev, &soft_uart->suart_hdl[port->line],
+			&pru_suart_config)) {
+		dev_err(&pdev->dev,
+			"pru_softuart_setconfig: failed to set config: %X\n",
+			err);
+	}
+exit:
+	return err;
+}
+
+/*
+ * Perform any autoconfiguration steps required for the port.  `flag`
+ * contains a bit mask of the required configuration.  UART_CONFIG_TYPE
+ * indicates that the port requires detection and identification.
+ * port->type should be set to the type found, or PORT_UNKNOWN if
+ * no port was detected.
+ *
+ * UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
+ * which should be probed using standard kernel autoprobing techniques.
+ * This is not necessary on platforms where ports have interrupts
+ * internally hard wired (eg, system on a chip implementations).
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static void pruss_suart_config_port(struct uart_port *port, s32 flags)
+{
+	if (flags & UART_CONFIG_TYPE && pruss_suart_request_port(port) == 0)
+		port->type = PORT_DA8XX_PRU_SUART;
+}
+
+/*
+ * Verify the new serial port information contained within serinfo is
+ * suitable for this port type.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+static s32 pruss_suart_verify_port(struct uart_port *port,
+				 struct serial_struct *ser)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	s32 ret = 0;
+
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_DA8XX_PRU_SUART)
+		ret = -EINVAL;
+	if (soft_uart->port[port->line].irq != ser->irq)
+		ret = -EINVAL;
+	if (ser->io_type != UPIO_MEM)
+		ret = -EINVAL;
+	if (soft_uart->port[port->line].uartclk / 16 != ser->baud_base)
+		ret = -EINVAL;
+	if ((void *)soft_uart->port[port->line].mapbase != ser->iomem_base)
+		ret = -EINVAL;
+	if (soft_uart->port[port->line].iobase != ser->port)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops pruss_suart_ops = {
+	.tx_empty	= pruss_suart_tx_empty,
+	.set_mctrl	= pruss_suart_set_mctrl,
+	.get_mctrl	= pruss_suart_get_mctrl,
+	.stop_tx	= pruss_suart_stop_tx,
+	.start_tx	= pruss_suart_start_tx,
+	.stop_rx	= pruss_suart_stop_rx,
+	.enable_ms	= pruss_suart_enable_ms,
+	.break_ctl	= pruss_suart_break_ctl,
+	.startup	= pruss_suart_startup,
+	.shutdown	= pruss_suart_shutdown,
+	.set_termios	= pruss_suart_set_termios,
+	.type		= pruss_suart_type,
+	.release_port	= pruss_suart_release_port,
+	.request_port	= pruss_suart_request_port,
+	.config_port	= pruss_suart_config_port,
+	.verify_port	= pruss_suart_verify_port,
+};
+
+static struct uart_driver pruss_suart_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRV_NAME,
+	.dev_name	= "ttySU",
+	.major		= 0,
+	.minor		= 16,
+	.nr		= NR_SUART,
+};
+
+static s32 __devinit pruss_suart_probe(struct platform_device *pdev)
+{
+	struct omapl_pru_suart *soft_uart;
+	const struct da850_evm_pruss_suart_data *pdata;
+	struct device *dev = &pdev->dev;
+	s32 err, i;
+	u8 *fw_data = NULL;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	soft_uart = kzalloc(sizeof(struct omapl_pru_suart), GFP_KERNEL);
+	if (!soft_uart)
+		return -ENOMEM;
+
+	if (!request_mem_region(pdata->resource.start,
+			resource_size(&pdata->resource),
+			dev_name(&pdev->dev))) {
+		dev_err(&pdev->dev, "mcasp memory region already claimed!\n");
+		err = -EBUSY;
+		goto probe_exit;
+	}
+
+	soft_uart->suart_iomap.mcasp_io_addr =
+			ioremap(pdata->resource.start,
+			resource_size(&pdata->resource));
+	if (!soft_uart->suart_iomap.mcasp_io_addr) {
+		dev_err(&pdev->dev, "mcasp ioremap failed\n");
+		err = -EFAULT;
+		goto probe_exit_1;
+	}
+
+	soft_uart->suart_iomap.p_fifo_buff_virt_base =
+	sram_alloc(SUART_CNTX_SZ * NR_SUART * 2,
+	(dma_addr_t *) &soft_uart->suart_iomap.p_fifo_buff_phys_base);
+	if (!soft_uart->suart_iomap.p_fifo_buff_virt_base)
+		goto probe_exit_iounmap;
+
+	soft_uart->clk_freq_pru = pruss_get_clk_freq(dev);
+
+	soft_uart->clk_mcasp = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(soft_uart->clk_mcasp)) {
+		dev_err(&pdev->dev, "no clock available: mcasp\n");
+		err = -ENODEV;
+		soft_uart->clk_mcasp = NULL;
+		goto probe_exit_sram_free;
+	}
+
+	soft_uart->clk_freq_mcasp = clk_get_rate(soft_uart->clk_mcasp);
+	clk_enable(soft_uart->clk_mcasp);
+
+	err = request_firmware(&soft_uart->fw, "PRU_SUART_Emulation.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 size %td. downloading...\n",
+		soft_uart->fw->size);
+
+	/* download firmware into pru  & init */
+	fw_data = kmalloc(soft_uart->fw->size, GFP_KERNEL);
+	memcpy((void *)fw_data, (const void *)soft_uart->fw->data,
+		soft_uart->fw->size);
+
+	soft_uart->suart_iomap.pru_clk_freq =
+		(soft_uart->clk_freq_pru / 1000000);
+
+	err = pru_softuart_init(dev, SUART_DEFAULT_BAUD, SUART_DEFAULT_BAUD,
+			SUART_DEFAULT_OVRSMPL, fw_data,
+			soft_uart->fw->size, &soft_uart->suart_iomap);
+	if (err) {
+		dev_err(&pdev->dev, "pruss init error\n");
+		err = -ENODEV;
+		kfree((const void *)fw_data);
+		goto probe_release_fw;
+	}
+	kfree((const void *)fw_data);
+
+	platform_set_drvdata(pdev, &soft_uart->port[0]);
+	soft_uart->dev = dev;
+
+	for (i = 0; i < NR_SUART; i++) {
+		soft_uart->port[i].ops = &pruss_suart_ops;
+		soft_uart->port[i].iotype = UPIO_MEM;
+		soft_uart->port[i].flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+		soft_uart->port[i].mapbase =
+			(u32)soft_uart->suart_iomap.p_fifo_buff_virt_base;
+		soft_uart->port[i].membase =
+			(u8 *)&soft_uart->suart_iomap;
+		soft_uart->port[i].type = PORT_DA8XX_PRU_SUART;
+		soft_uart->port[i].irq =
+			platform_get_irq(to_platform_device(dev->parent), i);
+		soft_uart->port[i].dev = &pdev->dev;
+		soft_uart->port[i].irqflags = IRQF_SHARED;
+		soft_uart->port[i].uartclk = soft_uart->clk_freq_mcasp;
+		soft_uart->port[i].fifosize = SUART_FIFO_LEN;
+		soft_uart->tx_loadsz = SUART_FIFO_LEN;
+		soft_uart->port[i].custom_divisor = 1;
+		soft_uart->port[i].line = i;
+		soft_uart->suart_hdl[i].uart_num = i + 1;
+		spin_lock_init(&soft_uart->port[i].lock);
+		soft_uart->port[i].serial_in = NULL;
+
+		soft_uart->suart_fifo_addr[i].fifo_vaddr_buff_tx =
+		soft_uart->suart_iomap.p_fifo_buff_virt_base +
+		(2 * SUART_CNTX_SZ * i);
+
+		soft_uart->suart_fifo_addr[i].fifo_vaddr_buff_rx =
+		soft_uart->suart_iomap.p_fifo_buff_virt_base +
+		((2 * SUART_CNTX_SZ * i) + SUART_CNTX_SZ);
+
+		soft_uart->suart_fifo_addr[i].fifo_phys_addr_tx =
+		soft_uart->suart_iomap.p_fifo_buff_phys_base +
+		(2 * SUART_CNTX_SZ * i);
+
+		soft_uart->suart_fifo_addr[i].fifo_phys_addr_rx =
+		soft_uart->suart_iomap.p_fifo_buff_phys_base +
+		((2 * SUART_CNTX_SZ * i) + SUART_CNTX_SZ);
+
+		soft_uart->port[i].serial_out = NULL;
+		uart_add_one_port(&pruss_suart_reg, &soft_uart->port[i]);
+		sema_init(&soft_uart->port_sem[i], 1);
+	}
+
+	dev_info(&pdev->dev,
+		"%s device registered (pru_clk=%d, asp_clk=%d)\n",
+		DRV_NAME, soft_uart->clk_freq_pru, soft_uart->clk_freq_mcasp);
+
+	return 0;
+
+probe_release_fw:
+	release_firmware(soft_uart->fw);
+probe_exit_clk:
+	clk_put(soft_uart->clk_mcasp);
+	clk_disable(soft_uart->clk_mcasp);
+probe_exit_sram_free:
+	sram_free(soft_uart->suart_iomap.p_fifo_buff_virt_base,
+	SUART_CNTX_SZ * NR_SUART * 2);
+probe_exit_iounmap:
+	iounmap(soft_uart->suart_iomap.mcasp_io_addr);
+probe_exit_1:
+	release_mem_region(pdata->resource.start,
+		resource_size(&pdata->resource));
+probe_exit:
+	kfree(soft_uart);
+	return err;
+}
+
+static s32 __devexit pruss_suart_remove(struct platform_device *pdev)
+{
+	struct omapl_pru_suart *soft_uart = platform_get_drvdata(pdev);
+	const struct da850_evm_pruss_suart_data *pdata;
+	struct device *dev = &pdev->dev;
+	int i;
+
+	pdata = dev->platform_data;
+	if (!pdata)
+		dev_err(&pdev->dev, "platform data not found\n");
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (soft_uart) {
+		for (i = 0; i < NR_SUART; i++) {
+			uart_remove_one_port(&pruss_suart_reg,
+			&soft_uart->port[i]);
+		}
+	}
+
+	sram_free(soft_uart->suart_iomap.p_fifo_buff_virt_base,
+		SUART_CNTX_SZ * NR_SUART * 2);
+	release_firmware(soft_uart->fw);
+	clk_put(soft_uart->clk_mcasp);
+	clk_disable(soft_uart->clk_mcasp);
+	iounmap(soft_uart->suart_iomap.mcasp_io_addr);
+	if (pdata) {
+		release_mem_region(pdata->resource.start,
+			resource_size(&pdata->resource));
+	}
+	kfree(soft_uart);
+	return 0;
+}
+
+#define pruss_suart_suspend NULL
+#define pruss_suart_resume NULL
+
+static struct platform_driver serial_pruss_driver = {
+	.probe		= pruss_suart_probe,
+	.remove		= __devexit_p(pruss_suart_remove),
+	.suspend	= pruss_suart_suspend,
+	.resume		= pruss_suart_resume,
+	.driver		= {
+			.name	= DRV_NAME,
+			.owner	= THIS_MODULE,
+	},
+};
+
+static s32 __init pruss_suart_init(void)
+{
+	s32 ret;
+
+	pruss_suart_reg.nr = NR_SUART;
+	ret = uart_register_driver(&pruss_suart_reg);
+	if (ret)
+		return ret;
+	ret = platform_driver_register(&serial_pruss_driver);
+	if (ret)
+		goto out;
+
+	__suart_debug("SUART serial driver loaded\n");
+	return ret;
+out:
+	uart_unregister_driver(&pruss_suart_reg);
+	return ret;
+}
+
+module_init(pruss_suart_init);
+
+static void __exit pruss_suart_exit(void)
+{
+	platform_driver_unregister(&serial_pruss_driver);
+	uart_unregister_driver(&pruss_suart_reg);
+	__suart_debug("SUART serial driver unloaded\n");
+}
+
+module_exit(pruss_suart_exit);
+
+/* Module information */
+MODULE_AUTHOR("Subhasish Ghosh <subhasish@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
new file mode 100644
index 0000000..d809dd3
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
@@ -0,0 +1,2350 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include "pruss_suart_api.h"
+#include "pruss_suart_regs.h"
+#include "pruss_suart_board.h"
+#include "pruss_suart_utils.h"
+#include "pruss_suart_err.h"
+
+static u8 g_uart_statu_table[8];
+static pruss_suart_iomap suart_iomap;
+
+static u32 uart_rx[8] = {PRU_SUART0_CONFIG_RX_SER, PRU_SUART1_CONFIG_RX_SER,
+			PRU_SUART2_CONFIG_RX_SER, PRU_SUART3_CONFIG_RX_SER,
+			PRU_SUART4_CONFIG_RX_SER, PRU_SUART5_CONFIG_RX_SER,
+			PRU_SUART6_CONFIG_RX_SER, PRU_SUART7_CONFIG_RX_SER};
+
+static u32 uart_tx[8] = {PRU_SUART0_CONFIG_TX_SER, PRU_SUART1_CONFIG_TX_SER,
+			PRU_SUART2_CONFIG_TX_SER, PRU_SUART3_CONFIG_TX_SER,
+			PRU_SUART4_CONFIG_TX_SER, PRU_SUART5_CONFIG_TX_SER,
+			PRU_SUART6_CONFIG_TX_SER, PRU_SUART7_CONFIG_TX_SER};
+
+static u32 uart_config[8] = {PRU_SUART0_CONFIG_DUPLEX, PRU_SUART1_CONFIG_DUPLEX,
+			PRU_SUART2_CONFIG_DUPLEX, PRU_SUART3_CONFIG_DUPLEX,
+			PRU_SUART4_CONFIG_DUPLEX, PRU_SUART5_CONFIG_DUPLEX,
+			PRU_SUART6_CONFIG_DUPLEX, PRU_SUART7_CONFIG_DUPLEX};
+
+#if (PRU_ACTIVE == BOTH_PRU)
+#if 1
+void pru_set_ram_data(struct device *dev, pruss_suart_iomap *pruss_ioaddr)
+{
+	u16 u16datatowrite;
+	u32 u32datatowrite;
+	u32 i;
+	pru_suart_regs_ovly pru_suart_regs = PRU0_DATARAM_OFFSET;
+	u32 *pu32_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
+	pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+
+	/* RX PRU - 0 Chanel 0-7 context information */
+	for (i = 0; i < 8; i++, pru_suart_regs++) {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_RX << 0);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= ((0xF & uart_rx[i]) << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+					PRU_SUART_HALF_RX_DISABLED) {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15) ;
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+		} else {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_ENABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		__raw_writel(MCASP_SRCTL_RX_MODE, pu32_sr_ctl_addr +
+								uart_rx[i]);
+		}
+		/*
+		* RX is active by default, write the dummy received data at
+		* PRU RAM addr 0x1FC to avoid memory corruption.
+		*/
+		pruss_readl(dev, (u32) &pru_suart_regs->ch_txrx_data,
+							&u32datatowrite, 1);
+		u32datatowrite |= RX_DEFAULT_DATA_DUMP_ADDR;
+		pruss_writel(dev, (u32) &pru_suart_regs->ch_txrx_data,
+							&u32datatowrite, 1);
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite = 0;
+		pruss_writel(dev, (u32) &pru_suart_regs->reserved1,
+							&u32datatowrite, 1);
+		/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+				(PRU0_DATARAM_OFFSET + (0x090 + (i * 0x020)));
+		u32datatowrite = (MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
+				&u32datatowrite, 1);
+		u32datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+				&u32datatowrite, 1);
+	}
+
+	/* ****************** PRU1 RAM BASE ADDR ************************ */
+	pru_suart_regs = (pru_suart_regs_ovly) PRU1_DATARAM_OFFSET;
+
+	/* ******************* TX PRU - 1  *********************** */
+	/* Channel 0-7 context information */
+	for (i = 0; i < 8; i++, pru_suart_regs++) {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_TX << 0);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (0xF & uart_tx[i] << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED) {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+		} else {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_ENABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		__raw_writel(MCASP_SRCTL_TX_MODE,
+				pu32_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite |= 1;
+		pruss_writel(dev, (u32) &pru_suart_regs->reserved1,
+							 &u32datatowrite, 1);
+	/* SUART1 TX context base addr */
+		 pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+			(PRU1_DATARAM_OFFSET + (0x0B0 + (i * 0x02C)));
+		u32datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
+				&u32datatowrite, 1);
+		u32datatowrite = (MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+				&u32datatowrite, 1);
+	/* SUART1 TX formatted data base addr */
+		u32datatowrite = (0x0090 + (i * 0x002C));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+					&u32datatowrite, 1);
+	}
+}
+#endif
+#else
+void pru_set_ram_data(struct device *dev, pruss_suart_iomap *pruss_ioaddr)
+{
+
+	pru_suart_regs_ovly pru_suart_regs = (pru_suart_regs_ovly)
+						pruss_ioaddr->pru_io_addr;
+	u32 i;
+	u32 *pu32_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
+	pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+
+	/* ***************** UART 0  ************************ */
+	/* Channel 0 context information is Tx */
+	for (i = 0; i < 4; i++, pru_suart_regs++) {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_TX << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (0xF & uart_tx[i]);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED){
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		} else {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_ENABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			__raw_writel(MCASP_SRCTL_TX_MODE,
+						pu32_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite |= 1;
+		pruss_writel(dev, (u32) &pru_suart_regs->reserved1,
+							&u32datatowrite, 1);
+	/* SUART1 TX context base addr */
+		 pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+				(PRU0_DATARAM_OFFSET + (0x0B0 + (i * 0x50)));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
+				(MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2)), 1);
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+				(MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2)), 1);
+	/* SUART1 TX formatted data base addr */
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+					(0x0090 + (i * 0x050)), 1);
+
+	/* Channel 1 is Rx context information */
+		pru_suart_regs++;
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_RX << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (0xF & uart_rx[i]);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+						PRU_SUART_HALF_RX_DISABLED) {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		} else {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_ENABLED << 15);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		__raw_writel(MCASP_SRCTL_RX_MODE,
+					pu32_sr_ctl_addr + uart_rx[i]);
+		}
+	/* RX is active by default, write the dummy received data
+	 * at PRU RAM addr 0x1FC to avoid memory corruption
+	 */
+		pruss_readl(dev, (u32) &pru_surt_regs->ch_txrx_data,
+						&u32datatowrite, 1);
+		u32datatowrite |= RX_DEFAULT_DATA_DUMP_ADDR;
+		pruss_writel(dev, (u32) &pru_suart_regs->ch_txrx_data,
+							&u32datatowrite, 1);
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite = 0;
+	pruss_writel(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+	/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+			(PRU0_DATARAM_OFFSET + (0x0C0 + (i * 0x50)));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
+				(MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2)), 1);
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+				(MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2)), 1);
+	}
+}
+#endif
+
+static void pru_set_rx_tx_mode(struct device *dev, u32 pru_mode, u32 pru_num)
+{
+
+	u32 pru_offset;
+
+	if (pru_num == PRUSS_NUM0)
+		pru_offset = PRU_SUART_PRU0_RX_TX_MODE;
+	else if (pru_num == PRUSS_NUM1)
+		pru_offset = PRU_SUART_PRU1_RX_TX_MODE;
+	else
+		return;
+	pruss_writeb(dev, pru_offset, (u8 *) &pru_mode, 1);
+}
+
+static void pru_set_delay_count(struct device *dev, u32 pru_freq)
+{
+	u32 u32delay_cnt;
+
+	if (pru_freq == 228)
+		u32delay_cnt = 5;
+	else if (pru_freq == 186)
+		u32delay_cnt = 5;
+	else
+		u32delay_cnt = 3;
+
+	/* PRU 0 */
+	pruss_writeb(dev, PRU_SUART_PRU0_DELAY_OFFSET,
+		(u8 *) &u32delay_cnt, 1);
+
+	/* PRU 1 */
+	pruss_writeb(dev, PRU_SUART_PRU1_DELAY_OFFSET,
+		(u8 *) &u32delay_cnt, 1);
+}
+
+static s32 suart_set_pru_id(struct device *dev, u32 pru_no)
+{
+	u32 offset;
+	u8 reg_val = 0;
+
+	if (0 == pru_no)
+		offset = PRU_SUART_PRU0_ID_ADDR;
+	else if (1 == pru_no)
+		offset = PRU_SUART_PRU1_ID_ADDR;
+	else
+		return PRU_SUART_FAILURE;
+
+	reg_val = pru_no;
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 1);
+
+	return PRU_SUART_SUCCESS;
+}
+
+/*
+ * suart Initialization routine
+ */
+s16 pru_softuart_init(struct device *dev, u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			u8 *pru_suart_emu_code, u32 fw_size,
+			pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 u32datatowrite[128] = {0};
+	s16 status = PRU_SUART_SUCCESS;
+	s16 idx;
+	s16 retval;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) &&
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH))
+		return PRU_SUART_FAILURE;
+
+	suart_iomap.mcasp_io_addr = pruss_ioaddr->mcasp_io_addr;
+	suart_iomap.p_fifo_buff_phys_base =
+					pruss_ioaddr->p_fifo_buff_phys_base;
+	suart_iomap.p_fifo_buff_virt_base =
+					pruss_ioaddr->p_fifo_buff_virt_base;
+	suart_iomap.pru_clk_freq = pruss_ioaddr->pru_clk_freq;
+	/* Configure McASP0  */
+	suart_mcasp_config(tx_baud_value,
+			rx_baud_value, oversampling, pruss_ioaddr);
+	pruss_enable(dev, PRUSS_NUM0);
+	pruss_enable(dev, PRUSS_NUM1);
+
+	/* Reset PRU RAM */
+	pruss_writel(dev, PRU0_DATARAM_OFFSET, u32datatowrite,
+				 (PRU0_DATARAM_SIZE / sizeof(int)));
+	pruss_writel(dev, PRU1_DATARAM_OFFSET, u32datatowrite,
+				 (PRU1_DATARAM_SIZE / sizeof(int)));
+	pruss_load(dev, PRUSS_NUM0, (u32 *)pru_suart_emu_code,
+				(fw_size / sizeof(u32)));
+	pruss_load(dev, PRUSS_NUM1, (u32 *)pru_suart_emu_code,
+				(fw_size / sizeof(u32)));
+	retval = arm_to_pru_intr_init(dev);
+	if (-1 == retval)
+		return status;
+	pru_set_delay_count(dev, pruss_ioaddr->pru_clk_freq);
+	suart_set_pru_id(dev, PRUSS_NUM0);
+	suart_set_pru_id(dev, PRUSS_NUM1);
+	pru_set_rx_tx_mode(dev, PRU0_MODE, PRUSS_NUM0);
+	pru_set_rx_tx_mode(dev, PRU1_MODE, PRUSS_NUM1);
+	pru_set_ram_data(dev, pruss_ioaddr);
+	pruss_run(dev, PRUSS_NUM0);
+	pruss_run(dev, PRUSS_NUM1);
+
+	/* Initialize g_uart_statu_table */
+	for (idx = 0; idx < 8; idx++)
+		g_uart_statu_table[idx] = ePRU_SUART_UART_FREE;
+
+	return status;
+}
+
+void pru_set_fifo_timeout(struct device *dev, s16 timeout)
+{
+	pruss_writew(dev, PRU_SUART_PRU0_IDLE_TIMEOUT_OFFSET,
+		&timeout, 1);
+	pruss_writew(dev, PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET,
+		&timeout, 1);
+}
+
+s16 pru_softuart_deinit(struct device *dev)
+{
+	u32 offset;
+	s16 s16retval = 0;
+	u32 u32value = 0;
+
+	offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+	u32value = 0xFFFFFFFF;
+	s16retval = pruss_writel(dev, offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+	offset = (u32) (PRUSS_INTC_STATCLRINT0 & 0xFFFF);
+	u32value = 0xFFFFFFFF;
+	s16retval = pruss_writel(dev, offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+	pruss_disable(dev, 0);
+	pruss_disable(dev, 1);
+
+	return PRU_SUART_SUCCESS;
+}
+
+/* suart Instance open routine  */
+s16 pru_softuart_open(suart_handle h_suart)
+{
+	s16 status = PRU_SUART_SUCCESS;
+
+	switch (h_suart->uart_num) {
+	case PRU_SUART_UART1:
+		if (g_uart_statu_table[PRU_SUART_UART1 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART0_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART0_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART0_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART1 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART2:
+		if (g_uart_statu_table[PRU_SUART_UART2 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART1_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART1_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART1_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART2 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART3:
+		if (g_uart_statu_table[PRU_SUART_UART3 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART2_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART2_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART2_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART3 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART4:
+		if (g_uart_statu_table[PRU_SUART_UART4 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART3_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART3_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART3_CONFIG_RX_SER;
+
+			g_uart_statu_table[PRU_SUART_UART4 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART5:
+		if (g_uart_statu_table[PRU_SUART_UART5 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART4_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART4_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART4_CONFIG_RX_SER;
+
+			g_uart_statu_table[PRU_SUART_UART5 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART6:
+		if (g_uart_statu_table[PRU_SUART_UART6 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART5_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART5_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART5_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART6 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART7:
+		if (g_uart_statu_table[PRU_SUART_UART7 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART6_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART6_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART6_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART7 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART8:
+		if (g_uart_statu_table[PRU_SUART_UART8 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART7_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART7_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART7_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART8 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	default:
+		status = SUART_INVALID_UART_NUM;
+		break;
+	}
+	return status;
+}
+
+/* suart instance close routine */
+s16 pru_softuart_close(suart_handle h_uart)
+{
+	s16 status = SUART_SUCCESS;
+
+	if (h_uart == NULL) {
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	} else {
+		g_uart_statu_table[h_uart->uart_num - 1] =
+			ePRU_SUART_UART_FREE;
+		/* Reset the Instance to Invalid */
+		h_uart->uart_num = PRU_SUART_UARTx_INVALID;
+		h_uart->uart_status = ePRU_SUART_UART_FREE;
+	}
+	return status;
+}
+
+/*
+ * suart routine for setting relative baud rate
+ */
+s16 pru_softuart_setbaud(struct device *dev, suart_handle h_uart,
+		u16 tx_clk_divisor, u16 rx_clk_divisor)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 regval = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/* Set the clock divisor value s32o the McASP */
+	if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
+		return SUART_INVALID_CLKDIVISOR;
+	if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
+		return SUART_INVALID_CLKDIVISOR;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	if (tx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+			(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = 0;
+	if (rx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	return status;
+}
+
+/*
+ * suart routine for setting number of bits per character for a specific uart
+ */
+s16 pru_softuart_setdatabits(struct device *dev, suart_handle h_uart,
+		u16 tx_data_bits, u16 rx_data_bits)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u32 reg_val;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/*
+	 * NOTE:
+	 * The supported data bits are 6,7,8,9,10,11,12 bits per character
+	 */
+
+	if ((tx_data_bits < ePRU_SUART_DATA_BITS6)
+			|| (tx_data_bits > ePRU_SUART_DATA_BITS12))
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+
+	if ((rx_data_bits < ePRU_SUART_DATA_BITS6)
+			|| (rx_data_bits > ePRU_SUART_DATA_BITS12))
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+			|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	if (tx_data_bits != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 1);
+		reg_val &= ~(0xF);
+		reg_val |= tx_data_bits;
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 1);
+	}
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+			|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	if (rx_data_bits != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 1);
+		reg_val &= ~(0xF);
+		reg_val |= rx_data_bits;
+		pruss_writeb(dev, offset, (u8 *) &rx_data_bits, 1);
+	}
+
+	return status;
+}
+
+/*
+ * suart routine to configure specific uart
+ */
+s16 pru_softuart_setconfig(struct device *dev, suart_handle h_uart,
+				suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/*
+	 * NOTE:
+	 * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
+	 * EQUAL TO 64, preScalarValue <= 64
+	 */
+	if ((config_uart->tx_clk_divisor > 384)
+			|| (config_uart->rx_clk_divisor > 384)) {
+		return SUART_INVALID_CLKDIVISOR;
+	}
+	if ((config_uart->tx_bits_per_char < 8)
+			|| (config_uart->tx_bits_per_char > 14)) {
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+	}
+	if ((config_uart->rx_bits_per_char < 8)
+			|| (config_uart->rx_bits_per_char > 14)) {
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+	}
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+			|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Configuring the Transmit part of the given UART */
+	/* Serializer has been as TX in mcasp config, by writing 1 in bits
+	*  corresponding to tx serializer in PFUNC regsiter ie already set
+	*  to GPIO mode PRU code will set then back to MCASP mode once TX
+	*  request for that serializer is posted.It is required because at this
+	*  pos32 Mcasp is accessed by both PRU and DSP have lower priority for
+	*  Mcasp in comparison to PRU and DPS keeps on looping there only
+	*/
+	/*
+	 * suart_mcasp_tx_serialzier_set
+	 * (config_uart->tx_serializer, &suart_iomap);
+	 */
+	/* Configuring TX serializer  */
+	if (config_uart->tx_serializer != PRU_SUART_SERIALIZER_NONE) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CTRL_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->tx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->tx_clk_divisor <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->tx_bits_per_char <<
+			PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+		offset = 8;
+		pru_softuart_write(dev, h_uart, &offset, 0);
+	}
+
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+			(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Configuring the Transmit part of the given UART */
+	if (config_uart->rx_serializer != PRU_SUART_SERIALIZER_NONE) {
+		/* Configuring RX serializer  */
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CTRL_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->rx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+		/* Configuring RX prescalar value and Oversampling */
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->rx_clk_divisor <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT) |
+			(config_uart->oversampling <<
+			PRU_SUART_CH_CONFIG1_OVS_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+		/* Configuring RX bits per character value */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+						+ PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->rx_bits_per_char <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+	}
+	return status;
+}
+
+/*
+ * suart routine for getting the number of bytes transfered
+ */
+s16 pru_softuart_get_tx_data_len(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16_read_value = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16_read_value, 2);
+	u16_read_value = ((u16_read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	return u16_read_value;
+}
+
+/*
+ * suart routine for getting the number of bytes received
+ */
+s16 pru_softuart_get_rx_data_len(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16_read_value = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16_read_value, 2);
+	u16_read_value = ((u16_read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+
+	return u16_read_value;
+}
+
+/*
+ * suart routine to get the configuration information from a specific uart
+ */
+s16 pru_softuart_getconfig(struct device *dev,
+			 suart_handle h_uart, suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 reg_val = 0;
+	s16 status = SUART_SUCCESS;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/*
+	 * NOTE:
+	 * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
+	 * EQUAL TO 64, preScalarValue <= 64
+	 */
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+					 (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Configuring the Transmit part of the given UART */
+	/* Configuring TX serializer  */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->tx_serializer = ((reg_val & PRU_SUART_CH_CTRL_SR_MASK) >>
+						PRU_SUART_CH_CTRL_SR_SHIFT);
+	/* Configuring TX prescalar value */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG1_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->tx_clk_divisor = ((reg_val &
+				 PRU_SUART_CH_CONFIG1_DIVISOR_MASK) >>
+					 PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+	/* Configuring TX bits per character value */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->tx_bits_per_char = ((reg_val &
+				 PRU_SUART_CH_CONFIG1_DIVISOR_MASK) >>
+					PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	/* Configuring the Transmit part of the given UART */
+	/* Configuring RX serializer  */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->rx_serializer = ((reg_val & PRU_SUART_CH_CTRL_SR_MASK) >>
+						PRU_SUART_CH_CTRL_SR_SHIFT);
+
+	/* Configuring RX prescalar value and oversampling */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG1_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->rx_clk_divisor = ((reg_val &
+					 PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+	config_uart->oversampling = ((reg_val &
+					 PRU_SUART_CH_CONFIG1_OVS_MASK) >>
+						PRU_SUART_CH_CONFIG1_OVS_SHIFT);
+
+	/* Configuring RX bits per character value */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->rx_bits_per_char = ((reg_val &
+					 PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+	return status;
+}
+
+s32 pru_softuart_pending_tx_request(struct device *dev)
+{
+	u32 offset = 0;
+	u32 u32ISR_value = 0;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		return SUART_SUCCESS;
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		/* Read PRU Interrupt Status Register from PRU */
+		offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+		pruss_readl(dev, offset, (u32 *)&u32ISR_value, 1);
+		if ((u32ISR_value & 0x1) == 0x1)
+			return PRU_SUART_FAILURE;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		/* Read PRU Interrupt Status Register from PRU */
+		offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+		pruss_readl(dev, offset, (u32 *)&u32ISR_value, 1);
+		if ((u32ISR_value & 0x2) == 0x2)
+			return PRU_SUART_FAILURE;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	return SUART_SUCCESS;
+}
+
+/*
+ * suart data transmit routine
+ */
+s16 pru_softuart_write(struct device *dev, suart_handle h_uart,
+		u32 *pt_tx_data_buf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			pru_num = h_uart->uart_num;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+			pru_num = h_uart->uart_num;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		pru_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		pru_num = 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* Writing the data pos32er to channel TX data pointer */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_TXRXDATA_OFFSET;
+	pruss_writeb(dev, offset, (u8 *) pt_tx_data_buf, 4);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~(PRU_SUART_CH_CTRL_MODE_MASK |
+			PRU_SUART_CH_CTRL_SREQ_MASK);
+	reg_val |= (PRU_SUART_CH_CTRL_TX_MODE <<
+		PRU_SUART_CH_CTRL_MODE_SHIFT) | (PRU_SUART_CH_CTRL_SREQ <<
+		PRU_SUART_CH_CTRL_SREQ_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, pru_num);
+
+	return status;
+}
+
+/*
+ * suart data receive routine
+ */
+s16 pru_softuart_read(struct device *dev, suart_handle h_uart,
+		u32 *ptDataBuf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+			 (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+	ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			pru_num = h_uart->uart_num;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+			pru_num = h_uart->uart_num;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		pru_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		pru_num = 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* Writing the data pos32er to channel RX data pointer */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+		PRU_SUART_CH_TXRXDATA_OFFSET;
+	pruss_writeb(dev, offset, (u8 *) ptDataBuf, 4);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+		PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~(PRU_SUART_CH_CTRL_MODE_MASK |
+		PRU_SUART_CH_CTRL_SREQ_MASK);
+	reg_val |= (PRU_SUART_CH_CTRL_RX_MODE <<
+		PRU_SUART_CH_CTRL_MODE_SHIFT) | (PRU_SUART_CH_CTRL_SREQ <<
+		PRU_SUART_CH_CTRL_SREQ_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* enable the timeout s32errupt */
+	suart_intr_setmask(dev, h_uart->uart_num, PRU_RX_INTR,
+		CHN_TXRX_IE_MASK_TIMEOUT);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, pru_num);
+
+	return status;
+}
+
+/*
+ * suart routine to read the data from the RX FIFO
+ */
+s16 pru_softuart_read_data(struct device *dev, suart_handle h_uart,
+				u8 *p_data_buffer, s32 s32max_len,
+					u32 *pu32data_read)
+{
+	s16 ret_val = PRU_SUART_SUCCESS;
+	u8 *pu8src_addr = NULL;
+	u32 u32data_read = 0;
+	u32 u32data_len = 0;
+	u32 u32char_len = 0;
+	u32 offset = 0;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16status = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Get the data pos32er from channel RX data pointer */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_TXRXDATA_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &pu8src_addr, 4);
+
+	/* Reading data length from SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u32data_len, 2);
+
+	/* read the character length */
+	u32char_len = u32data_len & PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK;
+	u32char_len -= 2;	/* remove the START & STOP bit */
+
+	u32data_len &= PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	u32data_len = u32data_len >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT;
+	u32data_len++;
+
+	/* if the character length is greater than 8, then the size doubles */
+	if (u32char_len > 8)
+		u32data_len *= 2;
+
+	/* Check if the time-out had occured. If, yes, then we need to find the
+	 * number of bytes read from PRU. Else, we need to
+	 * read the requested bytes
+	 */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16status, 1);
+	if (CHN_TXRX_STATUS_TIMEOUT == (u16status & CHN_TXRX_STATUS_TIMEOUT)) {
+		/* determine the number of bytes read s32o the FIFO */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+				 + PRU_SUART_CH_BYTESDONECNTR_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &u32data_read, 1);
+
+		/* if the character length is greater than 8,
+				then the size doubles */
+		if (u32char_len > 8)
+			u32data_read *= 2;
+
+/*
+ * the data corresponding is loaded in second
+ * half during the timeout
+ */
+		if (u32data_read > u32data_len) {
+			u32data_read -= u32data_len;
+			pu8src_addr += (u32data_len + 1);
+		}
+
+		pru_softuart_clr_rx_fifo(dev, h_uart);
+	} else {
+		u32data_read = u32data_len;
+/*
+ * if the bit is set, the data is in the first
+ * half of the FIFO else the data is in the second half
+ */
+		/* Determine the buffer index by reading FIFO_OddEven flag*/
+		if (u16status & CHN_TXRX_STATUS_CMPLT)
+			pu8src_addr += u32data_len;
+	}
+
+	/* we should be copying only max len given by the application */
+	if (u32data_read > s32max_len)
+		u32data_read = s32max_len;
+
+/* evaluate the virtual address of the FIFO address
+ * based on the physical addr
+ */
+	pu8src_addr = (u8 *)((u32) pu8src_addr -
+		(u32) suart_iomap.p_fifo_buff_phys_base +
+		(u32) suart_iomap.p_fifo_buff_virt_base);
+
+	/* Now we have both the data length and the source address. copy */
+	for (offset = 0; offset < u32data_read; offset++) {
+		*p_data_buffer++ = *pu8src_addr++;
+	}
+	*pu32data_read = u32data_read;
+	ret_val = PRU_SUART_SUCCESS;
+
+	return ret_val;
+}
+
+/*
+ * suart routine to disable the receive functionality.
+ * This routine stops the PRU from receiving on selected
+ * UART and also disables the McASP serializer corresponding
+ * to this UART Rx line.
+ */
+s16 pru_softuart_stop_receive(struct device *dev, suart_handle h_uart)
+{
+	u16 status = SUART_SUCCESS;
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16status;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* read the existing value of status flag */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16status, 1);
+
+	/* we need to clear the busy bit corresponding to receive channel */
+	u16status &= ~(CHN_TXRX_STATUS_RDY);
+	pruss_writeb(dev, offset, (u8 *) &u16status, 1);
+
+	/* get the serizlizer number being used for this Rx channel */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16status, 2);
+	u16status &= PRU_SUART_CH_CTRL_SR_MASK;
+	u16status = u16status >> PRU_SUART_CH_CTRL_SR_SHIFT;
+
+	/* we need to de-activate the serializer corresponding to this rx */
+	status = suart_asp_serializer_deactivate(u16status, &suart_iomap);
+
+	return status;
+}
+
+/*
+ * suart routine to get the tx status for a specific uart
+ */
+s16 pru_softuart_get_tx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+s16 pru_softuart_clr_tx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	status &= ~(0x2);
+	pruss_writeb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+/*
+ * suart routine to get the rx status for a specific uart
+ */
+s16 pru_softuart_get_rx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+s16 pru_softuart_clr_rx_fifo(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val;
+	u16 uart_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	uart_num = h_uart->uart_num;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		uart_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		uart_num = 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~(PRU_SUART_CH_CTRL_MODE_MASK | PRU_SUART_CH_CTRL_SREQ_MASK);
+	reg_val |= (PRU_SUART_CH_CTRL_RX_MODE << PRU_SUART_CH_CTRL_MODE_SHIFT) |
+		(PRU_SUART_CH_CTRL_SREQ << PRU_SUART_CH_CTRL_SREQ_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+	suart_intr_setmask(dev, h_uart->uart_num, PRU_RX_INTR,
+						CHN_TXRX_IE_MASK_TIMEOUT);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, uart_num);
+
+	return status;
+}
+
+s16 pru_softuart_clr_rx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+		(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	status &= ~(0x3C);
+	pruss_writeb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+/*
+ * suart_s32r_status_read: Gets the Global Interrupt status register
+ * for the specified SUART.
+ * uart_num < 1 to 6 >
+ * txrx_flag < Indicates TX or RX s32errupt for the uart >
+ */
+s16 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num, u16 *txrx_flag)
+{
+	u32 offset;
+	u32 u32intc_offset;
+	u32 ch_num = 0xFF;
+	u32 reg_val = 0;
+	u32 u32reg_val = 0;
+	u32 u32ISR_value = 0;
+	u32 u32ack_reg_val = 0;
+	u8 pru0_mode = PRU_MODE_INVALID;
+	u8 pru1_mode = PRU_MODE_INVALID;
+	u32 u32stat_inx_clr_regoffset = 0;
+
+	/* initialize the status & Flag to known value */
+	*txrx_flag = 0;
+
+	u32stat_inx_clr_regoffset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+
+	/* Read PRU Interrupt Status Register from PRU */
+	u32intc_offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+
+	pruss_readl(dev, u32intc_offset, (u32 *)&u32ISR_value, 1);
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* determine if the s32errupt occured current UART context */
+		u32reg_val = (PRU_SUART0_TX_EVT_BIT | PRU_SUART0_RX_EVT_BIT) <<
+				((uart_num - 1) * 2);
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = uart_num * 2 - 2;
+		if (uart_num <= 4)
+			pru0_mode = PRU_MODE_RX_TX_BOTH;
+		else
+			pru1_mode = PRU_MODE_RX_TX_BOTH;
+	} else {
+		ch_num = uart_num - 1;
+		if ((u32ISR_value & 0x03FC) != 0) {
+			u32reg_val = 0;
+
+			offset = PRU_SUART_PRU0_RX_TX_MODE;
+			pruss_readb(dev, offset, (u8 *) &pru0_mode, 1);
+			u32reg_val |= 1 << (uart_num + 1);
+			if (u32ISR_value & u32reg_val) {
+				/* acknowledge the s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+				*txrx_flag |= PRU_RX_INTR;
+			}
+		}
+		pruss_readl(dev, u32intc_offset, (u32 *)&u32ISR_value, 1);
+		if (u32ISR_value & 0x3FC00) {
+			u32reg_val = 0;
+			offset = PRU_SUART_PRU1_RX_TX_MODE;
+			pruss_readb(dev, offset, (u8 *) &pru1_mode, 1);
+			u32reg_val |= 1 << (uart_num + 9);
+			if (u32ISR_value & u32reg_val) {
+				/* acknowledge the s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART4_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+				*txrx_flag |= PRU_TX_INTR;
+			}
+		}
+	}
+	if (u32ISR_value & u32reg_val) {
+		if ((pru0_mode == PRU_MODE_RX_TX_BOTH)
+		    || (pru1_mode == PRU_MODE_RX_TX_BOTH)) {
+			/* Check if the s32errupt occured for Tx */
+			u32reg_val = PRU_SUART0_TX_EVT_BIT << ((uart_num - 1)
+									 * 2);
+			if (u32ISR_value & u32reg_val) {
+				/* s32erupt occured for TX */
+				*txrx_flag |= PRU_TX_INTR;
+				/* acknowledge the RX s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+			}
+
+			/* Check if the s32errupt occured for Rx */
+			u32reg_val = PRU_SUART0_RX_EVT_BIT<<((uart_num - 1)
+									 * 2);
+			if (u32ISR_value & u32reg_val) {
+				/* s32erupt occured for RX */
+				*txrx_flag |= PRU_RX_INTR;
+				ch_num += 1;
+
+				/* acknowledge the RX s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+			}
+		}
+		reg_val = SUART_SUCCESS;
+	}
+	return reg_val;
+}
+
+s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num, u32 txrxmode)
+{
+	u32 offset;
+	u16 txrx_flag = 0;
+	u16 chn_num;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (uart_num <= 4) {
+			/* PRU0 */
+			offset = PRU_SUART_PRU0_ISR_OFFSET + 1;
+		} else {
+			/* PRU1 */
+			offset = PRU_SUART_PRU1_ISR_OFFSET + 1;
+			/* First 8 channel corresponds to PRU0 */
+			chn_num -= 8;
+		}
+		if (2 == txrxmode)
+			chn_num++;
+	} else if (PRU0_MODE == txrxmode) {
+		offset = PRU_SUART_PRU0_ISR_OFFSET + 1;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_ISR_OFFSET + 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	pruss_readb(dev, offset, (u8 *) &txrx_flag, 1);
+	txrx_flag &= ~(0x2);
+	pruss_writeb(dev, offset, (u8 *) &txrx_flag, 1);
+
+	return 0;
+}
+
+s16 suart_arm_to_pru_intr(struct device *dev, u16 uart_num)
+{
+	u32 u32offset;
+	u32 u32value;
+	s16 s16retval;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		if ((uart_num > 0) && (uart_num <= 4)) {
+			/* PRU0 SYS_EVT32 */
+			u32value = 0x20;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			/* PRU1 SYS_EVT33 */
+			u32value = 0x21;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+	}
+
+	if ((PRU0_MODE == PRU_MODE_RX_ONLY) || (PRU1_MODE == PRU_MODE_RX_ONLY)
+	    || (PRU0_MODE == PRU_MODE_TX_ONLY)
+	    || (PRU1_MODE == PRU_MODE_TX_ONLY)) {
+		if (uart_num == PRUSS_NUM0) {
+			/* PRU0 SYS_EVT32 */
+			u32value = 0x20;
+		}
+
+		if (uart_num == PRUSS_NUM1) {
+			/* PRU0 SYS_EVT33 */
+			u32value = 0x21;
+		}
+	}
+
+	u32offset = (u32) (PRUSS_INTC_STATIDXSET & 0xFFFF);
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+	return 0;
+}
+
+s16 arm_to_pru_intr_init(struct device *dev)
+{
+	u32 u32offset;
+	u32 u32value;
+	u32 int_offset;
+	s16 s16retval = -1;
+#if 0
+	/* Set the MCASP Event to PRU0 as Edge Triggered */
+	u32offset = (u32)(PRU_INTC_TYPE0 & 0xFFFF);
+	u32value = 0x80000000;
+	s16retval =
+	    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+#endif
+	/* Clear all the host s32errupts */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_HSTINTENIDXCLR & 0xFFFF);
+		u32value = int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+
+	/* Enable the global s32errupt */
+	u32offset = (u32) (PRUSS_INTC_GLBLEN & 0xFFFF);
+	u32value = 0x1;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	/* Enable the Host s32errupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							 int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
+		u32value = int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+
+	u32offset = (u32) (PRUSS_INTC_HOSTMAP0 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_123_HOST;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+
+	u32offset = (u32) (PRUSS_INTC_HOSTMAP1 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_4567_HOST;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+	u32offset = (u32) (PRUSS_INTC_HOSTMAP2 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_89_HOST;
+	s16retval =
+	    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+
+	/* Set the channel for System s32rrupts
+	 * MAP Channel 0 to SYS_EVT31
+	 */
+	u32offset =	(u32) (PRUSS_INTC_CHANMAP7 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_0_SYSEVT_31;
+	s16retval =
+	    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		u32offset = (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_12_SYSEVT;
+		s16retval =
+		    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 3 to SYS_EVT36   SUART1-Tx
+		 * MAP channel 3 to SYS_EVT37   SUART1-Rx
+		 * MAP channel 4 to SYS_EVT38   SUART2-Tx
+		 * MAP channel 4 to SYS_EVT39   SUART2-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 5 to SYS_EVT40   SUART3-Tx
+		 * MAP channel 5 to SYS_EVT41   SUART3-Rx
+		 * MAP channel 6 to SYS_EVT42   SUART4-Tx
+		 * MAP channel 6 to SYS_EVT43   SUART4-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_56_SYSEVT_40_43;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 7 to SYS_EVT44   SUART5-Tx
+		 * MAP channel 7 to SYS_EVT45   SUART5-Rx
+		 * MAP channel 8 to SYS_EVT46   SUART6-Tx
+		 * MAP channel 8 to SYS_EVT47   SUART6-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_78_SYSEVT_44_47;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 9 to SYS_EVT48   SUART7-Tx
+		 * MAP channel 9 to SYS_EVT49   SUART7-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_9_SYSEVT_48_49;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+	}
+	if ((PRU0_MODE == PRU_MODE_RX_ONLY) || (PRU1_MODE == PRU_MODE_RX_ONLY)
+	    || (PRU0_MODE == PRU_MODE_TX_ONLY)
+	    || (PRU1_MODE == PRU_MODE_TX_ONLY)) {
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 0 to SYS_EVT32
+		 * MAP channel 1 to SYS_EVT33
+		 * MAP channel 2 to SYS_EVT34  SUART0
+		 * MAP channel 3 to SYS_EVT35  SUART1
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_0123_SYSEVT_32_35;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 4 to SYS_EVT36   SUART2
+		 * MAP channel 5 to SYS_EVT37   SUART3
+		 * MAP channel 6 to SYS_EVT38   SUART4
+		 * MAP channel 7 to SYS_EVT39   SUART5
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_4567_SYSEVT_36_39;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 8 to SYS_EVT40   SUART6
+		 * MAP channel 9 to SYS_EVT41   SUART7
+		 * MAP channel 2 to SYS_EVT42   SUART0
+		 * MAP channel 3 to SYS_EVT43   SUART1
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_8923_SYSEVT_40_43;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 4 to SYS_EVT44   SUART2
+		 * MAP channel 5 to SYS_EVT45   SUART3
+		 * MAP channel 6 to SYS_EVT46   SUART4
+		 * MAP channel 7 to SYS_EVT47   SUART5
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_4567_SYSEVT_44_47;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 8 to SYS_EVT48   SUART6
+		 * MAP channel 9 to SYS_EVT49   SUART7
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF);
+		u32value = 0x00010908;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+	}
+
+	/* Clear required set of system events
+	* and enable them using indexed register
+	*/
+	for (int_offset = 0; int_offset < 18; int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+		u32value = 32 + int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+
+	}
+	/* enable only the HOST to PRU s32errupts and let the PRU to Host events
+	 * enabled by the separate API on demand basis.
+	 */
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 31;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 32;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 33;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 50;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	/* Enable the global s32errupt */
+	u32offset = (u32) (PRUSS_INTC_GLBLEN & 0xFFFF);
+	u32value = 0x1;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	/* Enable the Host s32errupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
+		u32value = int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+
+	return 0;
+}
+
+s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
+		u32 txrxmode, s32 s32_flag)
+{
+	s32 ret_val = 0;
+	u32 u32offset;
+	u32 chn_num;
+	u32 u32value;
+	s16 s16retval = 0;
+
+	if (uart_num > 8)
+		return SUART_INVALID_UART_NUM;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+		(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		chn_num = (uart_num * 2) - 2;
+		if (2 == txrxmode)	/* Rx mode */
+			chn_num++;
+		u32value = 34 + chn_num;
+	} else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_RX_ONLY))
+		u32value = 34 + chn_num;
+	else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_RX_ONLY))
+		u32value = 42 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_TX_ONLY))
+		u32value = 34 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_TX_ONLY))
+		u32value = 42 + chn_num;
+	else
+		return -1;
+
+	if (SUART_TRUE == s32_flag) {
+		u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	} else {
+		u32offset = (u32) (PRUSS_INTC_ENIDXCLR & 0xFFFF);
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+	return ret_val;
+}
+
+s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 s32rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	u32 txrx_flag;
+	u32 regval = 0;
+	u32 chn_num;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if ((uart_num > 0) && (uart_num <= 4)) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			offset = PRU_SUART_PRU0_IMR_OFFSET;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			offset = PRU_SUART_PRU1_IMR_OFFSET;
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			chn_num -= 8;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+		if (2 == txrxmode) {	/* rx mode */
+			chn_num++;
+		}
+	} else if (PRU0_MODE == txrxmode) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		offset = PRU_SUART_PRU0_IMR_OFFSET;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (s32rmask & CHN_TXRX_IE_MASK_CMPLT)) {
+		pruss_readb(dev, offset, (u8 *) &txrx_flag, 2);
+		txrx_flag &= ~(regval);
+		txrx_flag |= regval;
+		pruss_writeb(dev, offset, (u8 *) &txrx_flag, 2);
+	}
+	if ((s32rmask & SUART_GBL_INTR_ERR_MASK) ==
+			SUART_GBL_INTR_ERR_MASK) {
+		regval = 0;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(SUART_GBL_INTR_ERR_MASK);
+		regval |= (SUART_GBL_INTR_ERR_MASK);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+
+	}
+	/* Break Indicator Interrupt Masked */
+	if ((s32rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		regval |= CHN_TXRX_IE_MASK_FE;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	/* Framing Error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (s32rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		regval |= CHN_TXRX_IE_MASK_BI;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(s32rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		regval |= CHN_TXRX_IE_MASK_TIMEOUT;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	return 0;
+}
+
+s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 s32rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 txrx_flag;
+	u16 regval = 0;
+	u16 chn_num;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if ((uart_num > 0) && (uart_num <= 4)) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			offset = PRU_SUART_PRU0_IMR_OFFSET;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			/* PRU1 */
+			offset = PRU_SUART_PRU1_IMR_OFFSET;
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			chn_num -= 8;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+		if (2 == txrxmode) {	/* rx mode */
+			chn_num++;
+		}
+	} else if (PRU0_MODE == txrxmode) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		offset = PRU_SUART_PRU0_IMR_OFFSET;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (s32rmask & CHN_TXRX_IE_MASK_CMPLT)) {
+		pruss_readb(dev, offset, (u8 *) &txrx_flag, 2);
+		txrx_flag &= ~(regval);
+		pruss_writeb(dev, offset, (u8 *) &txrx_flag, 2);
+	}
+
+	if ((s32rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK) {
+		regval = 0;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(SUART_GBL_INTR_ERR_MASK);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+
+	}
+	/* Break Indicator Interrupt Masked */
+	if ((s32rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	/* Framing Error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (s32rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(s32rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	return 0;
+}
+
+s32 suart_intr_getmask(struct device *dev, u16 uart_num, u32 txrxmode,
+			u32 s32rmask)
+{
+	u16 chn_num;
+	u32 offset;
+	u16 txrx_flag;
+	u16 regval = 1;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if ((uart_num > 0) && (uart_num <= 4)) {
+
+			offset = PRU_SUART_PRU0_IMR_OFFSET;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			/* PRU1 */
+			offset = PRU_SUART_PRU1_IMR_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			chn_num -= 8;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+
+		if (2 == txrxmode) {	/* rx mode */
+			chn_num++;
+		}
+	} else if (PRU0_MODE == txrxmode) {
+		offset = PRU_SUART_PRU0_IMR_OFFSET;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = regval << chn_num;
+	pruss_readb(dev, offset, (u8 *) &txrx_flag, 2);
+	txrx_flag &= regval;
+	if (0 == s32rmask) {
+		if (txrx_flag == 0)
+			return 1;
+	}
+	if (1 == s32rmask) {
+		if (txrx_flag == regval)
+			return 1;
+	}
+	return 0;
+}
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
new file mode 100644
index 0000000..4ce5621
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _SUART_API_H_
+#define _SUART_API_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+
+#define SINGLE_PRU				0
+#define BOTH_PRU				1
+#define PRU_ACTIVE				BOTH_PRU
+
+#define SUART_NUM_OF_CHANNELS_PER_SUART		2
+#define SUART_NUM_OF_BYTES_PER_CHANNEL		16
+
+#define SUART_PASS				0
+#define SUART_SUCCESS				0
+#define SUART_FAIL				1
+#define SUART_FALSE				0
+#define SUART_TRUE				1
+
+#define PRU_TX_INTR				1
+#define PRU_RX_INTR				2
+
+#define CHN_TXRX_STATUS_TIMEOUT			BIT(6)
+#define CHN_TXRX_STATUS_BI			BIT(5)
+#define CHN_TXRX_STATUS_FE			BIT(4)
+#define CHN_TXRX_STATUS_UNERR			BIT(3)
+#define CHN_TXRX_STATUS_OVRNERR			BIT(3)
+#define CHN_TXRX_STATUS_ERR			BIT(2)
+#define CHN_TXRX_STATUS_CMPLT			BIT(1)
+#define CHN_TXRX_STATUS_RDY			BIT(0)
+
+#define CHN_TXRX_IE_MASK_TIMEOUT		BIT(14)
+#define CHN_TXRX_IE_MASK_BI			BIT(13)
+#define CHN_TXRX_IE_MASK_FE			BIT(12)
+#define CHN_TXRX_IE_MASK_CMPLT			BIT(1)
+
+#define SUART_GBL_INTR_ERR_MASK			BIT(9)
+#define SUART_PRU_ID_MASK			0xFF
+
+#define SUART_FIFO_LEN				15
+#define SUART_8X_OVRSMPL			1
+#define SUART_16X_OVRSMPL			2
+#define SUART_DEFAULT_OVRSMPL			SUART_8X_OVRSMPL
+
+#if (SUART_DEFAULT_OVRSMPL == SUART_16X_OVRSMPL)
+#define SUART_DEFAULT_BAUD			57600
+#else
+#define SUART_DEFAULT_BAUD			115200
+#endif
+
+#define PRU_MODE_INVALID			0x00
+#define PRU_MODE_TX_ONLY			0x1
+#define PRU_MODE_RX_ONLY			0x2
+#define PRU_MODE_RX_TX_BOTH			0x3
+
+#if (PRU_ACTIVE == BOTH_PRU)
+#define PRU0_MODE				PRU_MODE_RX_ONLY
+#define PRU1_MODE				PRU_MODE_TX_ONLY
+#elif (PRU_ACTIVE ==  SINGLE_PRU)
+#define PRU0_MODE				PRU_MODE_RX_TX_BOTH
+#define PRU1_MODE				PRU_MODE_INVALID
+#else
+#define PRU0_MODE				PRU_MODE_INVALID
+#define PRU1_MODE				PRU_MODE_INVALID
+#endif
+
+#define MCASP_XBUF_BASE_ADDR			(0x01d00200)
+#define MCASP_RBUF_BASE_ADDR			(0x01d00280)
+#define MCASP_SRCTL_BASE_ADDR			(0x01d00180)
+
+#define MCASP_SRCTL_TX_MODE			(0x000D)
+#define MCASP_SRCTL_RX_MODE			(0x000E)
+
+/* Since only PRU0 can work as RX */
+#define RX_DEFAULT_DATA_DUMP_ADDR		(0x00001FC)
+#define PRU_NUM_OF_CHANNELS			(16)
+
+#define	PRU_SUART_UART1		(1u)
+#define	PRU_SUART_UART2		(2u)
+#define	PRU_SUART_UART3		(3u)
+#define	PRU_SUART_UART4		(4u)
+#define	PRU_SUART_UART5		(5u)
+#define	PRU_SUART_UART6		(6u)
+#define	PRU_SUART_UART7		(7u)
+#define PRU_SUART_UART8		(8u)
+
+#define PRU_SUART_UARTx_INVALID	(9u)
+
+#define PRU_SUART_HALF_TX	(1u)
+#define PRU_SUART_HALF_RX			(2u)
+#define PRU_SUART_HALF_TX_DISABLED		(4u)
+#define PRU_SUART_HALF_RX_DISABLED		(8u)
+
+
+/*
+ *  This enum is used to specify the direction of the channel in UART
+ */
+typedef enum {
+	SUART_CHN_TX = 1,
+	SUART_CHN_RX = 2
+} SUART_CHN_DIR;
+
+/*
+ *  This enum is used to specify the state of the channel in UART. It
+ *  is either enabled or disabled.
+ */
+typedef enum {
+	SUART_CHN_DISABLED = 0,
+	SUART_CHN_ENABLED = 1
+} SUART_CHN_STATE;
+
+typedef enum {
+	ePRU_SUART_DATA_BITS6 = 8,
+	ePRU_SUART_DATA_BITS7,
+	ePRU_SUART_DATA_BITS8,
+	ePRU_SUART_DATA_BITS9,
+	ePRU_SUART_DATA_BITS10,
+	ePRU_SUART_DATA_BITS11,
+	ePRU_SUART_DATA_BITS12
+	} SUART_EN_BITSPERCHAR;
+
+typedef enum {
+	ePRU_SUART_NUM_1 = 1,
+	ePRU_SUART_NUM_2,
+	ePRU_SUART_NUM_3,
+	ePRU_SUART_NUM_4,
+	ePRU_SUART_NUM_5,
+	ePRU_SUART_NUM_6,
+	ePRU_SUART_NUM_7,
+	ePRU_SUART_NUM_8
+} SUART_EN_UARTNUM;
+
+typedef enum {
+	ePRU_SUART_HALF_TX = 1,
+	ePRU_SUART_HALF_RX,
+	ePRU_SUART_FULL_TX_RX
+} SUART_EN_UARTTYPE;
+
+typedef enum {
+	ePRU_SUART_TX_CH0 = 0,
+	ePRU_SUART_TX_CH1,
+	ePRU_SUART_TX_CH2,
+	ePRU_SUART_TX_CH3,
+	ePRU_SUART_TX_CH4,
+	ePRU_SUART_TX_CH5,
+	ePRU_SUART_TX_CH6,
+	ePRU_SUART_TX_CH7
+} SUART_EN_TXCHANNEL;
+
+typedef enum {
+	ePRU_SUART_RX_CH0 = 0,
+	ePRU_SUART_RX_CH1,
+	ePRU_SUART_RX_CH2,
+	ePRU_SUART_RX_CH3,
+	ePRU_SUART_RX_CH4,
+	ePRU_SUART_RX_CH5,
+	ePRU_SUART_RX_CH6,
+	ePRU_SUART_RX_CH7
+} SUART_EN_RXCHANNEL;
+
+typedef enum {
+	ePRU_SUART_UART_FREE = 0,
+	ePRU_SUART_UART_IN_USE
+} SUART_EN_UART_STATUS;
+
+typedef struct {
+	u16 mode:2;
+	u16 service_req:1;
+	u16 asp_id:2;
+	u16 reserved1:3;
+	u16 serializer_num:4;
+	u16 reserved2:4;
+
+} pru_suart_chn_cntrl;
+
+typedef struct {
+	u16 presacler:10;
+	u16 over_sampling:2;
+	u16 framing_mask:1;
+	u16 break_mask:1;
+	u16 timeout_mask:1;
+	u16 reserved:1;
+} pru_suart_cnh_config1;
+
+typedef struct {
+	u16 bits_per_char:4;
+	u16 reserved1:4;
+	u16 data_len:4;
+	u16 reserved:4;
+} pru_suart_chn_config2;
+
+typedef struct {
+	u16 txrx_ready:1;
+	u16 txrx_complete:1;
+	u16 txrx_error:1;
+	u16 txrx_underrun:1;
+	u16 framing_error:1;
+	u16 break_error:1;
+	u16 timeout_error:1;
+	u16 reserved:8;
+	u16 chn_state:1;
+} pru_suart_chn_status;
+
+typedef struct {
+	pru_suart_chn_cntrl ch_ctrl;
+	pru_suart_cnh_config1 ch_config1;
+	pru_suart_chn_config2 ch_config2;
+	pru_suart_chn_status ch_txrx_status;
+	u32 ch_txrx_data;
+	u32 reserved1;
+} pru_suart_regs, *pru_suart_regs_ovly;
+
+typedef struct {
+	u32 asp_xsrctl_base;
+	u32 asp_xbuf_base;
+	u16 buff_addr;
+	u8 buff_size;
+	u8 bits_loaded;
+} pru_suart_tx_cntx_priv, *ppru_suart_tx_cntx_priv;
+
+typedef struct {
+	u32 asp_rbuf_base;
+	u32 asp_rsrctl_base;
+	u32 reserved1;
+	u32 reserved2;
+	u32 reserved3;
+	u32 reserved4;
+} pru_suart_rx_cntx_priv, *ppru_suart_rx_cntx_priv;
+
+typedef struct {
+	u8  tx_serializer;
+	u8  rx_serializer;
+	u16 tx_clk_divisor;
+	u16 rx_clk_divisor;
+	u8  tx_bits_per_char;
+	u8  rx_bits_per_char;
+	u8  oversampling;
+	u8  bi_inter_mask;
+	u8  fe_intr_mask;
+} suart_config;
+
+typedef struct {
+	u16 uart_num;
+	u16 uart_type;
+	u16 uart_tx_channel;
+	u16 uart_rx_channel;
+	u16 uart_status;
+} suart_struct_handle, *suart_handle;
+
+typedef struct {
+	void *mcasp_io_addr;
+	void *p_fifo_buff_phys_base;
+	void *p_fifo_buff_virt_base;
+	u32  pru_clk_freq;
+} pruss_suart_iomap;
+
+s16 pru_softuart_init(struct device *dev, u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			u8 *pru_suart_emu_code, u32 fw_size,
+			pruss_suart_iomap *pruss_ioaddr);
+
+s16 pru_softuart_open(suart_handle h_suart);
+
+s16 pru_softuart_close(suart_handle h_uart);
+
+s16 pru_softuart_setbaud(struct device *dev, suart_handle h_uart,
+			u16 tx_clk_divisor, u16 rx_clk_divisor);
+
+s16 pru_softuart_setdatabits(struct device *dev, suart_handle h_uart,
+			u16 tx_data_bits, u16 rx_data_bits);
+
+s16 pru_softuart_setconfig(struct device *dev, suart_handle h_uart,
+			suart_config *config_uart);
+
+s16 pru_softuart_getconfig(struct device *dev, suart_handle h_uart,
+			suart_config *config_uart);
+
+s32 pru_softuart_pending_tx_request(struct device *dev);
+
+s16 pru_softuart_write(struct device *dev, suart_handle h_uart,
+			u32 *pt_tx_data_buf, u16 data_len);
+
+s16 pru_softuart_read(struct device *dev, suart_handle h_uart,
+			u32 *pt_data_buf, u16 data_len);
+
+s32 suart_intr_clrmask(struct device *dev, u16 uart_num, u32 txrxmode,
+			u32 intrmask);
+
+s16 pru_softuart_clr_tx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_tx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_clr_rx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_rx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num,
+			u16 *txrx_flag);
+
+s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num, u32 txrxmode);
+
+s32 suart_intr_getmask(struct device *dev, u16 uart_num, u32 txrxmode,
+			u32 intrmask);
+
+s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+			u32 txrxmode, u32 intrmask);
+
+s16 pru_softuart_get_tx_data_len(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_rx_data_len(struct device *dev, suart_handle h_uart);
+
+s16 suart_arm_to_pru_intr(struct device *dev, u16 uart_num);
+
+s16 arm_to_pru_intr_init(struct device *dev);
+
+s16 pru_softuart_deinit(struct device *dev);
+
+s16 pru_softuart_clr_rx_fifo(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_read_data(struct device *dev, suart_handle h_uart,
+			u8 *p_data_buffer, s32 s32_max_len,
+			u32 *pu32data_read);
+
+s16 pru_softuart_stop_receive(struct device *dev, suart_handle h_uart);
+
+s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
+			u32 txrxmode, s32 s32flag);
+
+void pru_set_fifo_timeout(struct device *dev, s16 timeout);
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_board.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
new file mode 100644
index 0000000..58cc9e4
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: subhasish@mistralsolutions.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.
+ */
+
+#ifndef _OMAPL_SUART_BOARD_H_
+#define _OMAPL_SUART_BOARD_H_
+
+#define PRU_SUART0_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART0_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART0_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART1_CONFIG_DUPLEX	(PRU_SUART_HALF_TX | \
+					PRU_SUART_HALF_RX)
+#define PRU_SUART1_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_7)
+#define PRU_SUART1_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_8)
+
+#define PRU_SUART2_CONFIG_DUPLEX	(PRU_SUART_HALF_TX | \
+					PRU_SUART_HALF_RX)
+#define PRU_SUART2_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_9)
+#define PRU_SUART2_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_10)
+
+#define PRU_SUART3_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART3_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART3_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART4_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART4_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART4_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART5_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART5_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART5_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART6_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART6_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART6_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART7_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART7_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART7_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#endif				/* End of _OMAPL_SUART_BOARD_H_ */
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_err.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
new file mode 100644
index 0000000..dd94f4e
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra@mistralsolutions.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.
+ */
+
+#ifndef _SUART_ERR_H_
+#define _SUART_ERR_H_
+
+#define PRU_SUART_SUCCESS	(0u)
+#define PRU_SUART_FAILURE	(-1)
+
+#define PRU_SUART_ERR_DEVICE_NOT_OPEN	(1u)
+#define PRU_SUART_ERR_UARTS_INIT_FAIL	(2u)
+#define PRU_SUART_ERR_UARTS_RESET_FAIL	(3u)
+#define PRU_SUART_ERR_HANDLE_INVALID	(4u)
+#define PRU_SUART_ERR_PARAMETER_INVALID	(5u)
+
+#define PRU_SUART_ERR_TX		(6u)
+#define PRU_SUART_TX_COMPLETE		(7u)
+#define PRU_SUART_TX_BUSY		(8u)
+#define PRU_SUART_TX_UNDERRUN		(9u)
+
+#define PRU_SUART_ERR_RX		(10u)
+#define PRU_SUART_RX_COMPLETE		(11u)
+#define PRU_SUART_RX_BUSY		(12u)
+#define PRU_SUART_RX_OVERRUN		(13u)
+
+/* API Specific Errors */
+#define SUART_INVALID_TX_BAUD		(14u)
+#define SUART_INVALID_OVERSAMPLING	(15u)
+#define SUART_INVALID_RX_BAUD		(16u)
+
+#define SUART_UART_IN_USE		(17u)
+
+#define SUART_INVALID_CLKDIVISOR	(18u)
+#define SUART_INVALID_UART_NUM		(19u)
+#define SUART_INVALID_SR_NUM		(20u)
+
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
new file mode 100644
index 0000000..fa99c6b
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _OMAPLR_MCASP_H_
+#define _OMAPLR_MCASP_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+
+typedef struct {
+	u32 REVID;
+	u32 RSVD0[3];
+	u32 PFUNC;
+	u32 PDIR;
+	u32 PDOUT;
+	u32 PDIN;
+	u32 PDCLR;
+	u32 RSVD1[8];
+	u32 GBLCTL;
+	u32 AMUTE;
+	u32 DLBCTL;
+	u32 DITCTL;
+	u32 RSVD2[3];
+	u32 RGBLCTL;
+	u32 RMASK;
+	u32 RFMT;
+	u32 AFSRCTL;
+	u32 ACLKRCTL;
+	u32 AHCLKRCTL;
+	u32 RTDM;
+	u32 RINTCTL;
+	u32 RSTAT;
+	u32 RSLOT;
+	u32 RCLKCHK;
+	u32 REVTCTL;
+	u32 RSVD3[4];
+	u32 XGBLCTL;
+	u32 XMASK;
+	u32 XFMT;
+	u32 AFSXCTL;
+	u32 ACLKXCTL;
+	u32 AHCLKXCTL;
+	u32 XTDM;
+	u32 XINTCTL;
+	u32 XSTAT;
+	u32 XSLOT;
+	u32 XCLKCHK;
+	u32 XEVTCTL;
+	u32 RSVD4[12];
+	u32 DITCSRA0;
+	u32 DITCSRA1;
+	u32 DITCSRA2;
+	u32 DITCSRA3;
+	u32 DITCSRA4;
+	u32 DITCSRA5;
+	u32 DITCSRB0;
+	u32 DITCSRB1;
+	u32 DITCSRB2;
+	u32 DITCSRB3;
+	u32 DITCSRB4;
+	u32 DITCSRB5;
+	u32 DITUDRA0;
+	u32 DITUDRA1;
+	u32 DITUDRA2;
+	u32 DITUDRA3;
+	u32 DITUDRA4;
+	u32 DITUDRA5;
+	u32 DITUDRB0;
+	u32 DITUDRB1;
+	u32 DITUDRB2;
+	u32 DITUDRB3;
+	u32 DITUDRB4;
+	u32 DITUDRB5;
+	u32 RSVD5[8];
+	u32 SRCTL0;
+	u32 SRCTL1;
+	u32 SRCTL2;
+	u32 SRCTL3;
+	u32 SRCTL4;
+	u32 SRCTL5;
+	u32 SRCTL6;
+	u32 SRCTL7;
+	u32 SRCTL8;
+	u32 SRCTL9;
+	u32 SRCTL10;
+	u32 SRCTL11;
+	u32 SRCTL12;
+	u32 SRCTL13;
+	u32 SRCTL14;
+	u32 SRCTL15;
+	u32 RSVD6[16];
+	u32 XBUF0;
+	u32 XBUF1;
+	u32 XBUF2;
+	u32 XBUF3;
+	u32 XBUF4;
+	u32 XBUF5;
+	u32 XBUF6;
+	u32 XBUF7;
+	u32 XBUF8;
+	u32 XBUF9;
+	u32 XBUF10;
+	u32 XBUF11;
+	u32 XBUF12;
+	u32 XBUF13;
+	u32 XBUF14;
+	u32 XBUF15;
+	u32 RSVD7[16];
+	u32 RBUF0;
+	u32 RBUF1;
+	u32 RBUF2;
+	u32 RBUF3;
+	u32 RBUF4;
+	u32 RBUF5;
+	u32 RBUF6;
+	u32 RBUF7;
+	u32 RBUF8;
+	u32 RBUF9;
+	u32 RBUF10;
+	u32 RBUF11;
+	u32 RBUF12;
+	u32 RBUF13;
+	u32 RBUF14;
+	u32 RBUF15;
+} omapl_mcasp_regs, *omapl_mcasp_regs_ovly;
+
+
+#define OMAPL_MCASP_PFUNC_AFSR_MASK			(0x80000000u)
+#define OMAPL_MCASP_PFUNC_AFSR_SHIFT			(0x0000001Fu)
+#define OMAPL_MCASP_PFUNC_AFSR_RESETVAL			(0x00000000u)
+/* AFSR Tokens */
+#define OMAPL_MCASP_PFUNC_AFSR_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AFSR_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AHCLKR_MASK			(0x40000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKR_SHIFT			(0x0000001Eu)
+#define OMAPL_MCASP_PFUNC_AHCLKR_RESETVAL		(0x00000000u)
+/* AHCLKR Tokens */
+#define OMAPL_MCASP_PFUNC_AHCLKR_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKR_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_ACLKR_MASK			(0x20000000u)
+#define OMAPL_MCASP_PFUNC_ACLKR_SHIFT			(0x0000001Du)
+#define OMAPL_MCASP_PFUNC_ACLKR_RESETVAL		(0x00000000u)
+/* ACLKR Tokens */
+#define OMAPL_MCASP_PFUNC_ACLKR_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_ACLKR_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AFSX_MASK			(0x10000000u)
+#define OMAPL_MCASP_PFUNC_AFSX_SHIFT			(0x0000001Cu)
+#define OMAPL_MCASP_PFUNC_AFSX_RESETVAL			(0x00000000u)
+/* AFSX Tokens */
+#define OMAPL_MCASP_PFUNC_AFSX_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AFSX_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AHCLKX_MASK			(0x08000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKX_SHIFT			(0x0000001Bu)
+#define OMAPL_MCASP_PFUNC_AHCLKX_RESETVAL		(0x00000000u)
+/* AHCLKX Tokens */
+#define OMAPL_MCASP_PFUNC_AHCLKX_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKX_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_ACLKX_MASK			(0x04000000u)
+#define OMAPL_MCASP_PFUNC_ACLKX_SHIFT			(0x0000001Au)
+#define OMAPL_MCASP_PFUNC_ACLKX_RESETVAL		(0x00000000u)
+/* ACLKX Tokens */
+#define OMAPL_MCASP_PFUNC_ACLKX_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_ACLKX_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AMUTE_MASK			(0x02000000u)
+#define OMAPL_MCASP_PFUNC_AMUTE_SHIFT			(0x00000019u)
+#define OMAPL_MCASP_PFUNC_AMUTE_RESETVAL		(0x00000000u)
+/* AMUTE Tokens */
+#define OMAPL_MCASP_PFUNC_AMUTE_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AMUTE_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR15_MASK			(0x00008000u)
+#define OMAPL_MCASP_PFUNC_AXR15_SHIFT			(0x0000000Fu)
+#define OMAPL_MCASP_PFUNC_AXR15_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR15_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR15_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR14_MASK			(0x00004000u)
+#define OMAPL_MCASP_PFUNC_AXR14_SHIFT			(0x0000000Eu)
+#define OMAPL_MCASP_PFUNC_AXR14_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR14_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR14_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR13_MASK			(0x00002000u)
+#define OMAPL_MCASP_PFUNC_AXR13_SHIFT			(0x0000000Du)
+#define OMAPL_MCASP_PFUNC_AXR13_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR13_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR13_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR12_MASK			(0x00001000u)
+#define OMAPL_MCASP_PFUNC_AXR12_SHIFT			(0x0000000Cu)
+#define OMAPL_MCASP_PFUNC_AXR12_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR12_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR12_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR11_MASK			(0x00000800u)
+#define OMAPL_MCASP_PFUNC_AXR11_SHIFT			(0x0000000Bu)
+#define OMAPL_MCASP_PFUNC_AXR11_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR11_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR11_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR10_MASK			(0x00000400u)
+#define OMAPL_MCASP_PFUNC_AXR10_SHIFT			(0x0000000Au)
+#define OMAPL_MCASP_PFUNC_AXR10_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR10_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR10_GPIO			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_AXR9_MASK			(0x00000200u)
+#define OMAPL_MCASP_PFUNC_AXR9_SHIFT			(0x00000009u)
+#define OMAPL_MCASP_PFUNC_AXR9_RESETVAL			(0x00000000u)
+/* AXR9 Token */
+#define OMAPL_MCASP_PFUNC_AXR9_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR9_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR8_MASK			(0x00000100u)
+#define OMAPL_MCASP_PFUNC_AXR8_SHIFT			(0x00000008u)
+#define OMAPL_MCASP_PFUNC_AXR8_RESETVAL			(0x00000000u)
+/* AXR8 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR8_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR8_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR7_MASK			(0x00000080u)
+#define OMAPL_MCASP_PFUNC_AXR7_SHIFT			(0x00000007u)
+#define OMAPL_MCASP_PFUNC_AXR7_RESETVAL			(0x00000000u)
+/* AXR7 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR7_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR7_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR6_MASK			(0x00000040u)
+#define OMAPL_MCASP_PFUNC_AXR6_SHIFT			(0x00000006u)
+#define OMAPL_MCASP_PFUNC_AXR6_RESETVAL			(0x00000000u)
+/* AXR6 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR6_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR6_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR5_MASK			(0x00000020u)
+#define OMAPL_MCASP_PFUNC_AXR5_SHIFT			(0x00000005u)
+#define OMAPL_MCASP_PFUNC_AXR5_RESETVAL			(0x00000000u)
+/* AXR5 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR5_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR5_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR4_MASK			(0x00000010u)
+#define OMAPL_MCASP_PFUNC_AXR4_SHIFT			(0x00000004u)
+#define OMAPL_MCASP_PFUNC_AXR4_RESETVAL			(0x00000000u)
+/* AXR4 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR4_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR4_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR3_MASK			(0x00000008u)
+#define OMAPL_MCASP_PFUNC_AXR3_SHIFT			(0x00000003u)
+#define OMAPL_MCASP_PFUNC_AXR3_RESETVAL			(0x00000000u)
+/* AXR3 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR3_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR3_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR2_MASK			(0x00000004u)
+#define OMAPL_MCASP_PFUNC_AXR2_SHIFT			(0x00000002u)
+#define OMAPL_MCASP_PFUNC_AXR2_RESETVAL			(0x00000000u)
+/* AXR2 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR2_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR2_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR1_MASK			(0x00000002u)
+#define OMAPL_MCASP_PFUNC_AXR1_SHIFT			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_AXR1_RESETVAL			(0x00000000u)
+/* AXR1 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR1_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR1_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR0_MASK			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_AXR0_SHIFT			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR0_RESETVAL			(0x00000000u)
+/* AXR0 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR0_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR0_GPIO			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_RESETVAL			(0x00000000u)
+
+#define OMAPL_MCASP_PDIR_AFSR_MASK			(0x80000000u)
+#define OMAPL_MCASP_PDIR_AFSR_SHIFT			(0x0000001Fu)
+#define OMAPL_MCASP_PDIR_AFSR_RESETVAL			(0x00000000u)
+/* AFSR Tokens */
+#define OMAPL_MCASP_PDIR_AFSR_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AFSR_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AHCLKR_MASK			(0x40000000u)
+#define OMAPL_MCASP_PDIR_AHCLKR_SHIFT			(0x0000001Eu)
+#define OMAPL_MCASP_PDIR_AHCLKR_RESETVAL		(0x00000000u)
+/* AHCLKR Tokens */
+#define OMAPL_MCASP_PDIR_AHCLKR_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AHCLKR_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_ACLKR_MASK			(0x20000000u)
+#define OMAPL_MCASP_PDIR_ACLKR_SHIFT			(0x0000001Du)
+#define OMAPL_MCASP_PDIR_ACLKR_RESETVAL			(0x00000000u)
+/* ACLKR Tokens */
+#define OMAPL_MCASP_PDIR_ACLKR_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_ACLKR_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AFSX_MASK			(0x10000000u)
+#define OMAPL_MCASP_PDIR_AFSX_SHIFT			(0x0000001Cu)
+#define OMAPL_MCASP_PDIR_AFSX_RESETVAL			(0x00000000u)
+/* AFSX Tokens */
+#define OMAPL_MCASP_PDIR_AFSX_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AFSX_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AHCLKX_MASK			(0x08000000u)
+#define OMAPL_MCASP_PDIR_AHCLKX_SHIFT			(0x0000001Bu)
+#define OMAPL_MCASP_PDIR_AHCLKX_RESETVAL		(0x00000000u)
+/* AHCLKX Tokens */
+#define OMAPL_MCASP_PDIR_AHCLKX_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AHCLKX_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_ACLKX_MASK			(0x04000000u)
+#define OMAPL_MCASP_PDIR_ACLKX_SHIFT			(0x0000001Au)
+#define OMAPL_MCASP_PDIR_ACLKX_RESETVAL			(0x00000000u)
+/* ACLKX Tokens */
+#define OMAPL_MCASP_PDIR_ACLKX_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_ACLKX_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AMUTE_MASK			(0x02000000u)
+#define OMAPL_MCASP_PDIR_AMUTE_SHIFT			(0x00000019u)
+#define OMAPL_MCASP_PDIR_AMUTE_RESETVAL			(0x00000000u)
+/* AMUTE Tokens */
+#define OMAPL_MCASP_PDIR_AMUTE_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AMUTE_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR15_MASK			(0x00008000u)
+#define OMAPL_MCASP_PDIR_AXR15_SHIFT			(0x0000000Fu)
+#define OMAPL_MCASP_PDIR_AXR15_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR15_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR15_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR14_MASK			(0x00004000u)
+#define OMAPL_MCASP_PDIR_AXR14_SHIFT			(0x0000000Eu)
+#define OMAPL_MCASP_PDIR_AXR14_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR14_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR14_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR13_MASK			(0x00002000u)
+#define OMAPL_MCASP_PDIR_AXR13_SHIFT			(0x0000000Du)
+#define OMAPL_MCASP_PDIR_AXR13_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR13_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR13_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR12_MASK			(0x00001000u)
+#define OMAPL_MCASP_PDIR_AXR12_SHIFT			(0x0000000Cu)
+#define OMAPL_MCASP_PDIR_AXR12_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR12_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR12_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR11_MASK			(0x00000800u)
+#define OMAPL_MCASP_PDIR_AXR11_SHIFT			(0x0000000Bu)
+#define OMAPL_MCASP_PDIR_AXR11_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR11_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR11_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR10_MASK			(0x00000400u)
+#define OMAPL_MCASP_PDIR_AXR10_SHIFT			(0x0000000Au)
+#define OMAPL_MCASP_PDIR_AXR10_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR10_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR10_OUTPUT			(0x00000001u)
+#define OMAPL_MCASP_PDIR_AXR9_MASK			(0x00000200u)
+#define OMAPL_MCASP_PDIR_AXR9_SHIFT			(0x00000009u)
+#define OMAPL_MCASP_PDIR_AXR9_RESETVAL			(0x00000000u)
+/* AXR9 Tokens */
+#define OMAPL_MCASP_PDIR_AXR9_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR9_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR8_MASK			(0x00000100u)
+#define OMAPL_MCASP_PDIR_AXR8_SHIFT			(0x00000008u)
+#define OMAPL_MCASP_PDIR_AXR8_RESETVAL			(0x00000000u)
+/* AXR8 Tokens */
+#define OMAPL_MCASP_PDIR_AXR8_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR8_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR7_MASK			(0x00000080u)
+#define OMAPL_MCASP_PDIR_AXR7_SHIFT			(0x00000007u)
+#define OMAPL_MCASP_PDIR_AXR7_RESETVAL			(0x00000000u)
+/*----AXR7 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR7_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR7_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR6_MASK			(0x00000040u)
+#define OMAPL_MCASP_PDIR_AXR6_SHIFT			(0x00000006u)
+#define OMAPL_MCASP_PDIR_AXR6_RESETVAL			(0x00000000u)
+/*----AXR6 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR6_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR6_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR5_MASK			(0x00000020u)
+#define OMAPL_MCASP_PDIR_AXR5_SHIFT			(0x00000005u)
+#define OMAPL_MCASP_PDIR_AXR5_RESETVAL			(0x00000000u)
+/*----AXR5 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR5_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR5_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR4_MASK			(0x00000010u)
+#define OMAPL_MCASP_PDIR_AXR4_SHIFT			(0x00000004u)
+#define OMAPL_MCASP_PDIR_AXR4_RESETVAL			(0x00000000u)
+/*----AXR4 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR4_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR4_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR3_MASK			(0x00000008u)
+#define OMAPL_MCASP_PDIR_AXR3_SHIFT			(0x00000003u)
+#define OMAPL_MCASP_PDIR_AXR3_RESETVAL			(0x00000000u)
+/*----AXR3 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR3_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR3_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR2_MASK			(0x00000004u)
+#define OMAPL_MCASP_PDIR_AXR2_SHIFT			(0x00000002u)
+#define OMAPL_MCASP_PDIR_AXR2_RESETVAL			(0x00000000u)
+/*----AXR2 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR2_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR2_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR1_MASK			(0x00000002u)
+#define OMAPL_MCASP_PDIR_AXR1_SHIFT			(0x00000001u)
+#define OMAPL_MCASP_PDIR_AXR1_RESETVAL			(0x00000000u)
+/*----AXR1 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR1_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR1_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR0_MASK			(0x00000001u)
+#define OMAPL_MCASP_PDIR_AXR0_SHIFT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR0_RESETVAL			(0x00000000u)
+/*----AXR0 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR0_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR0_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_RESETVAL			(0x00000000u)
+
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_MASK			(0x00000080u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_SHIFT		(0x00000007u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_RESETVAL		(0x00000000u)
+/*----CLKXP Tokens----*/
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_RISINGEDGE		(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_FALLINGEDGE		(0x00000001u)
+
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_MASK			(0x00000040u)
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_SHIFT		(0x00000006u)
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_RESETVAL		(0x00000001u)
+/*----ASYNC Tokens----*/
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_SYNC			(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_ASYNC		(0x00000001u)
+
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_MASK			(0x00000020u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_SHIFT		(0x00000005u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_RESETVAL		(0x00000001u)
+/*----CLKXM Tokens----*/
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_EXTERNAL		(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_INTERNAL		(0x00000001u)
+
+#define OMAPL_MCASP_ACLKXCTL_CLKXDIV_MASK		(0x0000001Fu)
+#define OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT		(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXDIV_RESETVAL		(0x00000000u)
+
+#define OMAPL_MCASP_ACLKXCTL_RESETVAL			(0x00000060u)
+
+/* AHCLKXCTL */
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_MASK		(0x00008000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_SHIFT		(0x0000000Fu)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_RESETVAL		(0x00000001u)
+/*----HCLKXM Tokens----*/
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_EXTERNAL		(0x00000000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_INTERNAL		(0x00000001u)
+
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_MASK		(0x00004000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_SHIFT		(0x0000000Eu)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_RESETVAL		(0x00000000u)
+/*----HCLKXP Tokens----*/
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_NOTINVERTED	(0x00000000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_INVERTED		(0x00000001u)
+
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_MASK		(0x00000FFFu)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT		(0x00000000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_RESETVAL		(0x00000000u)
+
+#define OMAPL_MCASP_AHCLKXCTL_RESETVAL			(0x00008000u)
+
+#define MCASP_SUART_GBLCTL				(0X00000000)
+#define MCASP_SUART_RGBLCTL				(0X00000000)
+#define MCASP_SUART_XGBLCTL				(0X00000000)
+#define MCASP_SUART_RMASK_8				(0x000000FF)
+#define MCASP_SUART_RMASK_16				(0x0000FFFF)
+#define MCASP_SUART_RFMT_8				(0x0000A038)
+#define MCASP_SUART_RFMT_16				(0x0000A078)
+#define MCASP_SUART_FSRM				(0X00000002)
+#define MCASP_SUART_CLKRM_CLKRP				(0X000000A0)
+#define MCASP_SUART_HCLKRP				(0X00008000)
+#define MCASP_SUART_RTDMS0				(0X00000001)
+#define MCASP_SUART_RSYNCERR				(0X00000002)
+#define MCASP_SUART_RMAX_RPS_256			(0x00FF0008)
+#define MCASP_SUART_XMASK_0_31				(0X0000FFFF)
+#define MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0		(0x00002078)
+#define MCASP_SUART_FSXM				(0x00000002)
+#define MCASP_SUART_CLKXM_ASYNC_CLKXP			(0x000000E0)
+#define MCASP_SUART_HCLKXM				(0x00008000)
+#define MCASP_SUART_XTDMS0				(0X00000001)
+#define MCASP_SUART_XSYNCERR				(0x00000002)
+#define MCASP_SUART_XMAX_XPS_256			(0x00FF0008)
+#define MCASP_SUART_SRCTL_DISMOD			(0x0000000c)
+#define MCASP_SUART_DIT_DISABLE				(0X00000000)
+#define MCASP_SUART_LOOPBACK_DISABLE			(0x00000000)
+#define MCASP_SUART_AMUTE_DISABLE			(0X00000000)
+#define MCASP_SUART_XSTAT				(0x0000FFFF)
+#define MCASP_SUART_RSTAT				(0x0000FFFF)
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
new file mode 100644
index 0000000..c2aa9d7
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra@mistralsolutions.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.
+ */
+
+#ifndef _SUART_PRU_REGS_H_
+#define _SUART_PRU_REGS_H_
+
+#include <linux/types.h>
+
+/** PRU0 DATA RAM base address */
+#define PRU0_DATARAM_OFFSET		(0x0000u)
+/** PRU1 DATA RAM base address */
+#define PRU1_DATARAM_OFFSET		(0x2000u)
+
+/** PRU0 DATA RAM size */
+#define PRU0_DATARAM_SIZE		(0x200u)
+/** PRU1 DATA RAM size */
+#define PRU1_DATARAM_SIZE		(0x200u)
+
+#define PRU_SUART_PRU0_CH0_OFFSET	(0x0000)
+#define PRU_SUART_PRU0_CH1_OFFSET	(0x0010)
+#define PRU_SUART_PRU0_CH2_OFFSET	(0x0020)
+#define PRU_SUART_PRU0_CH3_OFFSET	(0x0030)
+#define PRU_SUART_PRU0_CH4_OFFSET	(0x0040)
+#define PRU_SUART_PRU0_CH5_OFFSET	(0x0050)
+#define PRU_SUART_PRU0_CH6_OFFSET	(0x0060)
+#define PRU_SUART_PRU0_CH7_OFFSET	(0x0070)
+#define PRU_SUART_PRU0_IMR_OFFSET	(0x0080)
+/** Interrupt Mask Register */
+#define PRU_SUART_PRU0_ISR_OFFSET	(0x0082)
+/** Interrupt Status Register */
+#define PRU_SUART_PRU0_ID_ADDR		(0x0084)
+/** PRU ID Register */
+#define PRU_SUART_PRU0_RX_TX_MODE	(0x0085)
+#define PRU_SUART_PRU0_DELAY_OFFSET	(0x0086)
+#define PRU_SUART_PRU0_IDLE_TIMEOUT_OFFSET	(0x0088)
+
+/* ********* PRU 1 Macros ************* */
+#define PRU_SUART_PRU1_CH0_OFFSET	(0x2000)
+#define PRU_SUART_PRU1_CH1_OFFSET	(0x2010)
+#define PRU_SUART_PRU1_CH2_OFFSET	(0x2020)
+#define PRU_SUART_PRU1_CH3_OFFSET	(0x2030)
+#define PRU_SUART_PRU1_CH4_OFFSET	(0x2040)
+#define PRU_SUART_PRU1_CH5_OFFSET	(0x2050)
+#define PRU_SUART_PRU1_CH6_OFFSET	(0x2060)
+#define PRU_SUART_PRU1_CH7_OFFSET	(0x2070)
+#define PRU_SUART_PRU1_IMR_OFFSET	(0x2080)
+#define PRU_SUART_PRU1_ISR_OFFSET	(0x2082)
+#define PRU_SUART_PRU1_ID_ADDR		(0x2084)
+#define PRU_SUART_PRU1_RX_TX_MODE	(0x2085)
+#define PRU_SUART_PRU1_DELAY_OFFSET	(0x2086)
+#define PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET	(0x2088)
+
+/* SUART Channel Control Register bit descriptions */
+#define PRU_SUART_CH_CTRL_MODE_SHIFT		0x0000
+#define PRU_SUART_CH_CTRL_MODE_MASK		0x0003
+#define PRU_SUART_CH_CTRL_TX_MODE		0x0001
+#define PRU_SUART_CH_CTRL_RX_MODE		0x0002
+
+/* Service Request */
+#define PRU_SUART_CH_CTRL_SREQ_SHIFT		0x0002
+#define PRU_SUART_CH_CTRL_SREQ_MASK		0x0004
+#define PRU_SUART_CH_CTRL_SREQ			0x0001
+
+/* McASP Instance */
+#define PRU_SUART_CH_CTRL_MCASP_SHIFT		0x0003
+#define PRU_SUART_CH_CTRL_MCASP_MASK		0x0018
+#define PRU_SUART_CH_CTRL_SR_SHIFT		0x0008
+#define PRU_SUART_CH_CTRL_SR_MASK		0x0F00
+
+/* SUART channel configuration1 register descriptions */
+
+/* clock divisor -  relative baud value */
+#define PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT	0x0000
+#define PRU_SUART_CH_CONFIG1_DIVISOR_MASK	0x03FF
+/* oversampling */
+#define PRU_SUART_CH_CONFIG1_OVS_SHIFT		0x000A
+#define PRU_SUART_CH_CONFIG1_OVS_MASK		0x0C00
+
+/* SUART channel configuration2 register descriptions */
+/* Bits per character */
+#define PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT	0x0000
+#define PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK	0x000F
+
+/* Bits per character */
+#define PRU_SUART_CH_CONFIG2_DATALEN_SHIFT	0x0008
+#define PRU_SUART_CH_CONFIG2_DATALEN_MASK	0x0F00
+
+/* SUART Channel register offsets */
+#define PRU_SUART_CH_CTRL_OFFSET		0x00
+#define PRU_SUART_CH_CONFIG1_OFFSET		0x02
+#define PRU_SUART_CH_CONFIG2_OFFSET		0x04
+#define PRU_SUART_CH_TXRXSTATUS_OFFSET		0x06
+#define PRU_SUART_CH_TXRXDATA_OFFSET		0x08
+#define PRU_SUART_CH_BYTESDONECNTR_OFFSET	0x0C
+
+/* SUART Event Numbers macros */
+#define PRU_SUART0_TX_EVT	34
+#define PRU_SUART0_RX_EVT	35
+#define PRU_SUART1_TX_EVT	36
+#define PRU_SUART1_RX_EVT	37
+#define PRU_SUART2_TX_EVT	38
+#define PRU_SUART2_RX_EVT	39
+#define PRU_SUART3_TX_EVT	40
+#define PRU_SUART3_RX_EVT	41
+#define PRU_SUART4_TX_EVT	42
+#define PRU_SUART4_RX_EVT	43
+#define PRU_SUART5_TX_EVT	44
+#define PRU_SUART5_RX_EVT	45
+#define PRU_SUART6_TX_EVT	46
+#define PRU_SUART6_RX_EVT	47
+#define PRU_SUART7_TX_EVT	48
+#define PRU_SUART7_RX_EVT	49
+
+#define PRU_SUART0_TX_EVT_BIT	BIT(2)
+#define PRU_SUART0_RX_EVT_BIT	BIT(3)
+#define PRU_SUART1_TX_EVT_BIT	BIT(4)
+#define PRU_SUART1_RX_EVT_BIT	BIT(5)
+#define PRU_SUART2_TX_EVT_BIT	BIT(6)
+#define PRU_SUART2_RX_EVT_BIT	BIT(7)
+#define PRU_SUART3_TX_EVT_BIT	BIT(8)
+#define PRU_SUART3_RX_EVT_BIT	BIT(9)
+#define PRU_SUART4_TX_EVT_BIT	BIT(10)
+#define PRU_SUART4_RX_EVT_BIT	BIT(11)
+#define PRU_SUART5_TX_EVT_BIT	BIT(12)
+#define PRU_SUART5_RX_EVT_BIT	BIT(13)
+#define PRU_SUART6_TX_EVT_BIT	BIT(14)
+#define PRU_SUART6_RX_EVT_BIT	BIT(15)
+#define PRU_SUART7_TX_EVT_BIT	BIT(16)
+#define PRU_SUART7_RX_EVT_BIT	BIT(17)
+
+/*
+ *  SUART Config regs
+ */
+typedef struct {
+	u16 chn_ctrl;
+	u16 chn_config1;
+	u16 chn_config2;
+	u16 chn_txrx_status;
+	u32 chn_txrx_data;
+} suart_struct_pru_regs;
+
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
new file mode 100644
index 0000000..7ced423
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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/mfd/pruss/da8xx_pru.h>
+#include "pruss_suart_mcasp.h"
+#include "pruss_suart_api.h"
+#include "pruss_suart_regs.h"
+#include "pruss_suart_board.h"
+#include "pruss_suart_utils.h"
+#include "pruss_suart_err.h"
+
+
+#define SUART_TRX_DIV_CONF_SZ	4
+
+static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+			pruss_suart_iomap *pruss_ioaddr);
+static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value, u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr);
+
+/*
+ * Lookup table for TX baud rate
+ * The divisor value is calculated using the formula
+ *
+ * ACLKX = (AUXCLK)/(CLKXDIV * HCLKXDIV)
+ *
+ * Where
+ *		CLKXDIV takes values from 1-32
+ *		HCLKXDIV takes values from 1-4096
+ * Here
+ *		AUXCLK = 24MHz
+ */
+u32 lt_tx_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+	/*BaudRate,	Divisor,	CLKXDIV,HCLKXDIV */
+	{300,		80000,		24,		3200},
+	{600,		40000,		15,		2500},
+	{1800,		13333,		10,		1212},
+	{2400,		10000,		4,		2000},
+	{4800,		5000,		1,		2500},
+	{7200,		3333,		0,		3333},
+	{9600,		2500,		0,		2500},
+	{14400,		1666,		0,		1666},
+	{19200,		1250,		0,		1250},
+	{38400,		625,		0,		625},
+	{57600,		416,		0,		416},
+	{115200,	208,		0,		208},
+	{230400,	104,		0,		104}
+};
+
+/*
+ * Lookup table for RX baud rate for 8 bit oversampling
+ * The divisor value is calculated using the formula
+ *
+ *	ACLKR = (AUXCLK)/(CLKRDIV * HCLKRDIV) * Oversampling
+ *
+ * Where
+ *		CLKRDIV takes values from 1-32
+ *		HCLKRDIV takes values from 1-4096
+ * Here
+ *		AUXCLK = 24MHz
+ */
+u32 lt_rx_8x_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+/* BaudRate,	Divisor,	CLKXDIV,	HCLKXDIV */
+	{300,		10000,		4,		2000},
+	{600,		5000,		1,		2500},
+	{1800,		1667,		0,		1667},
+	{2400,		1250,		0,		1250},
+	{7200,		417,		0,		417},
+	{4800,		625,		0,		625},
+	{9600,		312,		0,		312},
+	{14400,		208,		0,		208},
+	{19200,		156,		0,		156},
+	{38400,		78,		0,		78},
+	{57600,		52,		0,		52},
+	{115200,	26,		0,		26},
+	{230400,	13,		0,		13}
+};
+
+/*
+ * Lookup table for RX baud rate for 16 bit oversampling
+ * The divisor value is calculated using the formula
+ *
+ *	ACLKR = (AUXCLK)/(CLKRDIV * HCLKRDIV) * Oversampling
+ *
+ * Where
+ *		CLKRDIV takes values from 1-32
+ *		HCLKRDIV takes values from 1-4096
+ * Here
+ *		AUXCLK = 24MHz
+ */
+u32 lt_rx_16x_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+/*BaudRate,	Divisor,	CLKXDIV,	HCLKXDIV */
+	{300,		5000,		1,		2500},
+	{600,		2500,		0,		2500},
+	{1800,		833,		0,		833},
+	{2400,		625,		0,		625},
+	{4800,		312,		0,		312},
+	{7200,		208,		0,		208},
+	{9600,		156,		0,		156},
+	{14400,		104,		0,		104},
+	{19200,		78,		0,		78},
+	{38400,		39,		0,		39},
+	{57600,		26,		0,		26},
+	{115200,	13,		0,		13},
+	{230400,	6,		0,		6}
+};
+
+/*
+ * McASP configuration routine
+ */
+void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value,
+			u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr)
+{
+	omapl_mcasp_regs_ovly mcasp0_regs =
+		(omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	/* reset mcasp */
+	__raw_writel(MCASP_SUART_GBLCTL, &mcasp0_regs->GBLCTL);
+	__raw_writel(MCASP_SUART_RGBLCTL, &mcasp0_regs->RGBLCTL);
+	__raw_writel(MCASP_SUART_XGBLCTL, &mcasp0_regs->XGBLCTL);
+
+	/* configure receive registers */
+	if ((SUART_8X_OVRSMPL == oversampling) || (0 == oversampling)) {
+		__raw_writel(MCASP_SUART_RMASK_8, &mcasp0_regs->RMASK);
+		__raw_writel(MCASP_SUART_RFMT_8, &mcasp0_regs->RFMT);
+	}
+	if (SUART_16X_OVRSMPL == oversampling) {
+		__raw_writel(MCASP_SUART_RMASK_16, &mcasp0_regs->RMASK);
+		__raw_writel(MCASP_SUART_RFMT_16, &mcasp0_regs->RFMT);
+
+	}
+
+	__raw_writel(MCASP_SUART_FSRM, &mcasp0_regs->AFSRCTL);
+	__raw_writel(MCASP_SUART_CLKRM_CLKRP, &mcasp0_regs->ACLKRCTL);
+	__raw_writel(MCASP_SUART_HCLKRP, &mcasp0_regs->AHCLKRCTL);
+	suart_mcasp_rx_baud_set(rx_baud_value, oversampling, pruss_ioaddr);
+	__raw_writel(MCASP_SUART_RTDMS0, &mcasp0_regs->RTDM);
+	__raw_writel(MCASP_SUART_RSYNCERR, &mcasp0_regs->RINTCTL);
+	__raw_writel(MCASP_SUART_RMAX_RPS_256, &mcasp0_regs->RCLKCHK);
+
+	/* configure transmit registers. */
+	__raw_writel(MCASP_SUART_XMASK_0_31, &mcasp0_regs->XMASK);
+	__raw_writel(MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0, &mcasp0_regs->XFMT);
+	__raw_writel(MCASP_SUART_FSXM, &mcasp0_regs->AFSXCTL);
+	__raw_writel(MCASP_SUART_CLKXM_ASYNC_CLKXP, &mcasp0_regs->ACLKXCTL);
+	__raw_writel(MCASP_SUART_HCLKXM, &mcasp0_regs->AHCLKXCTL);
+
+	suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
+	__raw_writel(MCASP_SUART_XTDMS0, &mcasp0_regs->XTDM);
+	__raw_writel(MCASP_SUART_XSYNCERR, &mcasp0_regs->XINTCTL);
+	__raw_writel(MCASP_SUART_XMAX_XPS_256, &mcasp0_regs->XCLKCHK);
+
+	/* Serializer as a transmitter */
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL0);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL1);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL2);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL3);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL4);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL5);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL6);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL7);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL8);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL9);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL10);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL11);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL12);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL13);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL14);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL15);
+
+	/* Configure all AXR[n] as McASP pins  */
+
+	/*
+	 *  Setting  all TX MCASP AXR[n] Pin mapped to Even Serializer number
+	 *  (0,2,4,6,8,10,12,14) to GPIO Mode by default. During setting the
+	 *  serializer to TX mode in PRU assembly code, the MCASP AXR[n] Pin
+	 *  would get configured to MCASP mode of operation,
+	 *  before Actual Data Transfer
+	 */
+
+	/* Setting  all TX Pin to GPIO Mode by default */
+	temp_reg = (OMAPL_MCASP_PFUNC_RESETVAL) |
+	    (1 << PRU_SUART0_CONFIG_TX_SER) | (1 << PRU_SUART1_CONFIG_TX_SER) |
+	    (1 << PRU_SUART2_CONFIG_TX_SER) | (1 << PRU_SUART3_CONFIG_TX_SER) |
+	    (1 << PRU_SUART4_CONFIG_TX_SER) | (1 << PRU_SUART5_CONFIG_TX_SER) |
+	    (1 << PRU_SUART6_CONFIG_TX_SER) | (1 << PRU_SUART7_CONFIG_TX_SER);
+	__raw_writel(temp_reg, &mcasp0_regs->PFUNC);
+
+	__raw_writel(0xFFF, &mcasp0_regs->PDOUT);
+
+	/* config pin function and direction */
+	__raw_writel(0x00000000, &mcasp0_regs->PDIR);
+	temp_reg =
+	    (1 << PRU_SUART0_CONFIG_TX_SER) | (1 << PRU_SUART1_CONFIG_TX_SER) |
+	    (1 << PRU_SUART2_CONFIG_TX_SER) | (1 << PRU_SUART3_CONFIG_TX_SER) |
+	    (1 << PRU_SUART4_CONFIG_TX_SER) | (1 << PRU_SUART5_CONFIG_TX_SER) |
+	    (1 << PRU_SUART6_CONFIG_TX_SER) | (1 << PRU_SUART7_CONFIG_TX_SER) |
+	    (MCASP_PDIR_VAL);
+	__raw_writel(temp_reg, &mcasp0_regs->PDIR);
+
+	__raw_writel(MCASP_SUART_DIT_DISABLE, &mcasp0_regs->DITCTL);
+	__raw_writel(MCASP_SUART_LOOPBACK_DISABLE, &mcasp0_regs->DLBCTL);
+	__raw_writel(MCASP_SUART_AMUTE_DISABLE, &mcasp0_regs->AMUTE);
+
+	__raw_writel(MCASP_SUART_XSTAT, &mcasp0_regs->XSTAT);
+	__raw_writel(MCASP_SUART_RSTAT, &mcasp0_regs->RSTAT);
+}
+
+void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+		pruss_suart_iomap *pruss_ioaddr)
+{
+	omapl_mcasp_regs_ovly mcasp0_regs =
+	    (omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+	temp_reg = mcasp0_regs->PFUNC | (0x1 << serializer_num);
+	__raw_writel(temp_reg, &mcasp0_regs->PFUNC);
+}
+
+/*
+ * mcasp TX buard rate setting routine
+ */
+s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+		pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val;
+	u32 loop_cnt;
+	s16 status = SUART_SUCCESS;
+	s16 found_val = SUART_FALSE;
+
+	omapl_mcasp_regs_ovly mcasp0_regs =
+	    (omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	/* Search the supported baud rate in the table */
+	for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+							loop_cnt++) {
+		if (tx_baud_value == lt_tx_baud_rate[loop_cnt][0]) {
+			found_val = SUART_TRUE;
+			break;
+		}
+	}
+	if (found_val == SUART_TRUE) {
+		clk_div_val = lt_tx_baud_rate[loop_cnt][2];
+		temp_reg = mcasp0_regs->ACLKXCTL |
+			clk_div_val << OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT;
+		__raw_writel(temp_reg, &mcasp0_regs->ACLKXCTL);
+		clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+		temp_reg = mcasp0_regs->AHCLKXCTL |
+			clk_div_val << OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT;
+		__raw_writel(temp_reg, &mcasp0_regs->AHCLKXCTL);
+	} else {
+		return SUART_INVALID_TX_BAUD;
+	}
+	return status;
+}
+
+/*
+ * mcasp RX buard rate setting routine
+ */
+s16 suart_mcasp_rx_baud_set(u32 rx_baud_value,
+	u32 oversampling, pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val;
+	u32 loop_cnt;
+	s16 status = SUART_SUCCESS;
+	s16 found_val = SUART_FALSE;
+
+	omapl_mcasp_regs_ovly mcasp0_regs =
+	    (omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	if (oversampling == SUART_8X_OVRSMPL) {
+		for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+		     loop_cnt++) {
+			if (rx_baud_value == lt_rx_8x_baud_rate[loop_cnt][0]) {
+				clk_div_val = lt_rx_8x_baud_rate[loop_cnt][2];
+				temp_reg = mcasp0_regs->ACLKRCTL | (clk_div_val
+					<< OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+
+				__raw_writel(temp_reg, &mcasp0_regs->ACLKRCTL);
+
+				clk_div_val =
+				lt_rx_8x_baud_rate[loop_cnt][3] - 1;
+
+				temp_reg = mcasp0_regs->AHCLKRCTL | (clk_div_val
+				<< OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+
+				__raw_writel(temp_reg, &mcasp0_regs->AHCLKRCTL);
+
+				found_val = SUART_TRUE;
+				break;
+			}
+		}
+	} else if (oversampling == SUART_16X_OVRSMPL) {
+		for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+		     loop_cnt++) {
+			if (rx_baud_value == lt_rx_16x_baud_rate[loop_cnt][0]) {
+				clk_div_val = lt_rx_16x_baud_rate[loop_cnt][2];
+				temp_reg =
+					mcasp0_regs->ACLKRCTL | (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->ACLKRCTL);
+				clk_div_val = lt_rx_16x_baud_rate[loop_cnt][3];
+				temp_reg =
+				mcasp0_regs->AHCLKRCTL | (clk_div_val <<
+				OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->AHCLKRCTL);
+				found_val = SUART_TRUE;
+				break;
+			}
+		}
+	} else if (oversampling == 0) {
+		for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+		     loop_cnt++) {
+			if (rx_baud_value == lt_tx_baud_rate[loop_cnt][0]) {
+				clk_div_val = lt_tx_baud_rate[loop_cnt][2];
+				temp_reg =
+				mcasp0_regs->ACLKRCTL | (clk_div_val <<
+				OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->ACLKRCTL);
+				clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+				temp_reg =
+				mcasp0_regs->AHCLKRCTL | (clk_div_val <<
+				OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->AHCLKRCTL);
+				found_val = SUART_TRUE;
+				break;
+			}
+		}
+	} else {
+		return SUART_INVALID_OVERSAMPLING;
+	}
+
+	if (found_val != SUART_TRUE)
+		return SUART_INVALID_RX_BAUD;
+
+	return status;
+}
+
+/*
+ * mcasp buard rate setting routine
+ */
+s16 suart_asp_baud_set(u32 tx_baud_value, u32 rx_baud_value, u32 oversampling,
+					pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = SUART_SUCCESS;
+
+	status = suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
+	status = suart_mcasp_rx_baud_set(rx_baud_value, oversampling,
+					pruss_ioaddr);
+
+	return status;
+}
+
+/*
+ * mcasp deactivate the selected serializer
+ */
+s16 suart_asp_serializer_deactivate(u16 u16sr_num,
+		pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = SUART_SUCCESS;
+	omapl_mcasp_regs_ovly mcasp0_regs = (omapl_mcasp_regs_ovly)
+				pruss_ioaddr->mcasp_io_addr;
+	if (u16sr_num > 15)
+		status = SUART_INVALID_SR_NUM;
+	else
+		__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL0);
+
+	return status;
+}
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
new file mode 100644
index 0000000..7839eb6
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra@mistralsolutions.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.
+ */
+
+#ifndef _SUART_UTILS_H_
+#define _SUART_UTILS_H_
+
+#include <linux/types.h>
+
+/* ************ Serializers ***************** */
+#define PRU_SUART_SERIALIZER_0		(0u)
+#define PRU_SUART_SERIALIZER_1		(1u)
+#define PRU_SUART_SERIALIZER_2		(2u)
+#define PRU_SUART_SERIALIZER_3		(3u)
+#define PRU_SUART_SERIALIZER_4		(4u)
+#define PRU_SUART_SERIALIZER_5		(5u)
+#define PRU_SUART_SERIALIZER_6		(6u)
+#define PRU_SUART_SERIALIZER_7		(7u)
+#define PRU_SUART_SERIALIZER_8		(8u)
+#define PRU_SUART_SERIALIZER_9		(9u)
+#define PRU_SUART_SERIALIZER_10		(10u)
+#define PRU_SUART_SERIALIZER_11		(11u)
+#define PRU_SUART_SERIALIZER_12		(12u)
+#define PRU_SUART_SERIALIZER_13		(13u)
+#define PRU_SUART_SERIALIZER_14		(14u)
+#define PRU_SUART_SERIALIZER_15		(15u)
+#define PRU_SUART_SERIALIZER_NONE	(16u)
+
+/* Total number of baud rates supported */
+#define SUART_NUM_OF_BAUDS_SUPPORTED	13
+
+#define MCASP_PDIR_VAL ( \
+	OMAPL_MCASP_PDIR_AFSR_OUTPUT<<OMAPL_MCASP_PDIR_AFSR_SHIFT | \
+	OMAPL_MCASP_PDIR_AHCLKR_OUTPUT<<OMAPL_MCASP_PDIR_AHCLKR_SHIFT | \
+	OMAPL_MCASP_PDIR_ACLKR_OUTPUT<<OMAPL_MCASP_PDIR_ACLKR_SHIFT | \
+	OMAPL_MCASP_PDIR_AFSX_OUTPUT<<OMAPL_MCASP_PDIR_AFSX_SHIFT | \
+	OMAPL_MCASP_PDIR_AHCLKX_OUTPUT<<OMAPL_MCASP_PDIR_AHCLKX_SHIFT | \
+	OMAPL_MCASP_PDIR_ACLKX_OUTPUT<<OMAPL_MCASP_PDIR_ACLKX_SHIFT)
+
+extern void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_baud_set(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_serializer_deactivate(u16 u16sr_num,
+			pruss_suart_iomap *pruss_ioaddr);
+
+extern void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+			pruss_suart_iomap *pruss_ioaddr);
+#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 758c5b0..eae37fe 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -202,6 +202,8 @@
 /* VIA VT8500 SoC */
 #define PORT_VT8500	97
 
+#define PORT_DA8XX_PRU_SUART	98
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
-- 
1.7.2.3


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-11 14:51   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-11 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds support for the TTY compliant
Soft-UART device emulated on PRUSS.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/tty/serial/Kconfig                         |    2 +
 drivers/tty/serial/Makefile                        |    1 +
 drivers/tty/serial/da8xx_pruss/Kconfig             |   19 +
 drivers/tty/serial/da8xx_pruss/Makefile            |    9 +
 drivers/tty/serial/da8xx_pruss/pruss_suart.c       | 1014 +++++++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c   | 2350 ++++++++++++++++++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h   |  345 +++
 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h |   58 +
 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h   |   48 +
 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h |  526 +++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h  |  153 ++
 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c |  384 ++++
 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h |   63 +
 include/linux/serial_core.h                        |    2 +
 14 files changed, 4974 insertions(+), 0 deletions(-)
 create mode 100644 drivers/tty/serial/da8xx_pruss/Kconfig
 create mode 100644 drivers/tty/serial/da8xx_pruss/Makefile
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
 create mode 100644 drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index b1682d7..68c40c2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1595,4 +1595,6 @@ config SERIAL_PCH_UART
 	  This driver is for PCH(Platform controller Hub) UART of Intel EG20T
 	  which is an IOH(Input/Output Hub) for x86 embedded processor.
 	  Enabling PCH_DMA, this PCH UART works as DMA mode.
+
+source "drivers/tty/serial/da8xx_pruss/Kconfig"
 endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 8ea92e9..51c89e9 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,3 +92,4 @@ obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
 obj-$(CONFIG_SERIAL_IFX6X60)  	+= ifx6x60.o
 obj-$(CONFIG_SERIAL_PCH_UART)	+= pch_uart.o
+obj-$(CONFIG_SERIAL_PRUSS_SUART)	+= da8xx_pruss/
diff --git a/drivers/tty/serial/da8xx_pruss/Kconfig b/drivers/tty/serial/da8xx_pruss/Kconfig
new file mode 100644
index 0000000..23ac53f
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/Kconfig
@@ -0,0 +1,19 @@
+#
+# SUART Kernel Configuration
+#
+
+config SERIAL_PRUSS_SUART
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	select SERIAL_CORE
+	tristate "PRUSS based SoftUART emulation on DA8XX"
+	---help---
+	Enable this to emulate a UART controller on the PRUSS of DA8XX.
+	If not sure, mark N
+
+config PRUSS_SUART_MCASP
+    int "McASP number"
+    depends on ARCH_DAVINCI && ARCH_DAVINCI_DA830 && SERIAL_PRUSS_SUART
+    default "0"
+    ---help---
+    Enter the McASP number to use with SUART (0, 1 or 2).
+	You will need to recompile the kernel if this is changed.
diff --git a/drivers/tty/serial/da8xx_pruss/Makefile b/drivers/tty/serial/da8xx_pruss/Makefile
new file mode 100644
index 0000000..34a5b1f
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for SoftUART emulation
+#
+
+suart_emu-objs :=       pruss_suart.o \
+                        pruss_suart_api.o \
+                        pruss_suart_utils.o
+
+obj-$(CONFIG_SERIAL_PRUSS_SUART)        += suart_emu.o
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart.c b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
new file mode 100644
index 0000000..d222e2e
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -0,0 +1,1014 @@
+/*
+ * PRUSS SUART Emulation device driver
+ * Author: subhasish at mistralsolutions.com
+ *
+ * This driver supports TI's PRU SUART 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/module.h>
+#include <mach/da8xx.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <mach/sram.h>
+#include "pruss_suart_board.h"
+#include "pruss_suart_api.h"
+#include "pruss_suart_utils.h"
+#include "pruss_suart_err.h"
+
+#define NR_SUART			8
+#define DRV_NAME			"da8xx_pruss_uart"
+#define DRV_DESC			"PRUSS SUART Driver v1.0"
+#define MAX_SUART_RETRIES		100
+#define SUART_CNTX_SZ			512
+#define SUART_FIFO_TIMEOUT_DFLT		5
+#define SUART_FIFO_TIMEOUT_MIN		4
+#define SUART_FIFO_TIMEOUT_MAX		500
+
+#ifdef __SUART_DEBUG
+#define __suart_debug(fmt, args...) \
+		printk(KERN_DEBUG "suart_debug: " fmt, ## args)
+#else
+#define __suart_debug(fmt, args...)
+#endif
+
+#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## args)
+
+/* Default timeout set to 5ms */
+static s16 suart_timeout = SUART_FIFO_TIMEOUT_DFLT;
+module_param(suart_timeout, short, S_IRUGO);
+MODULE_PARM_DESC(suart_timeout,
+		 "fifo timeout in milli seconds (min: 4; max: 500)");
+
+struct suart_fifo {
+	void *fifo_vaddr_buff_tx;
+	void *fifo_vaddr_buff_rx;
+	void *fifo_phys_addr_tx;
+	void *fifo_phys_addr_rx;
+};
+
+struct omapl_pru_suart {
+	struct uart_port port[NR_SUART];
+	struct device *dev; /* pdev->dev */
+	struct semaphore port_sem[NR_SUART];
+	struct clk *clk_mcasp;
+	struct suart_fifo suart_fifo_addr[NR_SUART];
+	const struct firmware *fw;
+	suart_struct_handle suart_hdl[NR_SUART];
+	pruss_suart_iomap suart_iomap;
+	u32 clk_freq_pru;
+	u32 clk_freq_mcasp;
+	u32 tx_loadsz;
+};
+
+static u32 suart_get_duplex(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	return soft_uart->suart_hdl[uart_no].uart_type;
+}
+
+static inline void __stop_tx(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct device *dev = soft_uart->dev;
+	u16 txready;
+	u32 i;
+
+	/* Check if any TX in progress */
+	for (i = 0, txready = 1; (i < 10000) && txready; i++) {
+		txready = (pru_softuart_get_tx_status
+			(dev, &soft_uart->suart_hdl[uart_no]) &
+				CHN_TXRX_STATUS_RDY);
+	}
+	/* To stop tx, disable the TX interrupt */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[uart_no].uart_num,
+				PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl[uart_no]);
+}
+
+static void pruss_suart_stop_tx(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	__stop_tx(soft_uart, port->line);
+}
+
+static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
+	struct device *dev = soft_uart->dev;
+	s32 count = 0;
+
+	if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
+		return;
+
+	if (down_trylock(&soft_uart->port_sem[uart_no]))
+		return;
+
+	if (uart_circ_empty(xmit) ||
+			uart_tx_stopped(&soft_uart->port[uart_no])) {
+		pruss_suart_stop_tx(&soft_uart->port[uart_no]);
+		up(&soft_uart->port_sem[uart_no]);
+		return;
+	}
+
+	for (count = 0; count <= soft_uart->tx_loadsz; count++) {
+		*((s8 *)soft_uart->suart_fifo_addr[uart_no].fifo_vaddr_buff_tx
+		+ count) = xmit->buf[xmit->tail];
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		soft_uart->port[uart_no].icount.tx++;
+		if (uart_circ_empty(xmit)) {
+			uart_circ_clear(xmit);
+			break;
+		}
+	}
+
+	if (count == (SUART_FIFO_LEN + 1))
+		count = SUART_FIFO_LEN;
+
+	/* Write the character to the data port */
+	if (SUART_SUCCESS != pru_softuart_write(dev,
+		&soft_uart->suart_hdl[uart_no],
+			(u32 *)&soft_uart->suart_fifo_addr
+				[uart_no].fifo_phys_addr_tx, count)) {
+		__suart_err("failed to tx data\n");
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&soft_uart->port[uart_no]);
+
+#if 0
+	if (uart_circ_empty(xmit))
+		__stop_tx(soft_uart, uart_no);
+#endif
+}
+
+static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct tty_struct *tty = soft_uart->port[uart_no].state->port.tty;
+	struct device *dev = soft_uart->dev;
+	s8 flags = TTY_NORMAL;
+	u16 rx_status, data_len = SUART_FIFO_LEN;
+	u32 data_len_read;
+	u8 suart_data[SUART_FIFO_LEN + 1];
+	s32 i = 0;
+
+	if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
+		return;
+	/* read the status */
+	rx_status = pru_softuart_get_rx_status(dev,
+			&soft_uart->suart_hdl[uart_no]);
+
+	/* check for errors */
+	if (rx_status & CHN_TXRX_STATUS_ERR) {
+		if (rx_status & CHN_TXRX_STATUS_FE)
+			soft_uart->port[uart_no].icount.frame++;
+		if (rx_status & CHN_TXRX_STATUS_OVRNERR)
+			soft_uart->port[uart_no].icount.overrun++;
+		if (rx_status & CHN_TXRX_STATUS_BI)
+			soft_uart->port[uart_no].icount.brk++;
+		rx_status &= soft_uart->port[uart_no].read_status_mask;
+		if (rx_status & CHN_TXRX_STATUS_FE)
+			flags = TTY_FRAME;
+		if (rx_status & CHN_TXRX_STATUS_OVRNERR)
+			flags = TTY_OVERRUN;
+		if (rx_status & CHN_TXRX_STATUS_BI)
+			flags = TTY_BREAK;
+
+#ifdef SUPPORT_SYSRQ
+		soft_uart->port[uart_no].sysrq = 0;
+#endif
+	} else {
+		pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
+				       suart_data, data_len + 1,
+				       &data_len_read);
+
+		for (i = 0; i <= data_len_read; i++) {
+			soft_uart->port[uart_no].icount.rx++;
+			/* check for sys rq */
+			if (uart_handle_sysrq_char
+			    (&soft_uart->port[uart_no], suart_data))
+				continue;
+		}
+		/* update the tty data structure */
+		tty_insert_flip_string(tty, suart_data, data_len_read);
+	}
+
+	/* push data into tty */
+	pru_softuart_clr_rx_status(dev, &soft_uart->suart_hdl[uart_no]);
+	spin_unlock(&soft_uart->port[uart_no].lock);
+	tty_flip_buffer_push(tty);
+	spin_lock(&soft_uart->port[uart_no].lock);
+}
+
+static irqreturn_t pruss_suart_interrupt(s32 irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	u16 txrx_flag;
+	u32 ret;
+	unsigned long flags = 0;
+	u16 uart_num = port->line + 1;
+
+	spin_lock_irqsave(&soft_uart->port[port->line].lock, flags);
+	do {
+		ret = pru_softuart_get_isrstatus(dev, uart_num, &txrx_flag);
+		if (PRU_SUART_SUCCESS != ret) {
+			__suart_err("suart%d: failed to get interrupt, ret:"
+				" 0x%X txrx_flag 0x%X\n",
+				port->line, ret, txrx_flag);
+			spin_unlock_irqrestore(&soft_uart->
+				port[port->line].lock, flags);
+			return IRQ_NONE;
+		}
+		if ((PRU_RX_INTR & txrx_flag) == PRU_RX_INTR) {
+			pru_intr_clr_isrstatus(dev, uart_num, PRU_RX_INTR);
+			if ((soft_uart->port[port->line].ignore_status_mask &
+				CHN_TXRX_STATUS_RDY) == CHN_TXRX_STATUS_RDY) {
+				pru_softuart_clr_rx_status(dev,
+					&soft_uart->suart_hdl
+				[port->line]);
+			} else {
+				omapl_pru_rx_chars(soft_uart, port->line);
+			}
+		}
+
+		if ((PRU_TX_INTR & txrx_flag) == PRU_TX_INTR) {
+			pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
+			pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl
+						 [port->line]);
+			up(&soft_uart->port_sem[port->line]);
+			omapl_pru_tx_chars(soft_uart, port->line);
+		}
+	} while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
+
+	spin_unlock_irqrestore(&soft_uart->port[port->line].lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void pruss_suart_stop_rx(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	/* disable rx interrupt */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+}
+
+static void pruss_suart_enable_ms(struct uart_port *port)
+{
+	__suart_err("modem control timer not supported\n");
+}
+
+static void pruss_suart_start_tx(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	/* unmask the tx interrupts */
+
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	omapl_pru_tx_chars(soft_uart, port->line);
+}
+
+static u32 pruss_suart_tx_empty(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+
+	return (pru_softuart_get_tx_status(dev,
+		&soft_uart->suart_hdl[port->line])
+		& CHN_TXRX_STATUS_RDY) ? 0 : TIOCSER_TEMT;
+}
+
+static u32 pruss_suart_get_mctrl(struct uart_port *port)
+{
+	return -ENOTSUPP;
+}
+
+static void pruss_suart_set_mctrl(struct uart_port *port, u32 mctrl)
+{
+	__suart_debug("modem control not supported\n");
+}
+
+static void pruss_suart_break_ctl(struct uart_port *port, s32 break_state)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (break_state == -1)
+		suart_intr_clrmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+	else
+		suart_intr_setmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void pruss_suart_set_termios(struct uart_port *port,
+				  struct ktermios *termios,
+				  struct ktermios *old)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	u8 cval = 0;
+	unsigned long flags = 0;
+	u32 baud = 0;
+	u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+/*
+ * Do not allow unsupported configurations to be set
+ */
+	if (1) {
+		termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
+				      | PARENB | PARODD | CMSPAR);
+		termios->c_cflag |= CLOCAL;
+	}
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS6:
+		cval = ePRU_SUART_DATA_BITS6;
+		break;
+	case CS7:
+		cval = ePRU_SUART_DATA_BITS7;
+		break;
+	default:
+	case CS8:
+		cval = ePRU_SUART_DATA_BITS8;
+		break;
+	}
+	/*
+	 * We do not support CS5.
+	 */
+	if ((termios->c_cflag & CSIZE) == CS5) {
+		termios->c_cflag &= ~CSIZE;
+		termios->c_cflag |= old_csize;
+	}
+	if (SUART_SUCCESS != pru_softuart_setdatabits
+		(dev, &soft_uart->suart_hdl[port->line], cval, cval))
+		__suart_err("failed to set data bits to: %d\n", cval);
+
+/*
+ * Ask the core to calculate the divisor for us.
+ */
+	baud = uart_get_baud_rate(port, termios, old,
+			  port->uartclk / 16 / 0xffff,
+			  port->uartclk / 16);
+
+/*
+ * Ok, we're now changing the port state.  Do it with
+ * interrupts disabled.
+ */
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Set the baud */
+	if (SUART_SUCCESS !=
+	    pru_softuart_setbaud(dev, &soft_uart->suart_hdl[port->line],
+				 SUART_DEFAULT_BAUD / baud,
+				 SUART_DEFAULT_BAUD / baud))
+		__suart_err("failed to set baud to: %d\n", baud);
+
+/*
+ * update port->read_config_mask and port->ignore_config_mask
+ * to indicate the events we are interested in receiving
+ */
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, SUART_GBL_INTR_ERR_MASK);
+	port->read_status_mask = 0;
+	if (termios->c_iflag & INPCK) {	/* Input parity check not supported,
+					just enabled FE */
+		port->read_status_mask |= CHN_TXRX_STATUS_FE;
+		suart_intr_setmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_FE);
+	}
+	if (termios->c_iflag & (BRKINT | PARMRK)) {
+		port->read_status_mask |= CHN_TXRX_STATUS_BI;
+		suart_intr_setmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+	}
+/*
+ * Characteres to ignore
+ */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= CHN_TXRX_STATUS_BI;
+		/*
+		 * If we're ignoring break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR) {
+			port->ignore_status_mask |=
+			    (CHN_TXRX_STATUS_OVRNERR | CHN_TXRX_STATUS_FE);
+			/*
+			 * Overrun in case of RX
+			 * Underrun in case of TX
+			 */
+			suart_intr_clrmask(dev, soft_uart->
+					   suart_hdl[port->line].uart_num,
+					   PRU_RX_INTR, CHN_TXRX_IE_MASK_FE);
+		}
+		suart_intr_clrmask(dev,
+			soft_uart->suart_hdl[port->line].uart_num,
+			PRU_RX_INTR, CHN_TXRX_IE_MASK_BI);
+	}
+/*
+ * ignore all characters if CREAD is not set
+ */
+	if ((termios->c_cflag & CREAD) == 0) {
+		port->ignore_status_mask |= CHN_TXRX_STATUS_RDY;
+		pruss_suart_stop_rx(port);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+/*
+ *	Grab any interrupt resources and initialise any low level driver
+ *	state.  Enable the port for reception.  It should not activate
+ *	RTS nor DTR; this will be done via a separate call to set_mctrl.
+ *
+ *	This method will only be called when the port is initially opened.
+ *
+ *	Locking: port_sem taken.
+ *	Interrupts: globally disabled.
+ */
+static s32 pruss_suart_startup(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	s32 retval;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+
+	retval = request_irq(port->irq, pruss_suart_interrupt,
+			     port->irqflags, "suart_irq", port);
+	if (retval) {
+		free_irq(port->irq, port); /* should we free this if err */
+		goto out;
+	}
+	/*
+	 * enable interrupts from this port
+	 */
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, SUART_GBL_INTR_ERR_MASK);
+
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+
+	if ((suart_get_duplex(soft_uart, port->line) & ePRU_SUART_HALF_TX)
+	    == ePRU_SUART_HALF_TX) {
+		suart_pru_to_host_intr_enable(dev, soft_uart->
+			suart_hdl[port->line].uart_num, PRU_TX_INTR, true);
+	}
+	/* Seed RX if port is half-rx or full-duplex */
+	if ((suart_get_duplex(soft_uart, port->line) & ePRU_SUART_HALF_RX)
+		== ePRU_SUART_HALF_RX) {
+		suart_pru_to_host_intr_enable(dev, soft_uart->
+			suart_hdl[port->line].uart_num, PRU_RX_INTR, true);
+		pru_softuart_read(dev, &soft_uart->suart_hdl[port->line],
+			(u32 *)&soft_uart->suart_fifo_addr[port->line].
+			fifo_phys_addr_rx, SUART_FIFO_LEN);
+	}
+out:
+	return retval;
+}
+
+/*
+ * Disable the port, disable any break condition that may be in
+ * effect, and free any interrupt resources.  It should not disable
+ * RTS nor DTR; this will have already been done via a separate
+ * call to set_mctrl.
+ *
+ * Drivers must not access port->info once this call has completed.
+ *
+ * This method will only be called when there are no more users of
+ * this port.
+ *
+ * Locking: port_sem taken.
+ * Interrupts: caller dependent.
+ */
+
+static void pruss_suart_shutdown(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	/* Disable BI and FE intr */
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	suart_intr_clrmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_RX_INTR, CHN_TXRX_IE_MASK_BI
+			   | CHN_TXRX_IE_MASK_FE | CHN_TXRX_IE_MASK_CMPLT
+			   | CHN_TXRX_IE_MASK_TIMEOUT);
+
+	/* free interrupts */
+	free_irq(port->irq, port);
+}
+
+/*
+ * Return a pointer to a string constant describing the specified
+ * port, or return NULL, in which case the string 'unknown' is
+ * substituted.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static const char *pruss_suart_type(struct uart_port *port)
+{
+	return "suart_tty";
+}
+
+/*
+ * Release any memory and IO region resources currently in use by
+ * the port.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static void pruss_suart_release_port(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct platform_device *pdev = to_platform_device(port->dev);
+
+	if (0 != pru_softuart_close(&soft_uart->suart_hdl[port->line]))
+		dev_err(&pdev->dev, "failed to close suart\n");
+
+	return;
+}
+
+/*
+ * Request any memory and IO region resources required by the port.
+ * If any fail, no resources should be registered when this function
+ * returns, and it should return -EBUSY on failure.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ *
+ * We need to d/l the f/w in probe and since this api
+ * is called per uart, the request_mem_region should
+ * be called in probe itself.
+ */
+static s32 pruss_suart_request_port(struct uart_port *port)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct device *dev = soft_uart->dev;
+	suart_config pru_suart_config;
+	s16 timeout = 0;
+	u32 err = 0;
+
+	if (soft_uart == NULL) {
+		__suart_err("soft_uart ptr failed\n");
+		return -ENODEV;
+	}
+	err = pru_softuart_open(&soft_uart->suart_hdl[port->line]);
+	if (PRU_SUART_SUCCESS != err) {
+		dev_err(&pdev->dev, "failed to open suart: %d\n", err);
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* set fifo /timeout */
+	if (SUART_FIFO_TIMEOUT_MIN > suart_timeout) {
+		__suart_err("fifo timeout less than %d ms not supported\n",
+			    SUART_FIFO_TIMEOUT_MIN);
+		suart_timeout = SUART_FIFO_TIMEOUT_MIN;
+	} else if (SUART_FIFO_TIMEOUT_MAX < suart_timeout) {
+		__suart_err("fifo timeout more than %d ms not supported\n",
+			    SUART_FIFO_TIMEOUT_MAX);
+		suart_timeout = SUART_FIFO_TIMEOUT_MAX;
+	}
+
+	/* This is only for x8 */
+	timeout = (SUART_DEFAULT_BAUD * suart_timeout) / 1000;
+	pru_set_fifo_timeout(dev, timeout);
+
+	if (soft_uart->suart_hdl[port->line].uart_num == PRU_SUART_UART1) {
+		pru_suart_config.tx_serializer = PRU_SUART0_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART0_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART2) {
+		pru_suart_config.tx_serializer = PRU_SUART1_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART1_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART3) {
+		pru_suart_config.tx_serializer = PRU_SUART2_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART2_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART4) {
+		pru_suart_config.tx_serializer = PRU_SUART3_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART3_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART5) {
+		pru_suart_config.tx_serializer = PRU_SUART4_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART4_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART6) {
+		pru_suart_config.tx_serializer = PRU_SUART5_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART5_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART7) {
+		pru_suart_config.tx_serializer = PRU_SUART6_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART6_CONFIG_RX_SER;
+	} else if (soft_uart->suart_hdl[port->line].uart_num ==
+							PRU_SUART_UART8) {
+		pru_suart_config.tx_serializer = PRU_SUART7_CONFIG_TX_SER;
+		pru_suart_config.rx_serializer = PRU_SUART7_CONFIG_RX_SER;
+	} else {
+		return -ENOTSUPP;
+	}
+
+	/* Some defaults to startup. reconfigured by terimos later */
+	pru_suart_config.tx_clk_divisor = 1;
+	pru_suart_config.rx_clk_divisor = 1;
+	pru_suart_config.tx_bits_per_char = ePRU_SUART_DATA_BITS8;
+	pru_suart_config.rx_bits_per_char = ePRU_SUART_DATA_BITS8;
+	pru_suart_config.oversampling = SUART_DEFAULT_OVRSMPL;
+
+	if (PRU_SUART_SUCCESS !=
+		pru_softuart_setconfig(dev, &soft_uart->suart_hdl[port->line],
+			&pru_suart_config)) {
+		dev_err(&pdev->dev,
+			"pru_softuart_setconfig: failed to set config: %X\n",
+			err);
+	}
+exit:
+	return err;
+}
+
+/*
+ * Perform any autoconfiguration steps required for the port.  `flag`
+ * contains a bit mask of the required configuration.  UART_CONFIG_TYPE
+ * indicates that the port requires detection and identification.
+ * port->type should be set to the type found, or PORT_UNKNOWN if
+ * no port was detected.
+ *
+ * UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
+ * which should be probed using standard kernel autoprobing techniques.
+ * This is not necessary on platforms where ports have interrupts
+ * internally hard wired (eg, system on a chip implementations).
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+
+static void pruss_suart_config_port(struct uart_port *port, s32 flags)
+{
+	if (flags & UART_CONFIG_TYPE && pruss_suart_request_port(port) == 0)
+		port->type = PORT_DA8XX_PRU_SUART;
+}
+
+/*
+ * Verify the new serial port information contained within serinfo is
+ * suitable for this port type.
+ *
+ * Locking: none.
+ * Interrupts: caller dependent.
+ */
+static s32 pruss_suart_verify_port(struct uart_port *port,
+				 struct serial_struct *ser)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	s32 ret = 0;
+
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_DA8XX_PRU_SUART)
+		ret = -EINVAL;
+	if (soft_uart->port[port->line].irq != ser->irq)
+		ret = -EINVAL;
+	if (ser->io_type != UPIO_MEM)
+		ret = -EINVAL;
+	if (soft_uart->port[port->line].uartclk / 16 != ser->baud_base)
+		ret = -EINVAL;
+	if ((void *)soft_uart->port[port->line].mapbase != ser->iomem_base)
+		ret = -EINVAL;
+	if (soft_uart->port[port->line].iobase != ser->port)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops pruss_suart_ops = {
+	.tx_empty	= pruss_suart_tx_empty,
+	.set_mctrl	= pruss_suart_set_mctrl,
+	.get_mctrl	= pruss_suart_get_mctrl,
+	.stop_tx	= pruss_suart_stop_tx,
+	.start_tx	= pruss_suart_start_tx,
+	.stop_rx	= pruss_suart_stop_rx,
+	.enable_ms	= pruss_suart_enable_ms,
+	.break_ctl	= pruss_suart_break_ctl,
+	.startup	= pruss_suart_startup,
+	.shutdown	= pruss_suart_shutdown,
+	.set_termios	= pruss_suart_set_termios,
+	.type		= pruss_suart_type,
+	.release_port	= pruss_suart_release_port,
+	.request_port	= pruss_suart_request_port,
+	.config_port	= pruss_suart_config_port,
+	.verify_port	= pruss_suart_verify_port,
+};
+
+static struct uart_driver pruss_suart_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRV_NAME,
+	.dev_name	= "ttySU",
+	.major		= 0,
+	.minor		= 16,
+	.nr		= NR_SUART,
+};
+
+static s32 __devinit pruss_suart_probe(struct platform_device *pdev)
+{
+	struct omapl_pru_suart *soft_uart;
+	const struct da850_evm_pruss_suart_data *pdata;
+	struct device *dev = &pdev->dev;
+	s32 err, i;
+	u8 *fw_data = NULL;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not found\n");
+		return -EINVAL;
+	}
+
+	soft_uart = kzalloc(sizeof(struct omapl_pru_suart), GFP_KERNEL);
+	if (!soft_uart)
+		return -ENOMEM;
+
+	if (!request_mem_region(pdata->resource.start,
+			resource_size(&pdata->resource),
+			dev_name(&pdev->dev))) {
+		dev_err(&pdev->dev, "mcasp memory region already claimed!\n");
+		err = -EBUSY;
+		goto probe_exit;
+	}
+
+	soft_uart->suart_iomap.mcasp_io_addr =
+			ioremap(pdata->resource.start,
+			resource_size(&pdata->resource));
+	if (!soft_uart->suart_iomap.mcasp_io_addr) {
+		dev_err(&pdev->dev, "mcasp ioremap failed\n");
+		err = -EFAULT;
+		goto probe_exit_1;
+	}
+
+	soft_uart->suart_iomap.p_fifo_buff_virt_base =
+	sram_alloc(SUART_CNTX_SZ * NR_SUART * 2,
+	(dma_addr_t *) &soft_uart->suart_iomap.p_fifo_buff_phys_base);
+	if (!soft_uart->suart_iomap.p_fifo_buff_virt_base)
+		goto probe_exit_iounmap;
+
+	soft_uart->clk_freq_pru = pruss_get_clk_freq(dev);
+
+	soft_uart->clk_mcasp = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(soft_uart->clk_mcasp)) {
+		dev_err(&pdev->dev, "no clock available: mcasp\n");
+		err = -ENODEV;
+		soft_uart->clk_mcasp = NULL;
+		goto probe_exit_sram_free;
+	}
+
+	soft_uart->clk_freq_mcasp = clk_get_rate(soft_uart->clk_mcasp);
+	clk_enable(soft_uart->clk_mcasp);
+
+	err = request_firmware(&soft_uart->fw, "PRU_SUART_Emulation.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 size %td. downloading...\n",
+		soft_uart->fw->size);
+
+	/* download firmware into pru  & init */
+	fw_data = kmalloc(soft_uart->fw->size, GFP_KERNEL);
+	memcpy((void *)fw_data, (const void *)soft_uart->fw->data,
+		soft_uart->fw->size);
+
+	soft_uart->suart_iomap.pru_clk_freq =
+		(soft_uart->clk_freq_pru / 1000000);
+
+	err = pru_softuart_init(dev, SUART_DEFAULT_BAUD, SUART_DEFAULT_BAUD,
+			SUART_DEFAULT_OVRSMPL, fw_data,
+			soft_uart->fw->size, &soft_uart->suart_iomap);
+	if (err) {
+		dev_err(&pdev->dev, "pruss init error\n");
+		err = -ENODEV;
+		kfree((const void *)fw_data);
+		goto probe_release_fw;
+	}
+	kfree((const void *)fw_data);
+
+	platform_set_drvdata(pdev, &soft_uart->port[0]);
+	soft_uart->dev = dev;
+
+	for (i = 0; i < NR_SUART; i++) {
+		soft_uart->port[i].ops = &pruss_suart_ops;
+		soft_uart->port[i].iotype = UPIO_MEM;
+		soft_uart->port[i].flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+		soft_uart->port[i].mapbase =
+			(u32)soft_uart->suart_iomap.p_fifo_buff_virt_base;
+		soft_uart->port[i].membase =
+			(u8 *)&soft_uart->suart_iomap;
+		soft_uart->port[i].type = PORT_DA8XX_PRU_SUART;
+		soft_uart->port[i].irq =
+			platform_get_irq(to_platform_device(dev->parent), i);
+		soft_uart->port[i].dev = &pdev->dev;
+		soft_uart->port[i].irqflags = IRQF_SHARED;
+		soft_uart->port[i].uartclk = soft_uart->clk_freq_mcasp;
+		soft_uart->port[i].fifosize = SUART_FIFO_LEN;
+		soft_uart->tx_loadsz = SUART_FIFO_LEN;
+		soft_uart->port[i].custom_divisor = 1;
+		soft_uart->port[i].line = i;
+		soft_uart->suart_hdl[i].uart_num = i + 1;
+		spin_lock_init(&soft_uart->port[i].lock);
+		soft_uart->port[i].serial_in = NULL;
+
+		soft_uart->suart_fifo_addr[i].fifo_vaddr_buff_tx =
+		soft_uart->suart_iomap.p_fifo_buff_virt_base +
+		(2 * SUART_CNTX_SZ * i);
+
+		soft_uart->suart_fifo_addr[i].fifo_vaddr_buff_rx =
+		soft_uart->suart_iomap.p_fifo_buff_virt_base +
+		((2 * SUART_CNTX_SZ * i) + SUART_CNTX_SZ);
+
+		soft_uart->suart_fifo_addr[i].fifo_phys_addr_tx =
+		soft_uart->suart_iomap.p_fifo_buff_phys_base +
+		(2 * SUART_CNTX_SZ * i);
+
+		soft_uart->suart_fifo_addr[i].fifo_phys_addr_rx =
+		soft_uart->suart_iomap.p_fifo_buff_phys_base +
+		((2 * SUART_CNTX_SZ * i) + SUART_CNTX_SZ);
+
+		soft_uart->port[i].serial_out = NULL;
+		uart_add_one_port(&pruss_suart_reg, &soft_uart->port[i]);
+		sema_init(&soft_uart->port_sem[i], 1);
+	}
+
+	dev_info(&pdev->dev,
+		"%s device registered (pru_clk=%d, asp_clk=%d)\n",
+		DRV_NAME, soft_uart->clk_freq_pru, soft_uart->clk_freq_mcasp);
+
+	return 0;
+
+probe_release_fw:
+	release_firmware(soft_uart->fw);
+probe_exit_clk:
+	clk_put(soft_uart->clk_mcasp);
+	clk_disable(soft_uart->clk_mcasp);
+probe_exit_sram_free:
+	sram_free(soft_uart->suart_iomap.p_fifo_buff_virt_base,
+	SUART_CNTX_SZ * NR_SUART * 2);
+probe_exit_iounmap:
+	iounmap(soft_uart->suart_iomap.mcasp_io_addr);
+probe_exit_1:
+	release_mem_region(pdata->resource.start,
+		resource_size(&pdata->resource));
+probe_exit:
+	kfree(soft_uart);
+	return err;
+}
+
+static s32 __devexit pruss_suart_remove(struct platform_device *pdev)
+{
+	struct omapl_pru_suart *soft_uart = platform_get_drvdata(pdev);
+	const struct da850_evm_pruss_suart_data *pdata;
+	struct device *dev = &pdev->dev;
+	int i;
+
+	pdata = dev->platform_data;
+	if (!pdata)
+		dev_err(&pdev->dev, "platform data not found\n");
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (soft_uart) {
+		for (i = 0; i < NR_SUART; i++) {
+			uart_remove_one_port(&pruss_suart_reg,
+			&soft_uart->port[i]);
+		}
+	}
+
+	sram_free(soft_uart->suart_iomap.p_fifo_buff_virt_base,
+		SUART_CNTX_SZ * NR_SUART * 2);
+	release_firmware(soft_uart->fw);
+	clk_put(soft_uart->clk_mcasp);
+	clk_disable(soft_uart->clk_mcasp);
+	iounmap(soft_uart->suart_iomap.mcasp_io_addr);
+	if (pdata) {
+		release_mem_region(pdata->resource.start,
+			resource_size(&pdata->resource));
+	}
+	kfree(soft_uart);
+	return 0;
+}
+
+#define pruss_suart_suspend NULL
+#define pruss_suart_resume NULL
+
+static struct platform_driver serial_pruss_driver = {
+	.probe		= pruss_suart_probe,
+	.remove		= __devexit_p(pruss_suart_remove),
+	.suspend	= pruss_suart_suspend,
+	.resume		= pruss_suart_resume,
+	.driver		= {
+			.name	= DRV_NAME,
+			.owner	= THIS_MODULE,
+	},
+};
+
+static s32 __init pruss_suart_init(void)
+{
+	s32 ret;
+
+	pruss_suart_reg.nr = NR_SUART;
+	ret = uart_register_driver(&pruss_suart_reg);
+	if (ret)
+		return ret;
+	ret = platform_driver_register(&serial_pruss_driver);
+	if (ret)
+		goto out;
+
+	__suart_debug("SUART serial driver loaded\n");
+	return ret;
+out:
+	uart_unregister_driver(&pruss_suart_reg);
+	return ret;
+}
+
+module_init(pruss_suart_init);
+
+static void __exit pruss_suart_exit(void)
+{
+	platform_driver_unregister(&serial_pruss_driver);
+	uart_unregister_driver(&pruss_suart_reg);
+	__suart_debug("SUART serial driver unloaded\n");
+}
+
+module_exit(pruss_suart_exit);
+
+/* Module information */
+MODULE_AUTHOR("Subhasish Ghosh <subhasish@mistralsolutions.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
new file mode 100644
index 0000000..d809dd3
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
@@ -0,0 +1,2350 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include "pruss_suart_api.h"
+#include "pruss_suart_regs.h"
+#include "pruss_suart_board.h"
+#include "pruss_suart_utils.h"
+#include "pruss_suart_err.h"
+
+static u8 g_uart_statu_table[8];
+static pruss_suart_iomap suart_iomap;
+
+static u32 uart_rx[8] = {PRU_SUART0_CONFIG_RX_SER, PRU_SUART1_CONFIG_RX_SER,
+			PRU_SUART2_CONFIG_RX_SER, PRU_SUART3_CONFIG_RX_SER,
+			PRU_SUART4_CONFIG_RX_SER, PRU_SUART5_CONFIG_RX_SER,
+			PRU_SUART6_CONFIG_RX_SER, PRU_SUART7_CONFIG_RX_SER};
+
+static u32 uart_tx[8] = {PRU_SUART0_CONFIG_TX_SER, PRU_SUART1_CONFIG_TX_SER,
+			PRU_SUART2_CONFIG_TX_SER, PRU_SUART3_CONFIG_TX_SER,
+			PRU_SUART4_CONFIG_TX_SER, PRU_SUART5_CONFIG_TX_SER,
+			PRU_SUART6_CONFIG_TX_SER, PRU_SUART7_CONFIG_TX_SER};
+
+static u32 uart_config[8] = {PRU_SUART0_CONFIG_DUPLEX, PRU_SUART1_CONFIG_DUPLEX,
+			PRU_SUART2_CONFIG_DUPLEX, PRU_SUART3_CONFIG_DUPLEX,
+			PRU_SUART4_CONFIG_DUPLEX, PRU_SUART5_CONFIG_DUPLEX,
+			PRU_SUART6_CONFIG_DUPLEX, PRU_SUART7_CONFIG_DUPLEX};
+
+#if (PRU_ACTIVE == BOTH_PRU)
+#if 1
+void pru_set_ram_data(struct device *dev, pruss_suart_iomap *pruss_ioaddr)
+{
+	u16 u16datatowrite;
+	u32 u32datatowrite;
+	u32 i;
+	pru_suart_regs_ovly pru_suart_regs = PRU0_DATARAM_OFFSET;
+	u32 *pu32_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
+	pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+
+	/* RX PRU - 0 Chanel 0-7 context information */
+	for (i = 0; i < 8; i++, pru_suart_regs++) {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_RX << 0);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= ((0xF & uart_rx[i]) << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+					PRU_SUART_HALF_RX_DISABLED) {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15) ;
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+		} else {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_ENABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		__raw_writel(MCASP_SRCTL_RX_MODE, pu32_sr_ctl_addr +
+								uart_rx[i]);
+		}
+		/*
+		* RX is active by default, write the dummy received data at
+		* PRU RAM addr 0x1FC to avoid memory corruption.
+		*/
+		pruss_readl(dev, (u32) &pru_suart_regs->ch_txrx_data,
+							&u32datatowrite, 1);
+		u32datatowrite |= RX_DEFAULT_DATA_DUMP_ADDR;
+		pruss_writel(dev, (u32) &pru_suart_regs->ch_txrx_data,
+							&u32datatowrite, 1);
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite = 0;
+		pruss_writel(dev, (u32) &pru_suart_regs->reserved1,
+							&u32datatowrite, 1);
+		/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+				(PRU0_DATARAM_OFFSET + (0x090 + (i * 0x020)));
+		u32datatowrite = (MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
+				&u32datatowrite, 1);
+		u32datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+				&u32datatowrite, 1);
+	}
+
+	/* ****************** PRU1 RAM BASE ADDR ************************ */
+	pru_suart_regs = (pru_suart_regs_ovly) PRU1_DATARAM_OFFSET;
+
+	/* ******************* TX PRU - 1  *********************** */
+	/* Channel 0-7 context information */
+	for (i = 0; i < 8; i++, pru_suart_regs++) {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_TX << 0);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (0xF & uart_tx[i] << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+						&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+						&u16datatowrite, 1);
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED) {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+		} else {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+						&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_ENABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		__raw_writel(MCASP_SRCTL_TX_MODE,
+				pu32_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite |= 1;
+		pruss_writel(dev, (u32) &pru_suart_regs->reserved1,
+							 &u32datatowrite, 1);
+	/* SUART1 TX context base addr */
+		 pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+			(PRU1_DATARAM_OFFSET + (0x0B0 + (i * 0x02C)));
+		u32datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
+				&u32datatowrite, 1);
+		u32datatowrite = (MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+				&u32datatowrite, 1);
+	/* SUART1 TX formatted data base addr */
+		u32datatowrite = (0x0090 + (i * 0x002C));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+					&u32datatowrite, 1);
+	}
+}
+#endif
+#else
+void pru_set_ram_data(struct device *dev, pruss_suart_iomap *pruss_ioaddr)
+{
+
+	pru_suart_regs_ovly pru_suart_regs = (pru_suart_regs_ovly)
+						pruss_ioaddr->pru_io_addr;
+	u32 i;
+	u32 *pu32_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
+	pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+
+	/* ***************** UART 0  ************************ */
+	/* Channel 0 context information is Tx */
+	for (i = 0; i < 4; i++, pru_suart_regs++) {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_TX << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (0xF & uart_tx[i]);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED){
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		} else {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_ENABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			__raw_writel(MCASP_SRCTL_TX_MODE,
+						pu32_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite |= 1;
+		pruss_writel(dev, (u32) &pru_suart_regs->reserved1,
+							&u32datatowrite, 1);
+	/* SUART1 TX context base addr */
+		 pru_suart_tx_priv = (pru_suart_tx_cntx_priv *)
+				(PRU0_DATARAM_OFFSET + (0x0B0 + (i * 0x50)));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
+				(MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2)), 1);
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+				(MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2)), 1);
+	/* SUART1 TX formatted data base addr */
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+					(0x0090 + (i * 0x050)), 1);
+
+	/* Channel 1 is Rx context information */
+		pru_suart_regs++;
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_RX << 8);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+						&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_ctrl, &u16datatowrite, 1);
+		u16datatowrite |= (0xF & uart_rx[i]);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_ctrl,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		u16datatowrite |= (SUART_DEFAULT_OVRSMPL << 10);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config1,
+							&u16datatowrite, 1);
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		u16datatowrite |= 8;
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_config2,
+							&u16datatowrite, 1);
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+						PRU_SUART_HALF_RX_DISABLED) {
+			pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+			u16datatowrite |= (SUART_CHN_DISABLED << 15);
+			pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		} else {
+		pruss_readw(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		u16datatowrite |= (SUART_CHN_ENABLED << 15);
+		pruss_writew(dev, (u32) &pru_suart_regs->ch_txrx_status,
+							&u16datatowrite, 1);
+		__raw_writel(MCASP_SRCTL_RX_MODE,
+					pu32_sr_ctl_addr + uart_rx[i]);
+		}
+	/* RX is active by default, write the dummy received data
+	 * at PRU RAM addr 0x1FC to avoid memory corruption
+	 */
+		pruss_readl(dev, (u32) &pru_surt_regs->ch_txrx_data,
+						&u32datatowrite, 1);
+		u32datatowrite |= RX_DEFAULT_DATA_DUMP_ADDR;
+		pruss_writel(dev, (u32) &pru_suart_regs->ch_txrx_data,
+							&u32datatowrite, 1);
+		pruss_readl(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+		u32datatowrite = 0;
+	pruss_writel(dev, (u32) &pru_suart_regs->reserved1, &u32datatowrite, 1);
+	/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (pru_suart_rx_cntx_priv *)
+			(PRU0_DATARAM_OFFSET + (0x0C0 + (i * 0x50)));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
+				(MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2)), 1);
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+				(MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2)), 1);
+	}
+}
+#endif
+
+static void pru_set_rx_tx_mode(struct device *dev, u32 pru_mode, u32 pru_num)
+{
+
+	u32 pru_offset;
+
+	if (pru_num == PRUSS_NUM0)
+		pru_offset = PRU_SUART_PRU0_RX_TX_MODE;
+	else if (pru_num == PRUSS_NUM1)
+		pru_offset = PRU_SUART_PRU1_RX_TX_MODE;
+	else
+		return;
+	pruss_writeb(dev, pru_offset, (u8 *) &pru_mode, 1);
+}
+
+static void pru_set_delay_count(struct device *dev, u32 pru_freq)
+{
+	u32 u32delay_cnt;
+
+	if (pru_freq == 228)
+		u32delay_cnt = 5;
+	else if (pru_freq == 186)
+		u32delay_cnt = 5;
+	else
+		u32delay_cnt = 3;
+
+	/* PRU 0 */
+	pruss_writeb(dev, PRU_SUART_PRU0_DELAY_OFFSET,
+		(u8 *) &u32delay_cnt, 1);
+
+	/* PRU 1 */
+	pruss_writeb(dev, PRU_SUART_PRU1_DELAY_OFFSET,
+		(u8 *) &u32delay_cnt, 1);
+}
+
+static s32 suart_set_pru_id(struct device *dev, u32 pru_no)
+{
+	u32 offset;
+	u8 reg_val = 0;
+
+	if (0 == pru_no)
+		offset = PRU_SUART_PRU0_ID_ADDR;
+	else if (1 == pru_no)
+		offset = PRU_SUART_PRU1_ID_ADDR;
+	else
+		return PRU_SUART_FAILURE;
+
+	reg_val = pru_no;
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 1);
+
+	return PRU_SUART_SUCCESS;
+}
+
+/*
+ * suart Initialization routine
+ */
+s16 pru_softuart_init(struct device *dev, u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			u8 *pru_suart_emu_code, u32 fw_size,
+			pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 u32datatowrite[128] = {0};
+	s16 status = PRU_SUART_SUCCESS;
+	s16 idx;
+	s16 retval;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) &&
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH))
+		return PRU_SUART_FAILURE;
+
+	suart_iomap.mcasp_io_addr = pruss_ioaddr->mcasp_io_addr;
+	suart_iomap.p_fifo_buff_phys_base =
+					pruss_ioaddr->p_fifo_buff_phys_base;
+	suart_iomap.p_fifo_buff_virt_base =
+					pruss_ioaddr->p_fifo_buff_virt_base;
+	suart_iomap.pru_clk_freq = pruss_ioaddr->pru_clk_freq;
+	/* Configure McASP0  */
+	suart_mcasp_config(tx_baud_value,
+			rx_baud_value, oversampling, pruss_ioaddr);
+	pruss_enable(dev, PRUSS_NUM0);
+	pruss_enable(dev, PRUSS_NUM1);
+
+	/* Reset PRU RAM */
+	pruss_writel(dev, PRU0_DATARAM_OFFSET, u32datatowrite,
+				 (PRU0_DATARAM_SIZE / sizeof(int)));
+	pruss_writel(dev, PRU1_DATARAM_OFFSET, u32datatowrite,
+				 (PRU1_DATARAM_SIZE / sizeof(int)));
+	pruss_load(dev, PRUSS_NUM0, (u32 *)pru_suart_emu_code,
+				(fw_size / sizeof(u32)));
+	pruss_load(dev, PRUSS_NUM1, (u32 *)pru_suart_emu_code,
+				(fw_size / sizeof(u32)));
+	retval = arm_to_pru_intr_init(dev);
+	if (-1 == retval)
+		return status;
+	pru_set_delay_count(dev, pruss_ioaddr->pru_clk_freq);
+	suart_set_pru_id(dev, PRUSS_NUM0);
+	suart_set_pru_id(dev, PRUSS_NUM1);
+	pru_set_rx_tx_mode(dev, PRU0_MODE, PRUSS_NUM0);
+	pru_set_rx_tx_mode(dev, PRU1_MODE, PRUSS_NUM1);
+	pru_set_ram_data(dev, pruss_ioaddr);
+	pruss_run(dev, PRUSS_NUM0);
+	pruss_run(dev, PRUSS_NUM1);
+
+	/* Initialize g_uart_statu_table */
+	for (idx = 0; idx < 8; idx++)
+		g_uart_statu_table[idx] = ePRU_SUART_UART_FREE;
+
+	return status;
+}
+
+void pru_set_fifo_timeout(struct device *dev, s16 timeout)
+{
+	pruss_writew(dev, PRU_SUART_PRU0_IDLE_TIMEOUT_OFFSET,
+		&timeout, 1);
+	pruss_writew(dev, PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET,
+		&timeout, 1);
+}
+
+s16 pru_softuart_deinit(struct device *dev)
+{
+	u32 offset;
+	s16 s16retval = 0;
+	u32 u32value = 0;
+
+	offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+	u32value = 0xFFFFFFFF;
+	s16retval = pruss_writel(dev, offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+	offset = (u32) (PRUSS_INTC_STATCLRINT0 & 0xFFFF);
+	u32value = 0xFFFFFFFF;
+	s16retval = pruss_writel(dev, offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+	pruss_disable(dev, 0);
+	pruss_disable(dev, 1);
+
+	return PRU_SUART_SUCCESS;
+}
+
+/* suart Instance open routine  */
+s16 pru_softuart_open(suart_handle h_suart)
+{
+	s16 status = PRU_SUART_SUCCESS;
+
+	switch (h_suart->uart_num) {
+	case PRU_SUART_UART1:
+		if (g_uart_statu_table[PRU_SUART_UART1 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART0_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART0_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART0_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART1 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART2:
+		if (g_uart_statu_table[PRU_SUART_UART2 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART1_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART1_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART1_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART2 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART3:
+		if (g_uart_statu_table[PRU_SUART_UART3 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART2_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART2_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART2_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART3 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART4:
+		if (g_uart_statu_table[PRU_SUART_UART4 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART3_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART3_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART3_CONFIG_RX_SER;
+
+			g_uart_statu_table[PRU_SUART_UART4 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART5:
+		if (g_uart_statu_table[PRU_SUART_UART5 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART4_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART4_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART4_CONFIG_RX_SER;
+
+			g_uart_statu_table[PRU_SUART_UART5 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART6:
+		if (g_uart_statu_table[PRU_SUART_UART6 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART5_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART5_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART5_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART6 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART7:
+		if (g_uart_statu_table[PRU_SUART_UART7 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART6_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART6_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART6_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART7 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	case PRU_SUART_UART8:
+		if (g_uart_statu_table[PRU_SUART_UART8 - 1] ==
+				ePRU_SUART_UART_IN_USE) {
+			status = SUART_UART_IN_USE;
+			return status;
+		} else {
+			h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+			h_suart->uart_type = PRU_SUART7_CONFIG_DUPLEX;
+			h_suart->uart_tx_channel = PRU_SUART7_CONFIG_TX_SER;
+			h_suart->uart_rx_channel = PRU_SUART7_CONFIG_RX_SER;
+			g_uart_statu_table[PRU_SUART_UART8 - 1] =
+			    ePRU_SUART_UART_IN_USE;
+		}
+		break;
+
+	default:
+		status = SUART_INVALID_UART_NUM;
+		break;
+	}
+	return status;
+}
+
+/* suart instance close routine */
+s16 pru_softuart_close(suart_handle h_uart)
+{
+	s16 status = SUART_SUCCESS;
+
+	if (h_uart == NULL) {
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	} else {
+		g_uart_statu_table[h_uart->uart_num - 1] =
+			ePRU_SUART_UART_FREE;
+		/* Reset the Instance to Invalid */
+		h_uart->uart_num = PRU_SUART_UARTx_INVALID;
+		h_uart->uart_status = ePRU_SUART_UART_FREE;
+	}
+	return status;
+}
+
+/*
+ * suart routine for setting relative baud rate
+ */
+s16 pru_softuart_setbaud(struct device *dev, suart_handle h_uart,
+		u16 tx_clk_divisor, u16 rx_clk_divisor)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 regval = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/* Set the clock divisor value s32o the McASP */
+	if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
+		return SUART_INVALID_CLKDIVISOR;
+	if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
+		return SUART_INVALID_CLKDIVISOR;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	if (tx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+			(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = 0;
+	if (rx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	return status;
+}
+
+/*
+ * suart routine for setting number of bits per character for a specific uart
+ */
+s16 pru_softuart_setdatabits(struct device *dev, suart_handle h_uart,
+		u16 tx_data_bits, u16 rx_data_bits)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u32 reg_val;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/*
+	 * NOTE:
+	 * The supported data bits are 6,7,8,9,10,11,12 bits per character
+	 */
+
+	if ((tx_data_bits < ePRU_SUART_DATA_BITS6)
+			|| (tx_data_bits > ePRU_SUART_DATA_BITS12))
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+
+	if ((rx_data_bits < ePRU_SUART_DATA_BITS6)
+			|| (rx_data_bits > ePRU_SUART_DATA_BITS12))
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+			|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	if (tx_data_bits != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 1);
+		reg_val &= ~(0xF);
+		reg_val |= tx_data_bits;
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 1);
+	}
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+			|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	if (rx_data_bits != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 1);
+		reg_val &= ~(0xF);
+		reg_val |= rx_data_bits;
+		pruss_writeb(dev, offset, (u8 *) &rx_data_bits, 1);
+	}
+
+	return status;
+}
+
+/*
+ * suart routine to configure specific uart
+ */
+s16 pru_softuart_setconfig(struct device *dev, suart_handle h_uart,
+				suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/*
+	 * NOTE:
+	 * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
+	 * EQUAL TO 64, preScalarValue <= 64
+	 */
+	if ((config_uart->tx_clk_divisor > 384)
+			|| (config_uart->rx_clk_divisor > 384)) {
+		return SUART_INVALID_CLKDIVISOR;
+	}
+	if ((config_uart->tx_bits_per_char < 8)
+			|| (config_uart->tx_bits_per_char > 14)) {
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+	}
+	if ((config_uart->rx_bits_per_char < 8)
+			|| (config_uart->rx_bits_per_char > 14)) {
+		return PRU_SUART_ERR_PARAMETER_INVALID;
+	}
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+			|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Configuring the Transmit part of the given UART */
+	/* Serializer has been as TX in mcasp config, by writing 1 in bits
+	*  corresponding to tx serializer in PFUNC regsiter ie already set
+	*  to GPIO mode PRU code will set then back to MCASP mode once TX
+	*  request for that serializer is posted.It is required because@this
+	*  pos32 Mcasp is accessed by both PRU and DSP have lower priority for
+	*  Mcasp in comparison to PRU and DPS keeps on looping there only
+	*/
+	/*
+	 * suart_mcasp_tx_serialzier_set
+	 * (config_uart->tx_serializer, &suart_iomap);
+	 */
+	/* Configuring TX serializer  */
+	if (config_uart->tx_serializer != PRU_SUART_SERIALIZER_NONE) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CTRL_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->tx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->tx_clk_divisor <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->tx_bits_per_char <<
+			PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+		offset = 8;
+		pru_softuart_write(dev, h_uart, &offset, 0);
+	}
+
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+			(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Configuring the Transmit part of the given UART */
+	if (config_uart->rx_serializer != PRU_SUART_SERIALIZER_NONE) {
+		/* Configuring RX serializer  */
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CTRL_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->rx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+		/* Configuring RX prescalar value and Oversampling */
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->rx_clk_divisor <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT) |
+			(config_uart->oversampling <<
+			PRU_SUART_CH_CONFIG1_OVS_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+		/* Configuring RX bits per character value */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+						+ PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+		reg_val = reg_val | (config_uart->rx_bits_per_char <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+	}
+	return status;
+}
+
+/*
+ * suart routine for getting the number of bytes transfered
+ */
+s16 pru_softuart_get_tx_data_len(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16_read_value = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16_read_value, 2);
+	u16_read_value = ((u16_read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	return u16_read_value;
+}
+
+/*
+ * suart routine for getting the number of bytes received
+ */
+s16 pru_softuart_get_rx_data_len(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16_read_value = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16_read_value, 2);
+	u16_read_value = ((u16_read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+
+	return u16_read_value;
+}
+
+/*
+ * suart routine to get the configuration information from a specific uart
+ */
+s16 pru_softuart_getconfig(struct device *dev,
+			 suart_handle h_uart, suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 reg_val = 0;
+	s16 status = SUART_SUCCESS;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	/*
+	 * NOTE:
+	 * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
+	 * EQUAL TO 64, preScalarValue <= 64
+	 */
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+					 (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Configuring the Transmit part of the given UART */
+	/* Configuring TX serializer  */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->tx_serializer = ((reg_val & PRU_SUART_CH_CTRL_SR_MASK) >>
+						PRU_SUART_CH_CTRL_SR_SHIFT);
+	/* Configuring TX prescalar value */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG1_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->tx_clk_divisor = ((reg_val &
+				 PRU_SUART_CH_CONFIG1_DIVISOR_MASK) >>
+					 PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+	/* Configuring TX bits per character value */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->tx_bits_per_char = ((reg_val &
+				 PRU_SUART_CH_CONFIG1_DIVISOR_MASK) >>
+					PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+	if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num++;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	/* Configuring the Transmit part of the given UART */
+	/* Configuring RX serializer  */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->rx_serializer = ((reg_val & PRU_SUART_CH_CTRL_SR_MASK) >>
+						PRU_SUART_CH_CTRL_SR_SHIFT);
+
+	/* Configuring RX prescalar value and oversampling */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG1_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->rx_clk_divisor = ((reg_val &
+					 PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+	config_uart->oversampling = ((reg_val &
+					 PRU_SUART_CH_CONFIG1_OVS_MASK) >>
+						PRU_SUART_CH_CONFIG1_OVS_SHIFT);
+
+	/* Configuring RX bits per character value */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	config_uart->rx_bits_per_char = ((reg_val &
+					 PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+
+	return status;
+}
+
+s32 pru_softuart_pending_tx_request(struct device *dev)
+{
+	u32 offset = 0;
+	u32 u32ISR_value = 0;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		return SUART_SUCCESS;
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		/* Read PRU Interrupt Status Register from PRU */
+		offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+		pruss_readl(dev, offset, (u32 *)&u32ISR_value, 1);
+		if ((u32ISR_value & 0x1) == 0x1)
+			return PRU_SUART_FAILURE;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		/* Read PRU Interrupt Status Register from PRU */
+		offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+		pruss_readl(dev, offset, (u32 *)&u32ISR_value, 1);
+		if ((u32ISR_value & 0x2) == 0x2)
+			return PRU_SUART_FAILURE;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	return SUART_SUCCESS;
+}
+
+/*
+ * suart data transmit routine
+ */
+s16 pru_softuart_write(struct device *dev, suart_handle h_uart,
+		u32 *pt_tx_data_buf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			pru_num = h_uart->uart_num;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+			pru_num = h_uart->uart_num;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		pru_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		pru_num = 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* Writing the data pos32er to channel TX data pointer */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_TXRXDATA_OFFSET;
+	pruss_writeb(dev, offset, (u8 *) pt_tx_data_buf, 4);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~(PRU_SUART_CH_CTRL_MODE_MASK |
+			PRU_SUART_CH_CTRL_SREQ_MASK);
+	reg_val |= (PRU_SUART_CH_CTRL_TX_MODE <<
+		PRU_SUART_CH_CTRL_MODE_SHIFT) | (PRU_SUART_CH_CTRL_SREQ <<
+		PRU_SUART_CH_CTRL_SREQ_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, pru_num);
+
+	return status;
+}
+
+/*
+ * suart data receive routine
+ */
+s16 pru_softuart_read(struct device *dev, suart_handle h_uart,
+		u32 *ptDataBuf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+			 (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+	ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			pru_num = h_uart->uart_num;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+			pru_num = h_uart->uart_num;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		pru_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		pru_num = 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* Writing the data pos32er to channel RX data pointer */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+		PRU_SUART_CH_TXRXDATA_OFFSET;
+	pruss_writeb(dev, offset, (u8 *) ptDataBuf, 4);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+		PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~(PRU_SUART_CH_CTRL_MODE_MASK |
+		PRU_SUART_CH_CTRL_SREQ_MASK);
+	reg_val |= (PRU_SUART_CH_CTRL_RX_MODE <<
+		PRU_SUART_CH_CTRL_MODE_SHIFT) | (PRU_SUART_CH_CTRL_SREQ <<
+		PRU_SUART_CH_CTRL_SREQ_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+
+	/* enable the timeout s32errupt */
+	suart_intr_setmask(dev, h_uart->uart_num, PRU_RX_INTR,
+		CHN_TXRX_IE_MASK_TIMEOUT);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, pru_num);
+
+	return status;
+}
+
+/*
+ * suart routine to read the data from the RX FIFO
+ */
+s16 pru_softuart_read_data(struct device *dev, suart_handle h_uart,
+				u8 *p_data_buffer, s32 s32max_len,
+					u32 *pu32data_read)
+{
+	s16 ret_val = PRU_SUART_SUCCESS;
+	u8 *pu8src_addr = NULL;
+	u32 u32data_read = 0;
+	u32 u32data_len = 0;
+	u32 u32char_len = 0;
+	u32 offset = 0;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16status = 0;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (h_uart->uart_num <= 4) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Get the data pos32er from channel RX data pointer */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_TXRXDATA_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &pu8src_addr, 4);
+
+	/* Reading data length from SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u32data_len, 2);
+
+	/* read the character length */
+	u32char_len = u32data_len & PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK;
+	u32char_len -= 2;	/* remove the START & STOP bit */
+
+	u32data_len &= PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	u32data_len = u32data_len >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT;
+	u32data_len++;
+
+	/* if the character length is greater than 8, then the size doubles */
+	if (u32char_len > 8)
+		u32data_len *= 2;
+
+	/* Check if the time-out had occured. If, yes, then we need to find the
+	 * number of bytes read from PRU. Else, we need to
+	 * read the requested bytes
+	 */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16status, 1);
+	if (CHN_TXRX_STATUS_TIMEOUT == (u16status & CHN_TXRX_STATUS_TIMEOUT)) {
+		/* determine the number of bytes read s32o the FIFO */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+				 + PRU_SUART_CH_BYTESDONECNTR_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &u32data_read, 1);
+
+		/* if the character length is greater than 8,
+				then the size doubles */
+		if (u32char_len > 8)
+			u32data_read *= 2;
+
+/*
+ * the data corresponding is loaded in second
+ * half during the timeout
+ */
+		if (u32data_read > u32data_len) {
+			u32data_read -= u32data_len;
+			pu8src_addr += (u32data_len + 1);
+		}
+
+		pru_softuart_clr_rx_fifo(dev, h_uart);
+	} else {
+		u32data_read = u32data_len;
+/*
+ * if the bit is set, the data is in the first
+ * half of the FIFO else the data is in the second half
+ */
+		/* Determine the buffer index by reading FIFO_OddEven flag*/
+		if (u16status & CHN_TXRX_STATUS_CMPLT)
+			pu8src_addr += u32data_len;
+	}
+
+	/* we should be copying only max len given by the application */
+	if (u32data_read > s32max_len)
+		u32data_read = s32max_len;
+
+/* evaluate the virtual address of the FIFO address
+ * based on the physical addr
+ */
+	pu8src_addr = (u8 *)((u32) pu8src_addr -
+		(u32) suart_iomap.p_fifo_buff_phys_base +
+		(u32) suart_iomap.p_fifo_buff_virt_base);
+
+	/* Now we have both the data length and the source address. copy */
+	for (offset = 0; offset < u32data_read; offset++) {
+		*p_data_buffer++ = *pu8src_addr++;
+	}
+	*pu32data_read = u32data_read;
+	ret_val = PRU_SUART_SUCCESS;
+
+	return ret_val;
+}
+
+/*
+ * suart routine to disable the receive functionality.
+ * This routine stops the PRU from receiving on selected
+ * UART and also disables the McASP serializer corresponding
+ * to this UART Rx line.
+ */
+s16 pru_softuart_stop_receive(struct device *dev, suart_handle h_uart)
+{
+	u16 status = SUART_SUCCESS;
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num;
+	u16 u16status;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* read the existing value of status flag */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16status, 1);
+
+	/* we need to clear the busy bit corresponding to receive channel */
+	u16status &= ~(CHN_TXRX_STATUS_RDY);
+	pruss_writeb(dev, offset, (u8 *) &u16status, 1);
+
+	/* get the serizlizer number being used for this Rx channel */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &u16status, 2);
+	u16status &= PRU_SUART_CH_CTRL_SR_MASK;
+	u16status = u16status >> PRU_SUART_CH_CTRL_SR_SHIFT;
+
+	/* we need to de-activate the serializer corresponding to this rx */
+	status = suart_asp_serializer_deactivate(u16status, &suart_iomap);
+
+	return status;
+}
+
+/*
+ * suart routine to get the tx status for a specific uart
+ */
+s16 pru_softuart_get_tx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+s16 pru_softuart_clr_tx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+	} else if (PRU0_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_TX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	status &= ~(0x2);
+	pruss_writeb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+/*
+ * suart routine to get the rx status for a specific uart
+ */
+s16 pru_softuart_get_rx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+s16 pru_softuart_clr_rx_fifo(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+	u16 reg_val;
+	u16 uart_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+	uart_num = h_uart->uart_num;
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num * SUART_NUM_OF_CHANNELS_PER_SUART)
+									 - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		uart_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		uart_num = 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &reg_val, 2);
+	reg_val &= ~(PRU_SUART_CH_CTRL_MODE_MASK | PRU_SUART_CH_CTRL_SREQ_MASK);
+	reg_val |= (PRU_SUART_CH_CTRL_RX_MODE << PRU_SUART_CH_CTRL_MODE_SHIFT) |
+		(PRU_SUART_CH_CTRL_SREQ << PRU_SUART_CH_CTRL_SREQ_SHIFT);
+	pruss_writeb(dev, offset, (u8 *) &reg_val, 2);
+	suart_intr_setmask(dev, h_uart->uart_num, PRU_RX_INTR,
+						CHN_TXRX_IE_MASK_TIMEOUT);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, uart_num);
+
+	return status;
+}
+
+s16 pru_softuart_clr_rx_status(struct device *dev, suart_handle h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = SUART_SUCCESS;
+	u16 ch_num;
+
+	if (h_uart == NULL)
+		return PRU_SUART_ERR_HANDLE_INVALID;
+
+	ch_num = h_uart->uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+		(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = (h_uart->uart_num *
+			SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if (h_uart->uart_num <= 4) {
+			/* PRU0 */
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			/* PRU1 */
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			ch_num -= 8;
+		}
+		ch_num++;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status, 1);
+	status &= ~(0x3C);
+	pruss_writeb(dev, offset, (u8 *) &status, 1);
+	return status;
+}
+
+/*
+ * suart_s32r_status_read: Gets the Global Interrupt status register
+ * for the specified SUART.
+ * uart_num < 1 to 6 >
+ * txrx_flag < Indicates TX or RX s32errupt for the uart >
+ */
+s16 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num, u16 *txrx_flag)
+{
+	u32 offset;
+	u32 u32intc_offset;
+	u32 ch_num = 0xFF;
+	u32 reg_val = 0;
+	u32 u32reg_val = 0;
+	u32 u32ISR_value = 0;
+	u32 u32ack_reg_val = 0;
+	u8 pru0_mode = PRU_MODE_INVALID;
+	u8 pru1_mode = PRU_MODE_INVALID;
+	u32 u32stat_inx_clr_regoffset = 0;
+
+	/* initialize the status & Flag to known value */
+	*txrx_flag = 0;
+
+	u32stat_inx_clr_regoffset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+
+	/* Read PRU Interrupt Status Register from PRU */
+	u32intc_offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+
+	pruss_readl(dev, u32intc_offset, (u32 *)&u32ISR_value, 1);
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* determine if the s32errupt occured current UART context */
+		u32reg_val = (PRU_SUART0_TX_EVT_BIT | PRU_SUART0_RX_EVT_BIT) <<
+				((uart_num - 1) * 2);
+
+		/* channel starts from 0 and uart instance starts from 1 */
+		ch_num = uart_num * 2 - 2;
+		if (uart_num <= 4)
+			pru0_mode = PRU_MODE_RX_TX_BOTH;
+		else
+			pru1_mode = PRU_MODE_RX_TX_BOTH;
+	} else {
+		ch_num = uart_num - 1;
+		if ((u32ISR_value & 0x03FC) != 0) {
+			u32reg_val = 0;
+
+			offset = PRU_SUART_PRU0_RX_TX_MODE;
+			pruss_readb(dev, offset, (u8 *) &pru0_mode, 1);
+			u32reg_val |= 1 << (uart_num + 1);
+			if (u32ISR_value & u32reg_val) {
+				/* acknowledge the s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+				*txrx_flag |= PRU_RX_INTR;
+			}
+		}
+		pruss_readl(dev, u32intc_offset, (u32 *)&u32ISR_value, 1);
+		if (u32ISR_value & 0x3FC00) {
+			u32reg_val = 0;
+			offset = PRU_SUART_PRU1_RX_TX_MODE;
+			pruss_readb(dev, offset, (u8 *) &pru1_mode, 1);
+			u32reg_val |= 1 << (uart_num + 9);
+			if (u32ISR_value & u32reg_val) {
+				/* acknowledge the s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART4_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+				*txrx_flag |= PRU_TX_INTR;
+			}
+		}
+	}
+	if (u32ISR_value & u32reg_val) {
+		if ((pru0_mode == PRU_MODE_RX_TX_BOTH)
+		    || (pru1_mode == PRU_MODE_RX_TX_BOTH)) {
+			/* Check if the s32errupt occured for Tx */
+			u32reg_val = PRU_SUART0_TX_EVT_BIT << ((uart_num - 1)
+									 * 2);
+			if (u32ISR_value & u32reg_val) {
+				/* s32erupt occured for TX */
+				*txrx_flag |= PRU_TX_INTR;
+				/* acknowledge the RX s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+			}
+
+			/* Check if the s32errupt occured for Rx */
+			u32reg_val = PRU_SUART0_RX_EVT_BIT<<((uart_num - 1)
+									 * 2);
+			if (u32ISR_value & u32reg_val) {
+				/* s32erupt occured for RX */
+				*txrx_flag |= PRU_RX_INTR;
+				ch_num += 1;
+
+				/* acknowledge the RX s32errupt  */
+				u32ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, u32stat_inx_clr_regoffset,
+					(u32 *)&u32ack_reg_val, 1);
+			}
+		}
+		reg_val = SUART_SUCCESS;
+	}
+	return reg_val;
+}
+
+s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num, u32 txrxmode)
+{
+	u32 offset;
+	u16 txrx_flag = 0;
+	u16 chn_num;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (uart_num <= 4) {
+			/* PRU0 */
+			offset = PRU_SUART_PRU0_ISR_OFFSET + 1;
+		} else {
+			/* PRU1 */
+			offset = PRU_SUART_PRU1_ISR_OFFSET + 1;
+			/* First 8 channel corresponds to PRU0 */
+			chn_num -= 8;
+		}
+		if (2 == txrxmode)
+			chn_num++;
+	} else if (PRU0_MODE == txrxmode) {
+		offset = PRU_SUART_PRU0_ISR_OFFSET + 1;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_ISR_OFFSET + 1;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+
+	pruss_readb(dev, offset, (u8 *) &txrx_flag, 1);
+	txrx_flag &= ~(0x2);
+	pruss_writeb(dev, offset, (u8 *) &txrx_flag, 1);
+
+	return 0;
+}
+
+s16 suart_arm_to_pru_intr(struct device *dev, u16 uart_num)
+{
+	u32 u32offset;
+	u32 u32value;
+	s16 s16retval;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		if ((uart_num > 0) && (uart_num <= 4)) {
+			/* PRU0 SYS_EVT32 */
+			u32value = 0x20;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			/* PRU1 SYS_EVT33 */
+			u32value = 0x21;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+	}
+
+	if ((PRU0_MODE == PRU_MODE_RX_ONLY) || (PRU1_MODE == PRU_MODE_RX_ONLY)
+	    || (PRU0_MODE == PRU_MODE_TX_ONLY)
+	    || (PRU1_MODE == PRU_MODE_TX_ONLY)) {
+		if (uart_num == PRUSS_NUM0) {
+			/* PRU0 SYS_EVT32 */
+			u32value = 0x20;
+		}
+
+		if (uart_num == PRUSS_NUM1) {
+			/* PRU0 SYS_EVT33 */
+			u32value = 0x21;
+		}
+	}
+
+	u32offset = (u32) (PRUSS_INTC_STATIDXSET & 0xFFFF);
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+	return 0;
+}
+
+s16 arm_to_pru_intr_init(struct device *dev)
+{
+	u32 u32offset;
+	u32 u32value;
+	u32 int_offset;
+	s16 s16retval = -1;
+#if 0
+	/* Set the MCASP Event to PRU0 as Edge Triggered */
+	u32offset = (u32)(PRU_INTC_TYPE0 & 0xFFFF);
+	u32value = 0x80000000;
+	s16retval =
+	    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+#endif
+	/* Clear all the host s32errupts */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_HSTINTENIDXCLR & 0xFFFF);
+		u32value = int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+
+	/* Enable the global s32errupt */
+	u32offset = (u32) (PRUSS_INTC_GLBLEN & 0xFFFF);
+	u32value = 0x1;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	/* Enable the Host s32errupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							 int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
+		u32value = int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+
+	u32offset = (u32) (PRUSS_INTC_HOSTMAP0 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_123_HOST;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+
+	u32offset = (u32) (PRUSS_INTC_HOSTMAP1 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_4567_HOST;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+	u32offset = (u32) (PRUSS_INTC_HOSTMAP2 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_89_HOST;
+	s16retval =
+	    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+
+	/* Set the channel for System s32rrupts
+	 * MAP Channel 0 to SYS_EVT31
+	 */
+	u32offset =	(u32) (PRUSS_INTC_CHANMAP7 & 0xFFFF);
+	u32value = PRU_INTC_CHAN_0_SYSEVT_31;
+	s16retval =
+	    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (-1 == s16retval)
+		return -1;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		u32offset = (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_12_SYSEVT;
+		s16retval =
+		    pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 3 to SYS_EVT36   SUART1-Tx
+		 * MAP channel 3 to SYS_EVT37   SUART1-Rx
+		 * MAP channel 4 to SYS_EVT38   SUART2-Tx
+		 * MAP channel 4 to SYS_EVT39   SUART2-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 5 to SYS_EVT40   SUART3-Tx
+		 * MAP channel 5 to SYS_EVT41   SUART3-Rx
+		 * MAP channel 6 to SYS_EVT42   SUART4-Tx
+		 * MAP channel 6 to SYS_EVT43   SUART4-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_56_SYSEVT_40_43;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 7 to SYS_EVT44   SUART5-Tx
+		 * MAP channel 7 to SYS_EVT45   SUART5-Rx
+		 * MAP channel 8 to SYS_EVT46   SUART6-Tx
+		 * MAP channel 8 to SYS_EVT47   SUART6-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_78_SYSEVT_44_47;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 9 to SYS_EVT48   SUART7-Tx
+		 * MAP channel 9 to SYS_EVT49   SUART7-Rx
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_9_SYSEVT_48_49;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+	}
+	if ((PRU0_MODE == PRU_MODE_RX_ONLY) || (PRU1_MODE == PRU_MODE_RX_ONLY)
+	    || (PRU0_MODE == PRU_MODE_TX_ONLY)
+	    || (PRU1_MODE == PRU_MODE_TX_ONLY)) {
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 0 to SYS_EVT32
+		 * MAP channel 1 to SYS_EVT33
+		 * MAP channel 2 to SYS_EVT34  SUART0
+		 * MAP channel 3 to SYS_EVT35  SUART1
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_0123_SYSEVT_32_35;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 4 to SYS_EVT36   SUART2
+		 * MAP channel 5 to SYS_EVT37   SUART3
+		 * MAP channel 6 to SYS_EVT38   SUART4
+		 * MAP channel 7 to SYS_EVT39   SUART5
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_4567_SYSEVT_36_39;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 8 to SYS_EVT40   SUART6
+		 * MAP channel 9 to SYS_EVT41   SUART7
+		 * MAP channel 2 to SYS_EVT42   SUART0
+		 * MAP channel 3 to SYS_EVT43   SUART1
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_8923_SYSEVT_40_43;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 4 to SYS_EVT44   SUART2
+		 * MAP channel 5 to SYS_EVT45   SUART3
+		 * MAP channel 6 to SYS_EVT46   SUART4
+		 * MAP channel 7 to SYS_EVT47   SUART5
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF);
+		u32value = PRU_INTC_CHAN_4567_SYSEVT_44_47;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+
+		/* Sets the channel for the system s32errupt
+		 * MAP channel 8 to SYS_EVT48   SUART6
+		 * MAP channel 9 to SYS_EVT49   SUART7
+		 */
+		u32offset = (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF);
+		u32value = 0x00010908;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (-1 == s16retval)
+			return -1;
+	}
+
+	/* Clear required set of system events
+	* and enable them using indexed register
+	*/
+	for (int_offset = 0; int_offset < 18; int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+		u32value = 32 + int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+
+	}
+	/* enable only the HOST to PRU s32errupts and let the PRU to Host events
+	 * enabled by the separate API on demand basis.
+	 */
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 31;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 32;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 33;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+	u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+	u32value = 50;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	/* Enable the global s32errupt */
+	u32offset = (u32) (PRUSS_INTC_GLBLEN & 0xFFFF);
+	u32value = 0x1;
+	s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+	if (s16retval == -1)
+		return -1;
+
+	/* Enable the Host s32errupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++) {
+		u32offset = (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF);
+		u32value = int_offset;
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+
+	return 0;
+}
+
+s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
+		u32 txrxmode, s32 s32_flag)
+{
+	s32 ret_val = 0;
+	u32 u32offset;
+	u32 chn_num;
+	u32 u32value;
+	s16 s16retval = 0;
+
+	if (uart_num > 8)
+		return SUART_INVALID_UART_NUM;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+		(PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		chn_num = (uart_num * 2) - 2;
+		if (2 == txrxmode)	/* Rx mode */
+			chn_num++;
+		u32value = 34 + chn_num;
+	} else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_RX_ONLY))
+		u32value = 34 + chn_num;
+	else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_RX_ONLY))
+		u32value = 42 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_TX_ONLY))
+		u32value = 34 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_TX_ONLY))
+		u32value = 42 + chn_num;
+	else
+		return -1;
+
+	if (SUART_TRUE == s32_flag) {
+		u32offset = (u32) (PRUSS_INTC_ENIDXSET & 0xFFFF);
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	} else {
+		u32offset = (u32) (PRUSS_INTC_ENIDXCLR & 0xFFFF);
+		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
+		if (s16retval == -1)
+			return -1;
+	}
+	return ret_val;
+}
+
+s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 s32rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	u32 txrx_flag;
+	u32 regval = 0;
+	u32 chn_num;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if ((uart_num > 0) && (uart_num <= 4)) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			offset = PRU_SUART_PRU0_IMR_OFFSET;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			offset = PRU_SUART_PRU1_IMR_OFFSET;
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			chn_num -= 8;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+		if (2 == txrxmode) {	/* rx mode */
+			chn_num++;
+		}
+	} else if (PRU0_MODE == txrxmode) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		offset = PRU_SUART_PRU0_IMR_OFFSET;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (s32rmask & CHN_TXRX_IE_MASK_CMPLT)) {
+		pruss_readb(dev, offset, (u8 *) &txrx_flag, 2);
+		txrx_flag &= ~(regval);
+		txrx_flag |= regval;
+		pruss_writeb(dev, offset, (u8 *) &txrx_flag, 2);
+	}
+	if ((s32rmask & SUART_GBL_INTR_ERR_MASK) ==
+			SUART_GBL_INTR_ERR_MASK) {
+		regval = 0;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(SUART_GBL_INTR_ERR_MASK);
+		regval |= (SUART_GBL_INTR_ERR_MASK);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+
+	}
+	/* Break Indicator Interrupt Masked */
+	if ((s32rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		regval |= CHN_TXRX_IE_MASK_FE;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	/* Framing Error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (s32rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		regval |= CHN_TXRX_IE_MASK_BI;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(s32rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		regval |= CHN_TXRX_IE_MASK_TIMEOUT;
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	return 0;
+}
+
+s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 s32rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 txrx_flag;
+	u16 regval = 0;
+	u16 chn_num;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if ((uart_num > 0) && (uart_num <= 4)) {
+			pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+			offset = PRU_SUART_PRU0_IMR_OFFSET;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			/* PRU1 */
+			offset = PRU_SUART_PRU1_IMR_OFFSET;
+			pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			chn_num -= 8;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+		if (2 == txrxmode) {	/* rx mode */
+			chn_num++;
+		}
+	} else if (PRU0_MODE == txrxmode) {
+		pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		offset = PRU_SUART_PRU0_IMR_OFFSET;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (s32rmask & CHN_TXRX_IE_MASK_CMPLT)) {
+		pruss_readb(dev, offset, (u8 *) &txrx_flag, 2);
+		txrx_flag &= ~(regval);
+		pruss_writeb(dev, offset, (u8 *) &txrx_flag, 2);
+	}
+
+	if ((s32rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK) {
+		regval = 0;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(SUART_GBL_INTR_ERR_MASK);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+
+	}
+	/* Break Indicator Interrupt Masked */
+	if ((s32rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	/* Framing Error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (s32rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(s32rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		offset = pru_offset +
+			(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readb(dev, offset, (u8 *) &regval, 2);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		pruss_writeb(dev, offset, (u8 *) &regval, 2);
+	}
+	return 0;
+}
+
+s32 suart_intr_getmask(struct device *dev, u16 uart_num, u32 txrxmode,
+			u32 s32rmask)
+{
+	u16 chn_num;
+	u32 offset;
+	u16 txrx_flag;
+	u16 regval = 1;
+
+	chn_num = uart_num - 1;
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* channel starts from 0 and uart instance starts from 1 */
+		chn_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+
+		if ((uart_num > 0) && (uart_num <= 4)) {
+
+			offset = PRU_SUART_PRU0_IMR_OFFSET;
+		} else if ((uart_num > 4) && (uart_num <= 8)) {
+			/* PRU1 */
+			offset = PRU_SUART_PRU1_IMR_OFFSET;
+			/* First 8 channel corresponds to PRU0 */
+			chn_num -= 8;
+		} else {
+			return SUART_INVALID_UART_NUM;
+		}
+
+		if (2 == txrxmode) {	/* rx mode */
+			chn_num++;
+		}
+	} else if (PRU0_MODE == txrxmode) {
+		offset = PRU_SUART_PRU0_IMR_OFFSET;
+	} else if (PRU1_MODE == txrxmode) {
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+	} else {
+		return PRU_MODE_INVALID;
+	}
+	regval = regval << chn_num;
+	pruss_readb(dev, offset, (u8 *) &txrx_flag, 2);
+	txrx_flag &= regval;
+	if (0 == s32rmask) {
+		if (txrx_flag == 0)
+			return 1;
+	}
+	if (1 == s32rmask) {
+		if (txrx_flag == regval)
+			return 1;
+	}
+	return 0;
+}
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
new file mode 100644
index 0000000..4ce5621
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _SUART_API_H_
+#define _SUART_API_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+
+#define SINGLE_PRU				0
+#define BOTH_PRU				1
+#define PRU_ACTIVE				BOTH_PRU
+
+#define SUART_NUM_OF_CHANNELS_PER_SUART		2
+#define SUART_NUM_OF_BYTES_PER_CHANNEL		16
+
+#define SUART_PASS				0
+#define SUART_SUCCESS				0
+#define SUART_FAIL				1
+#define SUART_FALSE				0
+#define SUART_TRUE				1
+
+#define PRU_TX_INTR				1
+#define PRU_RX_INTR				2
+
+#define CHN_TXRX_STATUS_TIMEOUT			BIT(6)
+#define CHN_TXRX_STATUS_BI			BIT(5)
+#define CHN_TXRX_STATUS_FE			BIT(4)
+#define CHN_TXRX_STATUS_UNERR			BIT(3)
+#define CHN_TXRX_STATUS_OVRNERR			BIT(3)
+#define CHN_TXRX_STATUS_ERR			BIT(2)
+#define CHN_TXRX_STATUS_CMPLT			BIT(1)
+#define CHN_TXRX_STATUS_RDY			BIT(0)
+
+#define CHN_TXRX_IE_MASK_TIMEOUT		BIT(14)
+#define CHN_TXRX_IE_MASK_BI			BIT(13)
+#define CHN_TXRX_IE_MASK_FE			BIT(12)
+#define CHN_TXRX_IE_MASK_CMPLT			BIT(1)
+
+#define SUART_GBL_INTR_ERR_MASK			BIT(9)
+#define SUART_PRU_ID_MASK			0xFF
+
+#define SUART_FIFO_LEN				15
+#define SUART_8X_OVRSMPL			1
+#define SUART_16X_OVRSMPL			2
+#define SUART_DEFAULT_OVRSMPL			SUART_8X_OVRSMPL
+
+#if (SUART_DEFAULT_OVRSMPL == SUART_16X_OVRSMPL)
+#define SUART_DEFAULT_BAUD			57600
+#else
+#define SUART_DEFAULT_BAUD			115200
+#endif
+
+#define PRU_MODE_INVALID			0x00
+#define PRU_MODE_TX_ONLY			0x1
+#define PRU_MODE_RX_ONLY			0x2
+#define PRU_MODE_RX_TX_BOTH			0x3
+
+#if (PRU_ACTIVE == BOTH_PRU)
+#define PRU0_MODE				PRU_MODE_RX_ONLY
+#define PRU1_MODE				PRU_MODE_TX_ONLY
+#elif (PRU_ACTIVE ==  SINGLE_PRU)
+#define PRU0_MODE				PRU_MODE_RX_TX_BOTH
+#define PRU1_MODE				PRU_MODE_INVALID
+#else
+#define PRU0_MODE				PRU_MODE_INVALID
+#define PRU1_MODE				PRU_MODE_INVALID
+#endif
+
+#define MCASP_XBUF_BASE_ADDR			(0x01d00200)
+#define MCASP_RBUF_BASE_ADDR			(0x01d00280)
+#define MCASP_SRCTL_BASE_ADDR			(0x01d00180)
+
+#define MCASP_SRCTL_TX_MODE			(0x000D)
+#define MCASP_SRCTL_RX_MODE			(0x000E)
+
+/* Since only PRU0 can work as RX */
+#define RX_DEFAULT_DATA_DUMP_ADDR		(0x00001FC)
+#define PRU_NUM_OF_CHANNELS			(16)
+
+#define	PRU_SUART_UART1		(1u)
+#define	PRU_SUART_UART2		(2u)
+#define	PRU_SUART_UART3		(3u)
+#define	PRU_SUART_UART4		(4u)
+#define	PRU_SUART_UART5		(5u)
+#define	PRU_SUART_UART6		(6u)
+#define	PRU_SUART_UART7		(7u)
+#define PRU_SUART_UART8		(8u)
+
+#define PRU_SUART_UARTx_INVALID	(9u)
+
+#define PRU_SUART_HALF_TX	(1u)
+#define PRU_SUART_HALF_RX			(2u)
+#define PRU_SUART_HALF_TX_DISABLED		(4u)
+#define PRU_SUART_HALF_RX_DISABLED		(8u)
+
+
+/*
+ *  This enum is used to specify the direction of the channel in UART
+ */
+typedef enum {
+	SUART_CHN_TX = 1,
+	SUART_CHN_RX = 2
+} SUART_CHN_DIR;
+
+/*
+ *  This enum is used to specify the state of the channel in UART. It
+ *  is either enabled or disabled.
+ */
+typedef enum {
+	SUART_CHN_DISABLED = 0,
+	SUART_CHN_ENABLED = 1
+} SUART_CHN_STATE;
+
+typedef enum {
+	ePRU_SUART_DATA_BITS6 = 8,
+	ePRU_SUART_DATA_BITS7,
+	ePRU_SUART_DATA_BITS8,
+	ePRU_SUART_DATA_BITS9,
+	ePRU_SUART_DATA_BITS10,
+	ePRU_SUART_DATA_BITS11,
+	ePRU_SUART_DATA_BITS12
+	} SUART_EN_BITSPERCHAR;
+
+typedef enum {
+	ePRU_SUART_NUM_1 = 1,
+	ePRU_SUART_NUM_2,
+	ePRU_SUART_NUM_3,
+	ePRU_SUART_NUM_4,
+	ePRU_SUART_NUM_5,
+	ePRU_SUART_NUM_6,
+	ePRU_SUART_NUM_7,
+	ePRU_SUART_NUM_8
+} SUART_EN_UARTNUM;
+
+typedef enum {
+	ePRU_SUART_HALF_TX = 1,
+	ePRU_SUART_HALF_RX,
+	ePRU_SUART_FULL_TX_RX
+} SUART_EN_UARTTYPE;
+
+typedef enum {
+	ePRU_SUART_TX_CH0 = 0,
+	ePRU_SUART_TX_CH1,
+	ePRU_SUART_TX_CH2,
+	ePRU_SUART_TX_CH3,
+	ePRU_SUART_TX_CH4,
+	ePRU_SUART_TX_CH5,
+	ePRU_SUART_TX_CH6,
+	ePRU_SUART_TX_CH7
+} SUART_EN_TXCHANNEL;
+
+typedef enum {
+	ePRU_SUART_RX_CH0 = 0,
+	ePRU_SUART_RX_CH1,
+	ePRU_SUART_RX_CH2,
+	ePRU_SUART_RX_CH3,
+	ePRU_SUART_RX_CH4,
+	ePRU_SUART_RX_CH5,
+	ePRU_SUART_RX_CH6,
+	ePRU_SUART_RX_CH7
+} SUART_EN_RXCHANNEL;
+
+typedef enum {
+	ePRU_SUART_UART_FREE = 0,
+	ePRU_SUART_UART_IN_USE
+} SUART_EN_UART_STATUS;
+
+typedef struct {
+	u16 mode:2;
+	u16 service_req:1;
+	u16 asp_id:2;
+	u16 reserved1:3;
+	u16 serializer_num:4;
+	u16 reserved2:4;
+
+} pru_suart_chn_cntrl;
+
+typedef struct {
+	u16 presacler:10;
+	u16 over_sampling:2;
+	u16 framing_mask:1;
+	u16 break_mask:1;
+	u16 timeout_mask:1;
+	u16 reserved:1;
+} pru_suart_cnh_config1;
+
+typedef struct {
+	u16 bits_per_char:4;
+	u16 reserved1:4;
+	u16 data_len:4;
+	u16 reserved:4;
+} pru_suart_chn_config2;
+
+typedef struct {
+	u16 txrx_ready:1;
+	u16 txrx_complete:1;
+	u16 txrx_error:1;
+	u16 txrx_underrun:1;
+	u16 framing_error:1;
+	u16 break_error:1;
+	u16 timeout_error:1;
+	u16 reserved:8;
+	u16 chn_state:1;
+} pru_suart_chn_status;
+
+typedef struct {
+	pru_suart_chn_cntrl ch_ctrl;
+	pru_suart_cnh_config1 ch_config1;
+	pru_suart_chn_config2 ch_config2;
+	pru_suart_chn_status ch_txrx_status;
+	u32 ch_txrx_data;
+	u32 reserved1;
+} pru_suart_regs, *pru_suart_regs_ovly;
+
+typedef struct {
+	u32 asp_xsrctl_base;
+	u32 asp_xbuf_base;
+	u16 buff_addr;
+	u8 buff_size;
+	u8 bits_loaded;
+} pru_suart_tx_cntx_priv, *ppru_suart_tx_cntx_priv;
+
+typedef struct {
+	u32 asp_rbuf_base;
+	u32 asp_rsrctl_base;
+	u32 reserved1;
+	u32 reserved2;
+	u32 reserved3;
+	u32 reserved4;
+} pru_suart_rx_cntx_priv, *ppru_suart_rx_cntx_priv;
+
+typedef struct {
+	u8  tx_serializer;
+	u8  rx_serializer;
+	u16 tx_clk_divisor;
+	u16 rx_clk_divisor;
+	u8  tx_bits_per_char;
+	u8  rx_bits_per_char;
+	u8  oversampling;
+	u8  bi_inter_mask;
+	u8  fe_intr_mask;
+} suart_config;
+
+typedef struct {
+	u16 uart_num;
+	u16 uart_type;
+	u16 uart_tx_channel;
+	u16 uart_rx_channel;
+	u16 uart_status;
+} suart_struct_handle, *suart_handle;
+
+typedef struct {
+	void *mcasp_io_addr;
+	void *p_fifo_buff_phys_base;
+	void *p_fifo_buff_virt_base;
+	u32  pru_clk_freq;
+} pruss_suart_iomap;
+
+s16 pru_softuart_init(struct device *dev, u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			u8 *pru_suart_emu_code, u32 fw_size,
+			pruss_suart_iomap *pruss_ioaddr);
+
+s16 pru_softuart_open(suart_handle h_suart);
+
+s16 pru_softuart_close(suart_handle h_uart);
+
+s16 pru_softuart_setbaud(struct device *dev, suart_handle h_uart,
+			u16 tx_clk_divisor, u16 rx_clk_divisor);
+
+s16 pru_softuart_setdatabits(struct device *dev, suart_handle h_uart,
+			u16 tx_data_bits, u16 rx_data_bits);
+
+s16 pru_softuart_setconfig(struct device *dev, suart_handle h_uart,
+			suart_config *config_uart);
+
+s16 pru_softuart_getconfig(struct device *dev, suart_handle h_uart,
+			suart_config *config_uart);
+
+s32 pru_softuart_pending_tx_request(struct device *dev);
+
+s16 pru_softuart_write(struct device *dev, suart_handle h_uart,
+			u32 *pt_tx_data_buf, u16 data_len);
+
+s16 pru_softuart_read(struct device *dev, suart_handle h_uart,
+			u32 *pt_data_buf, u16 data_len);
+
+s32 suart_intr_clrmask(struct device *dev, u16 uart_num, u32 txrxmode,
+			u32 intrmask);
+
+s16 pru_softuart_clr_tx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_tx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_clr_rx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_rx_status(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num,
+			u16 *txrx_flag);
+
+s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num, u32 txrxmode);
+
+s32 suart_intr_getmask(struct device *dev, u16 uart_num, u32 txrxmode,
+			u32 intrmask);
+
+s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+			u32 txrxmode, u32 intrmask);
+
+s16 pru_softuart_get_tx_data_len(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_get_rx_data_len(struct device *dev, suart_handle h_uart);
+
+s16 suart_arm_to_pru_intr(struct device *dev, u16 uart_num);
+
+s16 arm_to_pru_intr_init(struct device *dev);
+
+s16 pru_softuart_deinit(struct device *dev);
+
+s16 pru_softuart_clr_rx_fifo(struct device *dev, suart_handle h_uart);
+
+s16 pru_softuart_read_data(struct device *dev, suart_handle h_uart,
+			u8 *p_data_buffer, s32 s32_max_len,
+			u32 *pu32data_read);
+
+s16 pru_softuart_stop_receive(struct device *dev, suart_handle h_uart);
+
+s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
+			u32 txrxmode, s32 s32flag);
+
+void pru_set_fifo_timeout(struct device *dev, s16 timeout);
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_board.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
new file mode 100644
index 0000000..58cc9e4
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: subhasish at mistralsolutions.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.
+ */
+
+#ifndef _OMAPL_SUART_BOARD_H_
+#define _OMAPL_SUART_BOARD_H_
+
+#define PRU_SUART0_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART0_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART0_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART1_CONFIG_DUPLEX	(PRU_SUART_HALF_TX | \
+					PRU_SUART_HALF_RX)
+#define PRU_SUART1_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_7)
+#define PRU_SUART1_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_8)
+
+#define PRU_SUART2_CONFIG_DUPLEX	(PRU_SUART_HALF_TX | \
+					PRU_SUART_HALF_RX)
+#define PRU_SUART2_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_9)
+#define PRU_SUART2_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_10)
+
+#define PRU_SUART3_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART3_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART3_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART4_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART4_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART4_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART5_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART5_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART5_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART6_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART6_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART6_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#define PRU_SUART7_CONFIG_DUPLEX	(PRU_SUART_HALF_TX_DISABLED | \
+					PRU_SUART_HALF_RX_DISABLED)
+#define PRU_SUART7_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_NONE)
+#define PRU_SUART7_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_NONE)
+
+#endif				/* End of _OMAPL_SUART_BOARD_H_ */
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_err.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
new file mode 100644
index 0000000..dd94f4e
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra at mistralsolutions.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.
+ */
+
+#ifndef _SUART_ERR_H_
+#define _SUART_ERR_H_
+
+#define PRU_SUART_SUCCESS	(0u)
+#define PRU_SUART_FAILURE	(-1)
+
+#define PRU_SUART_ERR_DEVICE_NOT_OPEN	(1u)
+#define PRU_SUART_ERR_UARTS_INIT_FAIL	(2u)
+#define PRU_SUART_ERR_UARTS_RESET_FAIL	(3u)
+#define PRU_SUART_ERR_HANDLE_INVALID	(4u)
+#define PRU_SUART_ERR_PARAMETER_INVALID	(5u)
+
+#define PRU_SUART_ERR_TX		(6u)
+#define PRU_SUART_TX_COMPLETE		(7u)
+#define PRU_SUART_TX_BUSY		(8u)
+#define PRU_SUART_TX_UNDERRUN		(9u)
+
+#define PRU_SUART_ERR_RX		(10u)
+#define PRU_SUART_RX_COMPLETE		(11u)
+#define PRU_SUART_RX_BUSY		(12u)
+#define PRU_SUART_RX_OVERRUN		(13u)
+
+/* API Specific Errors */
+#define SUART_INVALID_TX_BAUD		(14u)
+#define SUART_INVALID_OVERSAMPLING	(15u)
+#define SUART_INVALID_RX_BAUD		(16u)
+
+#define SUART_UART_IN_USE		(17u)
+
+#define SUART_INVALID_CLKDIVISOR	(18u)
+#define SUART_INVALID_UART_NUM		(19u)
+#define SUART_INVALID_SR_NUM		(20u)
+
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
new file mode 100644
index 0000000..fa99c6b
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
+ */
+
+#ifndef _OMAPLR_MCASP_H_
+#define _OMAPLR_MCASP_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/mfd/pruss/da8xx_pru.h>
+
+typedef struct {
+	u32 REVID;
+	u32 RSVD0[3];
+	u32 PFUNC;
+	u32 PDIR;
+	u32 PDOUT;
+	u32 PDIN;
+	u32 PDCLR;
+	u32 RSVD1[8];
+	u32 GBLCTL;
+	u32 AMUTE;
+	u32 DLBCTL;
+	u32 DITCTL;
+	u32 RSVD2[3];
+	u32 RGBLCTL;
+	u32 RMASK;
+	u32 RFMT;
+	u32 AFSRCTL;
+	u32 ACLKRCTL;
+	u32 AHCLKRCTL;
+	u32 RTDM;
+	u32 RINTCTL;
+	u32 RSTAT;
+	u32 RSLOT;
+	u32 RCLKCHK;
+	u32 REVTCTL;
+	u32 RSVD3[4];
+	u32 XGBLCTL;
+	u32 XMASK;
+	u32 XFMT;
+	u32 AFSXCTL;
+	u32 ACLKXCTL;
+	u32 AHCLKXCTL;
+	u32 XTDM;
+	u32 XINTCTL;
+	u32 XSTAT;
+	u32 XSLOT;
+	u32 XCLKCHK;
+	u32 XEVTCTL;
+	u32 RSVD4[12];
+	u32 DITCSRA0;
+	u32 DITCSRA1;
+	u32 DITCSRA2;
+	u32 DITCSRA3;
+	u32 DITCSRA4;
+	u32 DITCSRA5;
+	u32 DITCSRB0;
+	u32 DITCSRB1;
+	u32 DITCSRB2;
+	u32 DITCSRB3;
+	u32 DITCSRB4;
+	u32 DITCSRB5;
+	u32 DITUDRA0;
+	u32 DITUDRA1;
+	u32 DITUDRA2;
+	u32 DITUDRA3;
+	u32 DITUDRA4;
+	u32 DITUDRA5;
+	u32 DITUDRB0;
+	u32 DITUDRB1;
+	u32 DITUDRB2;
+	u32 DITUDRB3;
+	u32 DITUDRB4;
+	u32 DITUDRB5;
+	u32 RSVD5[8];
+	u32 SRCTL0;
+	u32 SRCTL1;
+	u32 SRCTL2;
+	u32 SRCTL3;
+	u32 SRCTL4;
+	u32 SRCTL5;
+	u32 SRCTL6;
+	u32 SRCTL7;
+	u32 SRCTL8;
+	u32 SRCTL9;
+	u32 SRCTL10;
+	u32 SRCTL11;
+	u32 SRCTL12;
+	u32 SRCTL13;
+	u32 SRCTL14;
+	u32 SRCTL15;
+	u32 RSVD6[16];
+	u32 XBUF0;
+	u32 XBUF1;
+	u32 XBUF2;
+	u32 XBUF3;
+	u32 XBUF4;
+	u32 XBUF5;
+	u32 XBUF6;
+	u32 XBUF7;
+	u32 XBUF8;
+	u32 XBUF9;
+	u32 XBUF10;
+	u32 XBUF11;
+	u32 XBUF12;
+	u32 XBUF13;
+	u32 XBUF14;
+	u32 XBUF15;
+	u32 RSVD7[16];
+	u32 RBUF0;
+	u32 RBUF1;
+	u32 RBUF2;
+	u32 RBUF3;
+	u32 RBUF4;
+	u32 RBUF5;
+	u32 RBUF6;
+	u32 RBUF7;
+	u32 RBUF8;
+	u32 RBUF9;
+	u32 RBUF10;
+	u32 RBUF11;
+	u32 RBUF12;
+	u32 RBUF13;
+	u32 RBUF14;
+	u32 RBUF15;
+} omapl_mcasp_regs, *omapl_mcasp_regs_ovly;
+
+
+#define OMAPL_MCASP_PFUNC_AFSR_MASK			(0x80000000u)
+#define OMAPL_MCASP_PFUNC_AFSR_SHIFT			(0x0000001Fu)
+#define OMAPL_MCASP_PFUNC_AFSR_RESETVAL			(0x00000000u)
+/* AFSR Tokens */
+#define OMAPL_MCASP_PFUNC_AFSR_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AFSR_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AHCLKR_MASK			(0x40000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKR_SHIFT			(0x0000001Eu)
+#define OMAPL_MCASP_PFUNC_AHCLKR_RESETVAL		(0x00000000u)
+/* AHCLKR Tokens */
+#define OMAPL_MCASP_PFUNC_AHCLKR_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKR_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_ACLKR_MASK			(0x20000000u)
+#define OMAPL_MCASP_PFUNC_ACLKR_SHIFT			(0x0000001Du)
+#define OMAPL_MCASP_PFUNC_ACLKR_RESETVAL		(0x00000000u)
+/* ACLKR Tokens */
+#define OMAPL_MCASP_PFUNC_ACLKR_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_ACLKR_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AFSX_MASK			(0x10000000u)
+#define OMAPL_MCASP_PFUNC_AFSX_SHIFT			(0x0000001Cu)
+#define OMAPL_MCASP_PFUNC_AFSX_RESETVAL			(0x00000000u)
+/* AFSX Tokens */
+#define OMAPL_MCASP_PFUNC_AFSX_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AFSX_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AHCLKX_MASK			(0x08000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKX_SHIFT			(0x0000001Bu)
+#define OMAPL_MCASP_PFUNC_AHCLKX_RESETVAL		(0x00000000u)
+/* AHCLKX Tokens */
+#define OMAPL_MCASP_PFUNC_AHCLKX_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AHCLKX_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_ACLKX_MASK			(0x04000000u)
+#define OMAPL_MCASP_PFUNC_ACLKX_SHIFT			(0x0000001Au)
+#define OMAPL_MCASP_PFUNC_ACLKX_RESETVAL		(0x00000000u)
+/* ACLKX Tokens */
+#define OMAPL_MCASP_PFUNC_ACLKX_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_ACLKX_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AMUTE_MASK			(0x02000000u)
+#define OMAPL_MCASP_PFUNC_AMUTE_SHIFT			(0x00000019u)
+#define OMAPL_MCASP_PFUNC_AMUTE_RESETVAL		(0x00000000u)
+/* AMUTE Tokens */
+#define OMAPL_MCASP_PFUNC_AMUTE_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AMUTE_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR15_MASK			(0x00008000u)
+#define OMAPL_MCASP_PFUNC_AXR15_SHIFT			(0x0000000Fu)
+#define OMAPL_MCASP_PFUNC_AXR15_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR15_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR15_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR14_MASK			(0x00004000u)
+#define OMAPL_MCASP_PFUNC_AXR14_SHIFT			(0x0000000Eu)
+#define OMAPL_MCASP_PFUNC_AXR14_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR14_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR14_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR13_MASK			(0x00002000u)
+#define OMAPL_MCASP_PFUNC_AXR13_SHIFT			(0x0000000Du)
+#define OMAPL_MCASP_PFUNC_AXR13_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR13_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR13_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR12_MASK			(0x00001000u)
+#define OMAPL_MCASP_PFUNC_AXR12_SHIFT			(0x0000000Cu)
+#define OMAPL_MCASP_PFUNC_AXR12_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR12_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR12_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR11_MASK			(0x00000800u)
+#define OMAPL_MCASP_PFUNC_AXR11_SHIFT			(0x0000000Bu)
+#define OMAPL_MCASP_PFUNC_AXR11_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR11_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR11_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR10_MASK			(0x00000400u)
+#define OMAPL_MCASP_PFUNC_AXR10_SHIFT			(0x0000000Au)
+#define OMAPL_MCASP_PFUNC_AXR10_RESETVAL		(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR10_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR10_GPIO			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_AXR9_MASK			(0x00000200u)
+#define OMAPL_MCASP_PFUNC_AXR9_SHIFT			(0x00000009u)
+#define OMAPL_MCASP_PFUNC_AXR9_RESETVAL			(0x00000000u)
+/* AXR9 Token */
+#define OMAPL_MCASP_PFUNC_AXR9_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR9_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR8_MASK			(0x00000100u)
+#define OMAPL_MCASP_PFUNC_AXR8_SHIFT			(0x00000008u)
+#define OMAPL_MCASP_PFUNC_AXR8_RESETVAL			(0x00000000u)
+/* AXR8 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR8_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR8_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR7_MASK			(0x00000080u)
+#define OMAPL_MCASP_PFUNC_AXR7_SHIFT			(0x00000007u)
+#define OMAPL_MCASP_PFUNC_AXR7_RESETVAL			(0x00000000u)
+/* AXR7 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR7_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR7_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR6_MASK			(0x00000040u)
+#define OMAPL_MCASP_PFUNC_AXR6_SHIFT			(0x00000006u)
+#define OMAPL_MCASP_PFUNC_AXR6_RESETVAL			(0x00000000u)
+/* AXR6 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR6_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR6_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR5_MASK			(0x00000020u)
+#define OMAPL_MCASP_PFUNC_AXR5_SHIFT			(0x00000005u)
+#define OMAPL_MCASP_PFUNC_AXR5_RESETVAL			(0x00000000u)
+/* AXR5 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR5_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR5_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR4_MASK			(0x00000010u)
+#define OMAPL_MCASP_PFUNC_AXR4_SHIFT			(0x00000004u)
+#define OMAPL_MCASP_PFUNC_AXR4_RESETVAL			(0x00000000u)
+/* AXR4 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR4_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR4_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR3_MASK			(0x00000008u)
+#define OMAPL_MCASP_PFUNC_AXR3_SHIFT			(0x00000003u)
+#define OMAPL_MCASP_PFUNC_AXR3_RESETVAL			(0x00000000u)
+/* AXR3 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR3_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR3_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR2_MASK			(0x00000004u)
+#define OMAPL_MCASP_PFUNC_AXR2_SHIFT			(0x00000002u)
+#define OMAPL_MCASP_PFUNC_AXR2_RESETVAL			(0x00000000u)
+/* AXR2 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR2_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR2_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR1_MASK			(0x00000002u)
+#define OMAPL_MCASP_PFUNC_AXR1_SHIFT			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_AXR1_RESETVAL			(0x00000000u)
+/* AXR1 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR1_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR1_GPIO			(0x00000001u)
+
+#define OMAPL_MCASP_PFUNC_AXR0_MASK			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_AXR0_SHIFT			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR0_RESETVAL			(0x00000000u)
+/* AXR0 Tokens */
+#define OMAPL_MCASP_PFUNC_AXR0_MCASP			(0x00000000u)
+#define OMAPL_MCASP_PFUNC_AXR0_GPIO			(0x00000001u)
+#define OMAPL_MCASP_PFUNC_RESETVAL			(0x00000000u)
+
+#define OMAPL_MCASP_PDIR_AFSR_MASK			(0x80000000u)
+#define OMAPL_MCASP_PDIR_AFSR_SHIFT			(0x0000001Fu)
+#define OMAPL_MCASP_PDIR_AFSR_RESETVAL			(0x00000000u)
+/* AFSR Tokens */
+#define OMAPL_MCASP_PDIR_AFSR_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AFSR_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AHCLKR_MASK			(0x40000000u)
+#define OMAPL_MCASP_PDIR_AHCLKR_SHIFT			(0x0000001Eu)
+#define OMAPL_MCASP_PDIR_AHCLKR_RESETVAL		(0x00000000u)
+/* AHCLKR Tokens */
+#define OMAPL_MCASP_PDIR_AHCLKR_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AHCLKR_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_ACLKR_MASK			(0x20000000u)
+#define OMAPL_MCASP_PDIR_ACLKR_SHIFT			(0x0000001Du)
+#define OMAPL_MCASP_PDIR_ACLKR_RESETVAL			(0x00000000u)
+/* ACLKR Tokens */
+#define OMAPL_MCASP_PDIR_ACLKR_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_ACLKR_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AFSX_MASK			(0x10000000u)
+#define OMAPL_MCASP_PDIR_AFSX_SHIFT			(0x0000001Cu)
+#define OMAPL_MCASP_PDIR_AFSX_RESETVAL			(0x00000000u)
+/* AFSX Tokens */
+#define OMAPL_MCASP_PDIR_AFSX_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AFSX_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AHCLKX_MASK			(0x08000000u)
+#define OMAPL_MCASP_PDIR_AHCLKX_SHIFT			(0x0000001Bu)
+#define OMAPL_MCASP_PDIR_AHCLKX_RESETVAL		(0x00000000u)
+/* AHCLKX Tokens */
+#define OMAPL_MCASP_PDIR_AHCLKX_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AHCLKX_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_ACLKX_MASK			(0x04000000u)
+#define OMAPL_MCASP_PDIR_ACLKX_SHIFT			(0x0000001Au)
+#define OMAPL_MCASP_PDIR_ACLKX_RESETVAL			(0x00000000u)
+/* ACLKX Tokens */
+#define OMAPL_MCASP_PDIR_ACLKX_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_ACLKX_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AMUTE_MASK			(0x02000000u)
+#define OMAPL_MCASP_PDIR_AMUTE_SHIFT			(0x00000019u)
+#define OMAPL_MCASP_PDIR_AMUTE_RESETVAL			(0x00000000u)
+/* AMUTE Tokens */
+#define OMAPL_MCASP_PDIR_AMUTE_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AMUTE_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR15_MASK			(0x00008000u)
+#define OMAPL_MCASP_PDIR_AXR15_SHIFT			(0x0000000Fu)
+#define OMAPL_MCASP_PDIR_AXR15_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR15_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR15_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR14_MASK			(0x00004000u)
+#define OMAPL_MCASP_PDIR_AXR14_SHIFT			(0x0000000Eu)
+#define OMAPL_MCASP_PDIR_AXR14_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR14_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR14_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR13_MASK			(0x00002000u)
+#define OMAPL_MCASP_PDIR_AXR13_SHIFT			(0x0000000Du)
+#define OMAPL_MCASP_PDIR_AXR13_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR13_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR13_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR12_MASK			(0x00001000u)
+#define OMAPL_MCASP_PDIR_AXR12_SHIFT			(0x0000000Cu)
+#define OMAPL_MCASP_PDIR_AXR12_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR12_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR12_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR11_MASK			(0x00000800u)
+#define OMAPL_MCASP_PDIR_AXR11_SHIFT			(0x0000000Bu)
+#define OMAPL_MCASP_PDIR_AXR11_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR11_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR11_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR10_MASK			(0x00000400u)
+#define OMAPL_MCASP_PDIR_AXR10_SHIFT			(0x0000000Au)
+#define OMAPL_MCASP_PDIR_AXR10_RESETVAL			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR10_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR10_OUTPUT			(0x00000001u)
+#define OMAPL_MCASP_PDIR_AXR9_MASK			(0x00000200u)
+#define OMAPL_MCASP_PDIR_AXR9_SHIFT			(0x00000009u)
+#define OMAPL_MCASP_PDIR_AXR9_RESETVAL			(0x00000000u)
+/* AXR9 Tokens */
+#define OMAPL_MCASP_PDIR_AXR9_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR9_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR8_MASK			(0x00000100u)
+#define OMAPL_MCASP_PDIR_AXR8_SHIFT			(0x00000008u)
+#define OMAPL_MCASP_PDIR_AXR8_RESETVAL			(0x00000000u)
+/* AXR8 Tokens */
+#define OMAPL_MCASP_PDIR_AXR8_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR8_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR7_MASK			(0x00000080u)
+#define OMAPL_MCASP_PDIR_AXR7_SHIFT			(0x00000007u)
+#define OMAPL_MCASP_PDIR_AXR7_RESETVAL			(0x00000000u)
+/*----AXR7 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR7_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR7_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR6_MASK			(0x00000040u)
+#define OMAPL_MCASP_PDIR_AXR6_SHIFT			(0x00000006u)
+#define OMAPL_MCASP_PDIR_AXR6_RESETVAL			(0x00000000u)
+/*----AXR6 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR6_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR6_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR5_MASK			(0x00000020u)
+#define OMAPL_MCASP_PDIR_AXR5_SHIFT			(0x00000005u)
+#define OMAPL_MCASP_PDIR_AXR5_RESETVAL			(0x00000000u)
+/*----AXR5 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR5_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR5_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR4_MASK			(0x00000010u)
+#define OMAPL_MCASP_PDIR_AXR4_SHIFT			(0x00000004u)
+#define OMAPL_MCASP_PDIR_AXR4_RESETVAL			(0x00000000u)
+/*----AXR4 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR4_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR4_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR3_MASK			(0x00000008u)
+#define OMAPL_MCASP_PDIR_AXR3_SHIFT			(0x00000003u)
+#define OMAPL_MCASP_PDIR_AXR3_RESETVAL			(0x00000000u)
+/*----AXR3 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR3_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR3_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR2_MASK			(0x00000004u)
+#define OMAPL_MCASP_PDIR_AXR2_SHIFT			(0x00000002u)
+#define OMAPL_MCASP_PDIR_AXR2_RESETVAL			(0x00000000u)
+/*----AXR2 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR2_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR2_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR1_MASK			(0x00000002u)
+#define OMAPL_MCASP_PDIR_AXR1_SHIFT			(0x00000001u)
+#define OMAPL_MCASP_PDIR_AXR1_RESETVAL			(0x00000000u)
+/*----AXR1 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR1_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR1_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_AXR0_MASK			(0x00000001u)
+#define OMAPL_MCASP_PDIR_AXR0_SHIFT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR0_RESETVAL			(0x00000000u)
+/*----AXR0 Tokens----*/
+#define OMAPL_MCASP_PDIR_AXR0_INPUT			(0x00000000u)
+#define OMAPL_MCASP_PDIR_AXR0_OUTPUT			(0x00000001u)
+
+#define OMAPL_MCASP_PDIR_RESETVAL			(0x00000000u)
+
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_MASK			(0x00000080u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_SHIFT		(0x00000007u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_RESETVAL		(0x00000000u)
+/*----CLKXP Tokens----*/
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_RISINGEDGE		(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXP_FALLINGEDGE		(0x00000001u)
+
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_MASK			(0x00000040u)
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_SHIFT		(0x00000006u)
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_RESETVAL		(0x00000001u)
+/*----ASYNC Tokens----*/
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_SYNC			(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_ASYNC_ASYNC		(0x00000001u)
+
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_MASK			(0x00000020u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_SHIFT		(0x00000005u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_RESETVAL		(0x00000001u)
+/*----CLKXM Tokens----*/
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_EXTERNAL		(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXM_INTERNAL		(0x00000001u)
+
+#define OMAPL_MCASP_ACLKXCTL_CLKXDIV_MASK		(0x0000001Fu)
+#define OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT		(0x00000000u)
+#define OMAPL_MCASP_ACLKXCTL_CLKXDIV_RESETVAL		(0x00000000u)
+
+#define OMAPL_MCASP_ACLKXCTL_RESETVAL			(0x00000060u)
+
+/* AHCLKXCTL */
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_MASK		(0x00008000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_SHIFT		(0x0000000Fu)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_RESETVAL		(0x00000001u)
+/*----HCLKXM Tokens----*/
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_EXTERNAL		(0x00000000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXM_INTERNAL		(0x00000001u)
+
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_MASK		(0x00004000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_SHIFT		(0x0000000Eu)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_RESETVAL		(0x00000000u)
+/*----HCLKXP Tokens----*/
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_NOTINVERTED	(0x00000000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXP_INVERTED		(0x00000001u)
+
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_MASK		(0x00000FFFu)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT		(0x00000000u)
+#define OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_RESETVAL		(0x00000000u)
+
+#define OMAPL_MCASP_AHCLKXCTL_RESETVAL			(0x00008000u)
+
+#define MCASP_SUART_GBLCTL				(0X00000000)
+#define MCASP_SUART_RGBLCTL				(0X00000000)
+#define MCASP_SUART_XGBLCTL				(0X00000000)
+#define MCASP_SUART_RMASK_8				(0x000000FF)
+#define MCASP_SUART_RMASK_16				(0x0000FFFF)
+#define MCASP_SUART_RFMT_8				(0x0000A038)
+#define MCASP_SUART_RFMT_16				(0x0000A078)
+#define MCASP_SUART_FSRM				(0X00000002)
+#define MCASP_SUART_CLKRM_CLKRP				(0X000000A0)
+#define MCASP_SUART_HCLKRP				(0X00008000)
+#define MCASP_SUART_RTDMS0				(0X00000001)
+#define MCASP_SUART_RSYNCERR				(0X00000002)
+#define MCASP_SUART_RMAX_RPS_256			(0x00FF0008)
+#define MCASP_SUART_XMASK_0_31				(0X0000FFFF)
+#define MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0		(0x00002078)
+#define MCASP_SUART_FSXM				(0x00000002)
+#define MCASP_SUART_CLKXM_ASYNC_CLKXP			(0x000000E0)
+#define MCASP_SUART_HCLKXM				(0x00008000)
+#define MCASP_SUART_XTDMS0				(0X00000001)
+#define MCASP_SUART_XSYNCERR				(0x00000002)
+#define MCASP_SUART_XMAX_XPS_256			(0x00FF0008)
+#define MCASP_SUART_SRCTL_DISMOD			(0x0000000c)
+#define MCASP_SUART_DIT_DISABLE				(0X00000000)
+#define MCASP_SUART_LOOPBACK_DISABLE			(0x00000000)
+#define MCASP_SUART_AMUTE_DISABLE			(0X00000000)
+#define MCASP_SUART_XSTAT				(0x0000FFFF)
+#define MCASP_SUART_RSTAT				(0x0000FFFF)
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
new file mode 100644
index 0000000..c2aa9d7
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra at mistralsolutions.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.
+ */
+
+#ifndef _SUART_PRU_REGS_H_
+#define _SUART_PRU_REGS_H_
+
+#include <linux/types.h>
+
+/** PRU0 DATA RAM base address */
+#define PRU0_DATARAM_OFFSET		(0x0000u)
+/** PRU1 DATA RAM base address */
+#define PRU1_DATARAM_OFFSET		(0x2000u)
+
+/** PRU0 DATA RAM size */
+#define PRU0_DATARAM_SIZE		(0x200u)
+/** PRU1 DATA RAM size */
+#define PRU1_DATARAM_SIZE		(0x200u)
+
+#define PRU_SUART_PRU0_CH0_OFFSET	(0x0000)
+#define PRU_SUART_PRU0_CH1_OFFSET	(0x0010)
+#define PRU_SUART_PRU0_CH2_OFFSET	(0x0020)
+#define PRU_SUART_PRU0_CH3_OFFSET	(0x0030)
+#define PRU_SUART_PRU0_CH4_OFFSET	(0x0040)
+#define PRU_SUART_PRU0_CH5_OFFSET	(0x0050)
+#define PRU_SUART_PRU0_CH6_OFFSET	(0x0060)
+#define PRU_SUART_PRU0_CH7_OFFSET	(0x0070)
+#define PRU_SUART_PRU0_IMR_OFFSET	(0x0080)
+/** Interrupt Mask Register */
+#define PRU_SUART_PRU0_ISR_OFFSET	(0x0082)
+/** Interrupt Status Register */
+#define PRU_SUART_PRU0_ID_ADDR		(0x0084)
+/** PRU ID Register */
+#define PRU_SUART_PRU0_RX_TX_MODE	(0x0085)
+#define PRU_SUART_PRU0_DELAY_OFFSET	(0x0086)
+#define PRU_SUART_PRU0_IDLE_TIMEOUT_OFFSET	(0x0088)
+
+/* ********* PRU 1 Macros ************* */
+#define PRU_SUART_PRU1_CH0_OFFSET	(0x2000)
+#define PRU_SUART_PRU1_CH1_OFFSET	(0x2010)
+#define PRU_SUART_PRU1_CH2_OFFSET	(0x2020)
+#define PRU_SUART_PRU1_CH3_OFFSET	(0x2030)
+#define PRU_SUART_PRU1_CH4_OFFSET	(0x2040)
+#define PRU_SUART_PRU1_CH5_OFFSET	(0x2050)
+#define PRU_SUART_PRU1_CH6_OFFSET	(0x2060)
+#define PRU_SUART_PRU1_CH7_OFFSET	(0x2070)
+#define PRU_SUART_PRU1_IMR_OFFSET	(0x2080)
+#define PRU_SUART_PRU1_ISR_OFFSET	(0x2082)
+#define PRU_SUART_PRU1_ID_ADDR		(0x2084)
+#define PRU_SUART_PRU1_RX_TX_MODE	(0x2085)
+#define PRU_SUART_PRU1_DELAY_OFFSET	(0x2086)
+#define PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET	(0x2088)
+
+/* SUART Channel Control Register bit descriptions */
+#define PRU_SUART_CH_CTRL_MODE_SHIFT		0x0000
+#define PRU_SUART_CH_CTRL_MODE_MASK		0x0003
+#define PRU_SUART_CH_CTRL_TX_MODE		0x0001
+#define PRU_SUART_CH_CTRL_RX_MODE		0x0002
+
+/* Service Request */
+#define PRU_SUART_CH_CTRL_SREQ_SHIFT		0x0002
+#define PRU_SUART_CH_CTRL_SREQ_MASK		0x0004
+#define PRU_SUART_CH_CTRL_SREQ			0x0001
+
+/* McASP Instance */
+#define PRU_SUART_CH_CTRL_MCASP_SHIFT		0x0003
+#define PRU_SUART_CH_CTRL_MCASP_MASK		0x0018
+#define PRU_SUART_CH_CTRL_SR_SHIFT		0x0008
+#define PRU_SUART_CH_CTRL_SR_MASK		0x0F00
+
+/* SUART channel configuration1 register descriptions */
+
+/* clock divisor -  relative baud value */
+#define PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT	0x0000
+#define PRU_SUART_CH_CONFIG1_DIVISOR_MASK	0x03FF
+/* oversampling */
+#define PRU_SUART_CH_CONFIG1_OVS_SHIFT		0x000A
+#define PRU_SUART_CH_CONFIG1_OVS_MASK		0x0C00
+
+/* SUART channel configuration2 register descriptions */
+/* Bits per character */
+#define PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT	0x0000
+#define PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK	0x000F
+
+/* Bits per character */
+#define PRU_SUART_CH_CONFIG2_DATALEN_SHIFT	0x0008
+#define PRU_SUART_CH_CONFIG2_DATALEN_MASK	0x0F00
+
+/* SUART Channel register offsets */
+#define PRU_SUART_CH_CTRL_OFFSET		0x00
+#define PRU_SUART_CH_CONFIG1_OFFSET		0x02
+#define PRU_SUART_CH_CONFIG2_OFFSET		0x04
+#define PRU_SUART_CH_TXRXSTATUS_OFFSET		0x06
+#define PRU_SUART_CH_TXRXDATA_OFFSET		0x08
+#define PRU_SUART_CH_BYTESDONECNTR_OFFSET	0x0C
+
+/* SUART Event Numbers macros */
+#define PRU_SUART0_TX_EVT	34
+#define PRU_SUART0_RX_EVT	35
+#define PRU_SUART1_TX_EVT	36
+#define PRU_SUART1_RX_EVT	37
+#define PRU_SUART2_TX_EVT	38
+#define PRU_SUART2_RX_EVT	39
+#define PRU_SUART3_TX_EVT	40
+#define PRU_SUART3_RX_EVT	41
+#define PRU_SUART4_TX_EVT	42
+#define PRU_SUART4_RX_EVT	43
+#define PRU_SUART5_TX_EVT	44
+#define PRU_SUART5_RX_EVT	45
+#define PRU_SUART6_TX_EVT	46
+#define PRU_SUART6_RX_EVT	47
+#define PRU_SUART7_TX_EVT	48
+#define PRU_SUART7_RX_EVT	49
+
+#define PRU_SUART0_TX_EVT_BIT	BIT(2)
+#define PRU_SUART0_RX_EVT_BIT	BIT(3)
+#define PRU_SUART1_TX_EVT_BIT	BIT(4)
+#define PRU_SUART1_RX_EVT_BIT	BIT(5)
+#define PRU_SUART2_TX_EVT_BIT	BIT(6)
+#define PRU_SUART2_RX_EVT_BIT	BIT(7)
+#define PRU_SUART3_TX_EVT_BIT	BIT(8)
+#define PRU_SUART3_RX_EVT_BIT	BIT(9)
+#define PRU_SUART4_TX_EVT_BIT	BIT(10)
+#define PRU_SUART4_RX_EVT_BIT	BIT(11)
+#define PRU_SUART5_TX_EVT_BIT	BIT(12)
+#define PRU_SUART5_RX_EVT_BIT	BIT(13)
+#define PRU_SUART6_TX_EVT_BIT	BIT(14)
+#define PRU_SUART6_RX_EVT_BIT	BIT(15)
+#define PRU_SUART7_TX_EVT_BIT	BIT(16)
+#define PRU_SUART7_RX_EVT_BIT	BIT(17)
+
+/*
+ *  SUART Config regs
+ */
+typedef struct {
+	u16 chn_ctrl;
+	u16 chn_config1;
+	u16 chn_config2;
+	u16 chn_txrx_status;
+	u32 chn_txrx_data;
+} suart_struct_pru_regs;
+
+#endif
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
new file mode 100644
index 0000000..7ced423
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: Jitendra Kumar <jitendra@mistralsolutions.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/mfd/pruss/da8xx_pru.h>
+#include "pruss_suart_mcasp.h"
+#include "pruss_suart_api.h"
+#include "pruss_suart_regs.h"
+#include "pruss_suart_board.h"
+#include "pruss_suart_utils.h"
+#include "pruss_suart_err.h"
+
+
+#define SUART_TRX_DIV_CONF_SZ	4
+
+static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+			pruss_suart_iomap *pruss_ioaddr);
+static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value, u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr);
+
+/*
+ * Lookup table for TX baud rate
+ * The divisor value is calculated using the formula
+ *
+ * ACLKX = (AUXCLK)/(CLKXDIV * HCLKXDIV)
+ *
+ * Where
+ *		CLKXDIV takes values from 1-32
+ *		HCLKXDIV takes values from 1-4096
+ * Here
+ *		AUXCLK = 24MHz
+ */
+u32 lt_tx_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+	/*BaudRate,	Divisor,	CLKXDIV,HCLKXDIV */
+	{300,		80000,		24,		3200},
+	{600,		40000,		15,		2500},
+	{1800,		13333,		10,		1212},
+	{2400,		10000,		4,		2000},
+	{4800,		5000,		1,		2500},
+	{7200,		3333,		0,		3333},
+	{9600,		2500,		0,		2500},
+	{14400,		1666,		0,		1666},
+	{19200,		1250,		0,		1250},
+	{38400,		625,		0,		625},
+	{57600,		416,		0,		416},
+	{115200,	208,		0,		208},
+	{230400,	104,		0,		104}
+};
+
+/*
+ * Lookup table for RX baud rate for 8 bit oversampling
+ * The divisor value is calculated using the formula
+ *
+ *	ACLKR = (AUXCLK)/(CLKRDIV * HCLKRDIV) * Oversampling
+ *
+ * Where
+ *		CLKRDIV takes values from 1-32
+ *		HCLKRDIV takes values from 1-4096
+ * Here
+ *		AUXCLK = 24MHz
+ */
+u32 lt_rx_8x_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+/* BaudRate,	Divisor,	CLKXDIV,	HCLKXDIV */
+	{300,		10000,		4,		2000},
+	{600,		5000,		1,		2500},
+	{1800,		1667,		0,		1667},
+	{2400,		1250,		0,		1250},
+	{7200,		417,		0,		417},
+	{4800,		625,		0,		625},
+	{9600,		312,		0,		312},
+	{14400,		208,		0,		208},
+	{19200,		156,		0,		156},
+	{38400,		78,		0,		78},
+	{57600,		52,		0,		52},
+	{115200,	26,		0,		26},
+	{230400,	13,		0,		13}
+};
+
+/*
+ * Lookup table for RX baud rate for 16 bit oversampling
+ * The divisor value is calculated using the formula
+ *
+ *	ACLKR = (AUXCLK)/(CLKRDIV * HCLKRDIV) * Oversampling
+ *
+ * Where
+ *		CLKRDIV takes values from 1-32
+ *		HCLKRDIV takes values from 1-4096
+ * Here
+ *		AUXCLK = 24MHz
+ */
+u32 lt_rx_16x_baud_rate[][SUART_TRX_DIV_CONF_SZ] = {
+/*BaudRate,	Divisor,	CLKXDIV,	HCLKXDIV */
+	{300,		5000,		1,		2500},
+	{600,		2500,		0,		2500},
+	{1800,		833,		0,		833},
+	{2400,		625,		0,		625},
+	{4800,		312,		0,		312},
+	{7200,		208,		0,		208},
+	{9600,		156,		0,		156},
+	{14400,		104,		0,		104},
+	{19200,		78,		0,		78},
+	{38400,		39,		0,		39},
+	{57600,		26,		0,		26},
+	{115200,	13,		0,		13},
+	{230400,	6,		0,		6}
+};
+
+/*
+ * McASP configuration routine
+ */
+void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value,
+			u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr)
+{
+	omapl_mcasp_regs_ovly mcasp0_regs =
+		(omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	/* reset mcasp */
+	__raw_writel(MCASP_SUART_GBLCTL, &mcasp0_regs->GBLCTL);
+	__raw_writel(MCASP_SUART_RGBLCTL, &mcasp0_regs->RGBLCTL);
+	__raw_writel(MCASP_SUART_XGBLCTL, &mcasp0_regs->XGBLCTL);
+
+	/* configure receive registers */
+	if ((SUART_8X_OVRSMPL == oversampling) || (0 == oversampling)) {
+		__raw_writel(MCASP_SUART_RMASK_8, &mcasp0_regs->RMASK);
+		__raw_writel(MCASP_SUART_RFMT_8, &mcasp0_regs->RFMT);
+	}
+	if (SUART_16X_OVRSMPL == oversampling) {
+		__raw_writel(MCASP_SUART_RMASK_16, &mcasp0_regs->RMASK);
+		__raw_writel(MCASP_SUART_RFMT_16, &mcasp0_regs->RFMT);
+
+	}
+
+	__raw_writel(MCASP_SUART_FSRM, &mcasp0_regs->AFSRCTL);
+	__raw_writel(MCASP_SUART_CLKRM_CLKRP, &mcasp0_regs->ACLKRCTL);
+	__raw_writel(MCASP_SUART_HCLKRP, &mcasp0_regs->AHCLKRCTL);
+	suart_mcasp_rx_baud_set(rx_baud_value, oversampling, pruss_ioaddr);
+	__raw_writel(MCASP_SUART_RTDMS0, &mcasp0_regs->RTDM);
+	__raw_writel(MCASP_SUART_RSYNCERR, &mcasp0_regs->RINTCTL);
+	__raw_writel(MCASP_SUART_RMAX_RPS_256, &mcasp0_regs->RCLKCHK);
+
+	/* configure transmit registers. */
+	__raw_writel(MCASP_SUART_XMASK_0_31, &mcasp0_regs->XMASK);
+	__raw_writel(MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0, &mcasp0_regs->XFMT);
+	__raw_writel(MCASP_SUART_FSXM, &mcasp0_regs->AFSXCTL);
+	__raw_writel(MCASP_SUART_CLKXM_ASYNC_CLKXP, &mcasp0_regs->ACLKXCTL);
+	__raw_writel(MCASP_SUART_HCLKXM, &mcasp0_regs->AHCLKXCTL);
+
+	suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
+	__raw_writel(MCASP_SUART_XTDMS0, &mcasp0_regs->XTDM);
+	__raw_writel(MCASP_SUART_XSYNCERR, &mcasp0_regs->XINTCTL);
+	__raw_writel(MCASP_SUART_XMAX_XPS_256, &mcasp0_regs->XCLKCHK);
+
+	/* Serializer as a transmitter */
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL0);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL1);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL2);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL3);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL4);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL5);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL6);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL7);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL8);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL9);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL10);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL11);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL12);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL13);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL14);
+	__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL15);
+
+	/* Configure all AXR[n] as McASP pins  */
+
+	/*
+	 *  Setting  all TX MCASP AXR[n] Pin mapped to Even Serializer number
+	 *  (0,2,4,6,8,10,12,14) to GPIO Mode by default. During setting the
+	 *  serializer to TX mode in PRU assembly code, the MCASP AXR[n] Pin
+	 *  would get configured to MCASP mode of operation,
+	 *  before Actual Data Transfer
+	 */
+
+	/* Setting  all TX Pin to GPIO Mode by default */
+	temp_reg = (OMAPL_MCASP_PFUNC_RESETVAL) |
+	    (1 << PRU_SUART0_CONFIG_TX_SER) | (1 << PRU_SUART1_CONFIG_TX_SER) |
+	    (1 << PRU_SUART2_CONFIG_TX_SER) | (1 << PRU_SUART3_CONFIG_TX_SER) |
+	    (1 << PRU_SUART4_CONFIG_TX_SER) | (1 << PRU_SUART5_CONFIG_TX_SER) |
+	    (1 << PRU_SUART6_CONFIG_TX_SER) | (1 << PRU_SUART7_CONFIG_TX_SER);
+	__raw_writel(temp_reg, &mcasp0_regs->PFUNC);
+
+	__raw_writel(0xFFF, &mcasp0_regs->PDOUT);
+
+	/* config pin function and direction */
+	__raw_writel(0x00000000, &mcasp0_regs->PDIR);
+	temp_reg =
+	    (1 << PRU_SUART0_CONFIG_TX_SER) | (1 << PRU_SUART1_CONFIG_TX_SER) |
+	    (1 << PRU_SUART2_CONFIG_TX_SER) | (1 << PRU_SUART3_CONFIG_TX_SER) |
+	    (1 << PRU_SUART4_CONFIG_TX_SER) | (1 << PRU_SUART5_CONFIG_TX_SER) |
+	    (1 << PRU_SUART6_CONFIG_TX_SER) | (1 << PRU_SUART7_CONFIG_TX_SER) |
+	    (MCASP_PDIR_VAL);
+	__raw_writel(temp_reg, &mcasp0_regs->PDIR);
+
+	__raw_writel(MCASP_SUART_DIT_DISABLE, &mcasp0_regs->DITCTL);
+	__raw_writel(MCASP_SUART_LOOPBACK_DISABLE, &mcasp0_regs->DLBCTL);
+	__raw_writel(MCASP_SUART_AMUTE_DISABLE, &mcasp0_regs->AMUTE);
+
+	__raw_writel(MCASP_SUART_XSTAT, &mcasp0_regs->XSTAT);
+	__raw_writel(MCASP_SUART_RSTAT, &mcasp0_regs->RSTAT);
+}
+
+void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+		pruss_suart_iomap *pruss_ioaddr)
+{
+	omapl_mcasp_regs_ovly mcasp0_regs =
+	    (omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+	temp_reg = mcasp0_regs->PFUNC | (0x1 << serializer_num);
+	__raw_writel(temp_reg, &mcasp0_regs->PFUNC);
+}
+
+/*
+ * mcasp TX buard rate setting routine
+ */
+s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+		pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val;
+	u32 loop_cnt;
+	s16 status = SUART_SUCCESS;
+	s16 found_val = SUART_FALSE;
+
+	omapl_mcasp_regs_ovly mcasp0_regs =
+	    (omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	/* Search the supported baud rate in the table */
+	for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+							loop_cnt++) {
+		if (tx_baud_value == lt_tx_baud_rate[loop_cnt][0]) {
+			found_val = SUART_TRUE;
+			break;
+		}
+	}
+	if (found_val == SUART_TRUE) {
+		clk_div_val = lt_tx_baud_rate[loop_cnt][2];
+		temp_reg = mcasp0_regs->ACLKXCTL |
+			clk_div_val << OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT;
+		__raw_writel(temp_reg, &mcasp0_regs->ACLKXCTL);
+		clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+		temp_reg = mcasp0_regs->AHCLKXCTL |
+			clk_div_val << OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT;
+		__raw_writel(temp_reg, &mcasp0_regs->AHCLKXCTL);
+	} else {
+		return SUART_INVALID_TX_BAUD;
+	}
+	return status;
+}
+
+/*
+ * mcasp RX buard rate setting routine
+ */
+s16 suart_mcasp_rx_baud_set(u32 rx_baud_value,
+	u32 oversampling, pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val;
+	u32 loop_cnt;
+	s16 status = SUART_SUCCESS;
+	s16 found_val = SUART_FALSE;
+
+	omapl_mcasp_regs_ovly mcasp0_regs =
+	    (omapl_mcasp_regs_ovly) pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	if (oversampling == SUART_8X_OVRSMPL) {
+		for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+		     loop_cnt++) {
+			if (rx_baud_value == lt_rx_8x_baud_rate[loop_cnt][0]) {
+				clk_div_val = lt_rx_8x_baud_rate[loop_cnt][2];
+				temp_reg = mcasp0_regs->ACLKRCTL | (clk_div_val
+					<< OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+
+				__raw_writel(temp_reg, &mcasp0_regs->ACLKRCTL);
+
+				clk_div_val =
+				lt_rx_8x_baud_rate[loop_cnt][3] - 1;
+
+				temp_reg = mcasp0_regs->AHCLKRCTL | (clk_div_val
+				<< OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+
+				__raw_writel(temp_reg, &mcasp0_regs->AHCLKRCTL);
+
+				found_val = SUART_TRUE;
+				break;
+			}
+		}
+	} else if (oversampling == SUART_16X_OVRSMPL) {
+		for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+		     loop_cnt++) {
+			if (rx_baud_value == lt_rx_16x_baud_rate[loop_cnt][0]) {
+				clk_div_val = lt_rx_16x_baud_rate[loop_cnt][2];
+				temp_reg =
+					mcasp0_regs->ACLKRCTL | (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->ACLKRCTL);
+				clk_div_val = lt_rx_16x_baud_rate[loop_cnt][3];
+				temp_reg =
+				mcasp0_regs->AHCLKRCTL | (clk_div_val <<
+				OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->AHCLKRCTL);
+				found_val = SUART_TRUE;
+				break;
+			}
+		}
+	} else if (oversampling == 0) {
+		for (loop_cnt = 0; loop_cnt < SUART_NUM_OF_BAUDS_SUPPORTED;
+		     loop_cnt++) {
+			if (rx_baud_value == lt_tx_baud_rate[loop_cnt][0]) {
+				clk_div_val = lt_tx_baud_rate[loop_cnt][2];
+				temp_reg =
+				mcasp0_regs->ACLKRCTL | (clk_div_val <<
+				OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->ACLKRCTL);
+				clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+				temp_reg =
+				mcasp0_regs->AHCLKRCTL | (clk_div_val <<
+				OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				__raw_writel(temp_reg, &mcasp0_regs->AHCLKRCTL);
+				found_val = SUART_TRUE;
+				break;
+			}
+		}
+	} else {
+		return SUART_INVALID_OVERSAMPLING;
+	}
+
+	if (found_val != SUART_TRUE)
+		return SUART_INVALID_RX_BAUD;
+
+	return status;
+}
+
+/*
+ * mcasp buard rate setting routine
+ */
+s16 suart_asp_baud_set(u32 tx_baud_value, u32 rx_baud_value, u32 oversampling,
+					pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = SUART_SUCCESS;
+
+	status = suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
+	status = suart_mcasp_rx_baud_set(rx_baud_value, oversampling,
+					pruss_ioaddr);
+
+	return status;
+}
+
+/*
+ * mcasp deactivate the selected serializer
+ */
+s16 suart_asp_serializer_deactivate(u16 u16sr_num,
+		pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = SUART_SUCCESS;
+	omapl_mcasp_regs_ovly mcasp0_regs = (omapl_mcasp_regs_ovly)
+				pruss_ioaddr->mcasp_io_addr;
+	if (u16sr_num > 15)
+		status = SUART_INVALID_SR_NUM;
+	else
+		__raw_writel(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->SRCTL0);
+
+	return status;
+}
diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
new file mode 100644
index 0000000..7839eb6
--- /dev/null
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Author: jitendra at mistralsolutions.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.
+ */
+
+#ifndef _SUART_UTILS_H_
+#define _SUART_UTILS_H_
+
+#include <linux/types.h>
+
+/* ************ Serializers ***************** */
+#define PRU_SUART_SERIALIZER_0		(0u)
+#define PRU_SUART_SERIALIZER_1		(1u)
+#define PRU_SUART_SERIALIZER_2		(2u)
+#define PRU_SUART_SERIALIZER_3		(3u)
+#define PRU_SUART_SERIALIZER_4		(4u)
+#define PRU_SUART_SERIALIZER_5		(5u)
+#define PRU_SUART_SERIALIZER_6		(6u)
+#define PRU_SUART_SERIALIZER_7		(7u)
+#define PRU_SUART_SERIALIZER_8		(8u)
+#define PRU_SUART_SERIALIZER_9		(9u)
+#define PRU_SUART_SERIALIZER_10		(10u)
+#define PRU_SUART_SERIALIZER_11		(11u)
+#define PRU_SUART_SERIALIZER_12		(12u)
+#define PRU_SUART_SERIALIZER_13		(13u)
+#define PRU_SUART_SERIALIZER_14		(14u)
+#define PRU_SUART_SERIALIZER_15		(15u)
+#define PRU_SUART_SERIALIZER_NONE	(16u)
+
+/* Total number of baud rates supported */
+#define SUART_NUM_OF_BAUDS_SUPPORTED	13
+
+#define MCASP_PDIR_VAL ( \
+	OMAPL_MCASP_PDIR_AFSR_OUTPUT<<OMAPL_MCASP_PDIR_AFSR_SHIFT | \
+	OMAPL_MCASP_PDIR_AHCLKR_OUTPUT<<OMAPL_MCASP_PDIR_AHCLKR_SHIFT | \
+	OMAPL_MCASP_PDIR_ACLKR_OUTPUT<<OMAPL_MCASP_PDIR_ACLKR_SHIFT | \
+	OMAPL_MCASP_PDIR_AFSX_OUTPUT<<OMAPL_MCASP_PDIR_AFSX_SHIFT | \
+	OMAPL_MCASP_PDIR_AHCLKX_OUTPUT<<OMAPL_MCASP_PDIR_AHCLKX_SHIFT | \
+	OMAPL_MCASP_PDIR_ACLKX_OUTPUT<<OMAPL_MCASP_PDIR_ACLKX_SHIFT)
+
+extern void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_baud_set(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_serializer_deactivate(u16 u16sr_num,
+			pruss_suart_iomap *pruss_ioaddr);
+
+extern void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+			pruss_suart_iomap *pruss_ioaddr);
+#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 758c5b0..eae37fe 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -202,6 +202,8 @@
 /* VIA VT8500 SoC */
 #define PORT_VT8500	97
 
+#define PORT_DA8XX_PRU_SUART	98
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 157+ 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 20:33     ` Wolfgang Grandegger
@ 2011-02-11 15:06     ` Kurt Van Dijck
  1 sibling, 0 replies; 157+ messages in thread
From: Kurt Van Dijck @ 2011-02-11 15:06 UTC (permalink / raw)
  To: Subhasish Ghosh
  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

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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-11 15:06     ` Kurt Van Dijck
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-11 15:06     ` Kurt Van Dijck
  0 siblings, 0 replies; 157+ messages in thread
From: Kurt Van Dijck @ 2011-02-11 15:06 UTC (permalink / raw)
  To: linux-arm-kernel

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] 157+ 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 20:33     ` Wolfgang Grandegger
@ 2011-02-11 15:20     ` Kurt Van Dijck
  1 sibling, 0 replies; 157+ messages in thread
From: Kurt Van Dijck @ 2011-02-11 15:20 UTC (permalink / raw)
  To: Subhasish Ghosh
  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

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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-11 15:20     ` Kurt Van Dijck
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-11 15:20     ` Kurt Van Dijck
  0 siblings, 0 replies; 157+ messages in thread
From: Kurt Van Dijck @ 2011-02-11 15:20 UTC (permalink / raw)
  To: linux-arm-kernel

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] 157+ messages in thread

* Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 15:26     ` Michael Williamson
  -1 siblings, 0 replies; 157+ messages in thread
From: Michael Williamson @ 2011-02-11 15:26 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	open list, m-watkins, linux-arm-kernel

Hi Subhasish,

On 2/11/2011 9:51 AM, Subhasish Ghosh wrote:

> This patch adds the pruss SUART pin mux and registers the device
> with the pruss mfd driver.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
>  arch/arm/mach-davinci/board-da850-evm.c |   36 +++++++++++++++++++++++++++++++
>  1 files changed, 36 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index f9c38f8..3858516 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {
>  	-1
>  };
>  
> +const short da850_evm_pruss_suart_pins[] = {
> +	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
> +	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
> +	DA850_AXR_13, DA850_AXR_9, DA850_AXR_7,
> +	DA850_AXR_14, DA850_AXR_10, DA850_AXR_8,
> +	-1
> +};
> +


Shouldn't this pins select PRU[0,1]_XXX type functions and not McASP functions?
E.G.: PRU0_R31[17] instead of AHCLKX, PRU0_R31[18] instead of AHCLKR, etc.

> +static int __init da850_evm_setup_pruss_suart(void)
> +{
> +	int ret;
> +
> +	ret = davinci_cfg_reg_list(da850_evm_pruss_suart_pins);
> +	if (ret)
> +		pr_warning("%s: da850_evm_pruss_suart_pins "
> +			"mux setup failed: %d\n", __func__, ret);
> +	return ret;
> +}
> +
>  static int __init da850_evm_setup_pruss_can(void)
>  {
>  	int ret, val = 0;
> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>  	return ret;
>  }
>  
> +static struct da850_evm_pruss_suart_data suart_data = {
> +	.version	= 1,
> +	.resource	= {
> +			.name	= "da8xx_mcasp0_iomem",
> +			.start	= DAVINCI_DA8XX_MCASP0_REG_BASE,
> +			.end	= DAVINCI_DA8XX_MCASP0_REG_BASE +
> +					(SZ_1K * 12) - 1,
> +			.flags	= IORESOURCE_MEM,
> +		},
> +};
> +
>  static struct da8xx_pruss_can_data can_data = {
>  	.version	= 1,
>  };
> @@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] = {
>  		.dev_name	= "da8xx_pruss_can",
>  		.pdata		= &can_data,
>  		.pdata_size	= sizeof(can_data),
> +		.setup		= da850_evm_setup_pruss_suart,


Should this be da850_evm_setup_pruss_can instead?

> +	},
> +	{
> +		.dev_name	= "da8xx_pruss_uart",
> +		.pdata		= &suart_data,
> +		.pdata_size	= sizeof(suart_data),
>  		.setup		= da850_evm_setup_pruss_can,


Should this be da850_evm_setup_pruss_suart instead?

>  	},
>  	{


-Mike


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

* [PATCH v2 11/13] da850: pruss SUART board specific additions.
@ 2011-02-11 15:26     ` Michael Williamson
  0 siblings, 0 replies; 157+ messages in thread
From: Michael Williamson @ 2011-02-11 15:26 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Subhasish,

On 2/11/2011 9:51 AM, Subhasish Ghosh wrote:

> This patch adds the pruss SUART pin mux and registers the device
> with the pruss mfd driver.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
>  arch/arm/mach-davinci/board-da850-evm.c |   36 +++++++++++++++++++++++++++++++
>  1 files changed, 36 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index f9c38f8..3858516 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {
>  	-1
>  };
>  
> +const short da850_evm_pruss_suart_pins[] = {
> +	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
> +	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
> +	DA850_AXR_13, DA850_AXR_9, DA850_AXR_7,
> +	DA850_AXR_14, DA850_AXR_10, DA850_AXR_8,
> +	-1
> +};
> +


Shouldn't this pins select PRU[0,1]_XXX type functions and not McASP functions?
E.G.: PRU0_R31[17] instead of AHCLKX, PRU0_R31[18] instead of AHCLKR, etc.

> +static int __init da850_evm_setup_pruss_suart(void)
> +{
> +	int ret;
> +
> +	ret = davinci_cfg_reg_list(da850_evm_pruss_suart_pins);
> +	if (ret)
> +		pr_warning("%s: da850_evm_pruss_suart_pins "
> +			"mux setup failed: %d\n", __func__, ret);
> +	return ret;
> +}
> +
>  static int __init da850_evm_setup_pruss_can(void)
>  {
>  	int ret, val = 0;
> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>  	return ret;
>  }
>  
> +static struct da850_evm_pruss_suart_data suart_data = {
> +	.version	= 1,
> +	.resource	= {
> +			.name	= "da8xx_mcasp0_iomem",
> +			.start	= DAVINCI_DA8XX_MCASP0_REG_BASE,
> +			.end	= DAVINCI_DA8XX_MCASP0_REG_BASE +
> +					(SZ_1K * 12) - 1,
> +			.flags	= IORESOURCE_MEM,
> +		},
> +};
> +
>  static struct da8xx_pruss_can_data can_data = {
>  	.version	= 1,
>  };
> @@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] = {
>  		.dev_name	= "da8xx_pruss_can",
>  		.pdata		= &can_data,
>  		.pdata_size	= sizeof(can_data),
> +		.setup		= da850_evm_setup_pruss_suart,


Should this be da850_evm_setup_pruss_can instead?

> +	},
> +	{
> +		.dev_name	= "da8xx_pruss_uart",
> +		.pdata		= &suart_data,
> +		.pdata_size	= sizeof(suart_data),
>  		.setup		= da850_evm_setup_pruss_can,


Should this be da850_evm_setup_pruss_suart instead?

>  	},
>  	{


-Mike

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 16:28     ` Alan Cox
  -1 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-02-11 16:28 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list

Don't see why it needs its own sub-directory



> +#ifdef __SUART_DEBUG
> +#define __suart_debug(fmt, args...) \
> +		printk(KERN_DEBUG "suart_debug: " fmt, ## args)
> +#else
> +#define __suart_debug(fmt, args...)
> +#endif
> +
> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## args)

Use dev_dbg/dev_err/pr_debug/pr_err


> +static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
> +{
> +	struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
> +	struct device *dev = soft_uart->dev;
> +	s32 count = 0;
> +
> +	if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
> +		return;
> +
> +	if (down_trylock(&soft_uart->port_sem[uart_no]))
> +		return;

Please use a mutex not a semaphore. We are trying to get almost all the
kernel using mutexes as it is needed for hard real time.


> +		pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
> +				       suart_data, data_len + 1,
> +				       &data_len_read);
> +
> +		for (i = 0; i <= data_len_read; i++) {
> +			soft_uart->port[uart_no].icount.rx++;
> +			/* check for sys rq */
> +			if (uart_handle_sysrq_char
> +			    (&soft_uart->port[uart_no], suart_data))
> +				continue;
> +		}
> +		/* update the tty data structure */
> +		tty_insert_flip_string(tty, suart_data, data_len_read);

You can avoid a copy here by using tty_prepare_flip_string()

Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty
refcounting is right


> +static void pruss_suart_set_termios(struct uart_port *port,
> +				  struct ktermios *termios,
> +				  struct ktermios *old)
> +{
> +	struct omapl_pru_suart *soft_uart =
> +	    container_of(port, struct omapl_pru_suart, port[port->line]);
> +	struct device *dev = soft_uart->dev;
> +	u8 cval = 0;
> +	unsigned long flags = 0;
> +	u32 baud = 0;
> +	u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
> +
> +/*
> + * Do not allow unsupported configurations to be set
> + */
> +	if (1) {
> +		termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
> +				      | PARENB | PARODD | CMSPAR);
> +		termios->c_cflag |= CLOCAL;

No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them
even if in fact they have no effect, so leave those two alone. The rest
is fine.


> +/*
> + * Characteres to ignore

Typo



> diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
> new file mode 100644
> index 0000000..d809dd3
> --- /dev/null
> +++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
> @@ -0,0 +1,2350 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
> +#include <linux/mfd/pruss/da8xx_pru.h>
> +#include <linux/io.h>
> +#include <mach/hardware.h>
> +#include "pruss_suart_api.h"
> +#include "pruss_suart_regs.h"
> +#include "pruss_suart_board.h"
> +#include "pruss_suart_utils.h"
> +#include "pruss_suart_err.h"
> +
> +static u8 g_uart_statu_table[8];
Can you lose the g_, its  a windows naming convention we dont use


> +s16 pru_softuart_open(suart_handle h_suart)
> +{

If you just used normal integers you could surely make this routine
trivial and remove all the duplication in the switches

> +	s16 status = PRU_SUART_SUCCESS;

And please stick to Linux error codes


> +/* suart instance close routine */
> +s16 pru_softuart_close(suart_handle h_uart)
> +{
> +	s16 status = SUART_SUCCESS;
> +
> +	if (h_uart == NULL) {
> +		return PRU_SUART_ERR_HANDLE_INVALID;

Which is never checked. Far better to use WARN_ON and the like for such
cases - or if like this one they don't appear to be possible to simply
delete them

> +	if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
> +		return SUART_INVALID_CLKDIVISOR;
> +	if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
> +		return SUART_INVALID_CLKDIVISOR;

[minor] Lots of excess brackets


> +		u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
> +		u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
> +		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
> +		if (-1 == s16retval)
> +			return -1;

If you fixed the API here you'd be able to just write

		if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF,
				PRU_INTC_BLAH)

or similar which would clean up a lot of messy code and shrink it
dramatically. Given you have lots of series of writes some kind of

	pruss_writel_multi(dev, array, len)

that took an array of addr/value pairs might also clean up a ton of code
and turn it into trivial tables


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-11 16:28     ` Alan Cox
  0 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-02-11 16:28 UTC (permalink / raw)
  To: linux-arm-kernel

Don't see why it needs its own sub-directory



> +#ifdef __SUART_DEBUG
> +#define __suart_debug(fmt, args...) \
> +		printk(KERN_DEBUG "suart_debug: " fmt, ## args)
> +#else
> +#define __suart_debug(fmt, args...)
> +#endif
> +
> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## args)

Use dev_dbg/dev_err/pr_debug/pr_err


> +static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
> +{
> +	struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
> +	struct device *dev = soft_uart->dev;
> +	s32 count = 0;
> +
> +	if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
> +		return;
> +
> +	if (down_trylock(&soft_uart->port_sem[uart_no]))
> +		return;

Please use a mutex not a semaphore. We are trying to get almost all the
kernel using mutexes as it is needed for hard real time.


> +		pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
> +				       suart_data, data_len + 1,
> +				       &data_len_read);
> +
> +		for (i = 0; i <= data_len_read; i++) {
> +			soft_uart->port[uart_no].icount.rx++;
> +			/* check for sys rq */
> +			if (uart_handle_sysrq_char
> +			    (&soft_uart->port[uart_no], suart_data))
> +				continue;
> +		}
> +		/* update the tty data structure */
> +		tty_insert_flip_string(tty, suart_data, data_len_read);

You can avoid a copy here by using tty_prepare_flip_string()

Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty
refcounting is right


> +static void pruss_suart_set_termios(struct uart_port *port,
> +				  struct ktermios *termios,
> +				  struct ktermios *old)
> +{
> +	struct omapl_pru_suart *soft_uart =
> +	    container_of(port, struct omapl_pru_suart, port[port->line]);
> +	struct device *dev = soft_uart->dev;
> +	u8 cval = 0;
> +	unsigned long flags = 0;
> +	u32 baud = 0;
> +	u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
> +
> +/*
> + * Do not allow unsupported configurations to be set
> + */
> +	if (1) {
> +		termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
> +				      | PARENB | PARODD | CMSPAR);
> +		termios->c_cflag |= CLOCAL;

No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them
even if in fact they have no effect, so leave those two alone. The rest
is fine.


> +/*
> + * Characteres to ignore

Typo



> diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
> new file mode 100644
> index 0000000..d809dd3
> --- /dev/null
> +++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
> @@ -0,0 +1,2350 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
> +#include <linux/mfd/pruss/da8xx_pru.h>
> +#include <linux/io.h>
> +#include <mach/hardware.h>
> +#include "pruss_suart_api.h"
> +#include "pruss_suart_regs.h"
> +#include "pruss_suart_board.h"
> +#include "pruss_suart_utils.h"
> +#include "pruss_suart_err.h"
> +
> +static u8 g_uart_statu_table[8];
Can you lose the g_, its  a windows naming convention we dont use


> +s16 pru_softuart_open(suart_handle h_suart)
> +{

If you just used normal integers you could surely make this routine
trivial and remove all the duplication in the switches

> +	s16 status = PRU_SUART_SUCCESS;

And please stick to Linux error codes


> +/* suart instance close routine */
> +s16 pru_softuart_close(suart_handle h_uart)
> +{
> +	s16 status = SUART_SUCCESS;
> +
> +	if (h_uart == NULL) {
> +		return PRU_SUART_ERR_HANDLE_INVALID;

Which is never checked. Far better to use WARN_ON and the like for such
cases - or if like this one they don't appear to be possible to simply
delete them

> +	if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
> +		return SUART_INVALID_CLKDIVISOR;
> +	if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
> +		return SUART_INVALID_CLKDIVISOR;

[minor] Lots of excess brackets


> +		u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
> +		u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
> +		s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
> +		if (-1 == s16retval)
> +			return -1;

If you fixed the API here you'd be able to just write

		if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF,
				PRU_INTC_BLAH)

or similar which would clean up a lot of messy code and shrink it
dramatically. Given you have lots of series of writes some kind of

	pruss_writel_multi(dev, array, len)

that took an array of addr/value pairs might also clean up a ton of code
and turn it into trivial tables

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

* Re: [PATCH v2 02/13] da850: pruss platform specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 18:41     ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:41 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi,
	Kevin Hilman (supporter:TI DAVINCI
	MACHIN...,commit_signer:16/18=89%),
	Russell King (maintainer:ARM PORT),
	Michael Williamson (commit_signer:5/18=28%),
	Cyril Chemparathy (commit_signer:3/18=17%),
	Sergei Shtylyov (commit_signer:3/18=17%),
	open list

Hello.

Subhasish Ghosh wrote:

> This patch adds the platform device and assignes the platform resources
> for the PRUSS mfd driver.

    You also add the PRUSS clock (and I would have done that as a separate patch).

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>

    You should have noted the patch dependency here -- this patch depends on the 
one nenaming DA8XX_LPSC0_DMAX.

WBR, Sergei

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

* [PATCH v2 02/13] da850: pruss platform specific additions.
@ 2011-02-11 18:41     ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

Subhasish Ghosh wrote:

> This patch adds the platform device and assignes the platform resources
> for the PRUSS mfd driver.

    You also add the PRUSS clock (and I would have done that as a separate patch).

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>

    You should have noted the patch dependency here -- this patch depends on the 
one nenaming DA8XX_LPSC0_DMAX.

WBR, Sergei

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

* Re: [PATCH v2 03/13] da850: pruss board specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 18:43     ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:43 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	open list, m-watkins, linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds board specific initializations and setup routines.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
[...]

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index 11f986b..242d1ed 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)
>  static __init int da850_evm_init_cpufreq(void) { return 0; }
>  #endif
>  
> +static struct da8xx_pruss_devices pruss_devices[] = {
> +	{.dev_name = NULL,},

    No need to explicitly initialize to NULL.

WBR, Sergei


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

* [PATCH v2 03/13] da850: pruss board specific additions.
@ 2011-02-11 18:43     ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:43 UTC (permalink / raw)
  To: linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds board specific initializations and setup routines.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
[...]

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index 11f986b..242d1ed 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)
>  static __init int da850_evm_init_cpufreq(void) { return 0; }
>  #endif
>  
> +static struct da8xx_pruss_devices pruss_devices[] = {
> +	{.dev_name = NULL,},

    No need to explicitly initialize to NULL.

WBR, Sergei

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

* Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 18:45     ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:45 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds the pruss CAN pin mux and registers the device
> with the pruss mfd driver.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
[...]

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index 242d1ed..2ce5536 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
[...]
>  static struct da8xx_pruss_devices pruss_devices[] = {
> -	{.dev_name = NULL,},
> +	{
> +		.dev_name	= "da8xx_pruss_can",
> +		.pdata		= &can_data,
> +		.pdata_size	= sizeof(can_data),
> +		.setup		= da850_evm_setup_pruss_can,
> +	},
> +	{
> +		.dev_name	= NULL,
> +	},

    No need to explicitly initialize to NULL.

WBR, Sergei

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

* [PATCH v2 06/13] da850: pruss CAN board specific additions.
@ 2011-02-11 18:45     ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds the pruss CAN pin mux and registers the device
> with the pruss mfd driver.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
[...]

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index 242d1ed..2ce5536 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
[...]
>  static struct da8xx_pruss_devices pruss_devices[] = {
> -	{.dev_name = NULL,},
> +	{
> +		.dev_name	= "da8xx_pruss_can",
> +		.pdata		= &can_data,
> +		.pdata_size	= sizeof(can_data),
> +		.setup		= da850_evm_setup_pruss_can,
> +	},
> +	{
> +		.dev_name	= NULL,
> +	},

    No need to explicitly initialize to NULL.

WBR, Sergei

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

* Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 18:47     ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:47 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	Thomas Koeller, nsekhar, open list, Victor Rodriguez,
	Cyril Chemparathy, m-watkins, linux-arm-kernel

Hello.

Subhasish Ghosh wrote:

> This patch adds the GPIOs for the pruss CAN device.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>

    I still think this patch should be merged with patch 5, and patch 8 with 
patch 6...

WBR, Sergei

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

* [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
@ 2011-02-11 18:47     ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

Subhasish Ghosh wrote:

> This patch adds the GPIOs for the pruss CAN device.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>

    I still think this patch should be merged with patch 5, and patch 8 with 
patch 6...

WBR, Sergei

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

* Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 18:50     ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:50 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds the pruss SUART pin mux and registers the device
> with the pruss mfd driver.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
>  arch/arm/mach-davinci/board-da850-evm.c |   36 +++++++++++++++++++++++++++++++
>  1 files changed, 36 insertions(+), 0 deletions(-)

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index f9c38f8..3858516 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
[...]
> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>  	return ret;
>  }
>  
> +static struct da850_evm_pruss_suart_data suart_data = {
> +	.version	= 1,
> +	.resource	= {
> +			.name	= "da8xx_mcasp0_iomem",
> +			.start	= DAVINCI_DA8XX_MCASP0_REG_BASE,
> +			.end	= DAVINCI_DA8XX_MCASP0_REG_BASE +
> +					(SZ_1K * 12) - 1,
> +			.flags	= IORESOURCE_MEM,
> +		},
> +};
> +

    I don't think passing a resource thru platform data is good idea... 
Resources should be bound to the platform device.

WBR, Sergei

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

* [PATCH v2 11/13] da850: pruss SUART board specific additions.
@ 2011-02-11 18:50     ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:50 UTC (permalink / raw)
  To: linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds the pruss SUART pin mux and registers the device
> with the pruss mfd driver.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
>  arch/arm/mach-davinci/board-da850-evm.c |   36 +++++++++++++++++++++++++++++++
>  1 files changed, 36 insertions(+), 0 deletions(-)

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index f9c38f8..3858516 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
[...]
> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>  	return ret;
>  }
>  
> +static struct da850_evm_pruss_suart_data suart_data = {
> +	.version	= 1,
> +	.resource	= {
> +			.name	= "da8xx_mcasp0_iomem",
> +			.start	= DAVINCI_DA8XX_MCASP0_REG_BASE,
> +			.end	= DAVINCI_DA8XX_MCASP0_REG_BASE +
> +					(SZ_1K * 12) - 1,
> +			.flags	= IORESOURCE_MEM,
> +		},
> +};
> +

    I don't think passing a resource thru platform data is good idea... 
Resources should be bound to the platform device.

WBR, Sergei

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

* Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-11 18:55     ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:55 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds the McASP clock alias.
> The alias is used by the pruss suart driver
> for enabling the McASP PSC.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
[...]

> diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
> index e15de72..f1cf605 100644
> --- a/arch/arm/mach-davinci/devices-da8xx.c
> +++ b/arch/arm/mach-davinci/devices-da8xx.c
> @@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {
>  
>  int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
>  {
> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE

    #ifdef's in the function body are generally fromned upon.

> +	int ret;
> +#endif
> +

    This line should have been inside #ifdef...

>  	da8xx_pruss_dev.dev.platform_data = pruss_device;
> +
> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE

    Why not do it before assigning the platform data and avoid extra #ifdef?

> +	ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
> +	NULL, &da850_mcasp_device.dev);

    This line should be indented more to the right.

> +	if (ret < 0)
> +		return ret;
> +#endif

WBR, Sergei

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

* [PATCH v2 12/13] da850: pruss SUART platform specific additions.
@ 2011-02-11 18:55     ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-11 18:55 UTC (permalink / raw)
  To: linux-arm-kernel

Subhasish Ghosh wrote:

> This patch adds the McASP clock alias.
> The alias is used by the pruss suart driver
> for enabling the McASP PSC.

> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
[...]

> diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
> index e15de72..f1cf605 100644
> --- a/arch/arm/mach-davinci/devices-da8xx.c
> +++ b/arch/arm/mach-davinci/devices-da8xx.c
> @@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {
>  
>  int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
>  {
> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE

    #ifdef's in the function body are generally fromned upon.

> +	int ret;
> +#endif
> +

    This line should have been inside #ifdef...

>  	da8xx_pruss_dev.dev.platform_data = pruss_device;
> +
> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE

    Why not do it before assigning the platform data and avoid extra #ifdef?

> +	ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
> +	NULL, &da850_mcasp_device.dev);

    This line should be indented more to the right.

> +	if (ret < 0)
> +		return ret;
> +#endif

WBR, Sergei

^ permalink raw reply	[flat|nested] 157+ 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 20:33     ` Wolfgang Grandegger
  2011-02-11 21:33     ` Marc Kleine-Budde
  1 sibling, 0 replies; 157+ 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] 157+ 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 20:33     ` Wolfgang Grandegger
@ 2011-02-11 21:33     ` Marc Kleine-Budde
  1 sibling, 0 replies; 157+ 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] 157+ 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
  -1 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-14  4:54       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-14  4:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

I had a discussion regarding this with Wolfgang:

http://www.mail-archive.com/socketcan-users at 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] 157+ 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
  -1 siblings, 2 replies; 157+ 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  7:23       ` Wolfgang Grandegger
@ 2011-02-14  7:42             ` Kurt Van Dijck
  2011-02-14  8:45           ` Subhasish Ghosh
  1 sibling, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-14  7:42             ` Kurt Van Dijck
  0 siblings, 0 replies; 157+ messages in thread
From: Kurt Van Dijck @ 2011-02-14  7:42 UTC (permalink / raw)
  To: linux-arm-kernel

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 at 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.
> 
> Using SysFS files would already be much better.
Ack.

Kurt

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  7:23       ` Wolfgang Grandegger
@ 2011-02-14  8:45           ` Subhasish Ghosh
  2011-02-14  8:45           ` Subhasish Ghosh
  1 sibling, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-14  8:45           ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-14  8:45 UTC (permalink / raw)
  To: linux-arm-kernel

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 at 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] 157+ 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
  -1 siblings, 0 replies; 157+ 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14  8:45           ` Subhasish Ghosh
  (?)
  (?)
@ 2011-02-14  9:35           ` Marc Kleine-Budde
  2011-02-14 13:15               ` Subhasish Ghosh
  -1 siblings, 1 reply; 157+ 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-14 13:15               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-14 13:15 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Wolfgang Grandegger, 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

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@pengutronix.de>
Sent: Monday, February 14, 2011 3:05 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: "Wolfgang Grandegger" <wg@grandegger.com>; "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.

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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-14 13:15               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-14 13:15               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-14 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

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@pengutronix.de>
Sent: Monday, February 14, 2011 3:05 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: "Wolfgang Grandegger" <wg@grandegger.com>; "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.

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] 157+ 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
  -1 siblings, 0 replies; 157+ 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-14 13:15               ` Subhasish Ghosh
                                 ` (2 preceding siblings ...)
  (?)
@ 2011-02-14 13:42               ` Wolfgang Grandegger
  -1 siblings, 0 replies; 157+ 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  7:07       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:07 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

--------------------------------------------------
From: "Kurt Van Dijck" <kurt.van.dijck@eia.be>
Sent: Friday, February 11, 2011 8:50 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.

> 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  7:07       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  7:07       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:07 UTC (permalink / raw)
  To: linux-arm-kernel

--------------------------------------------------
From: "Kurt Van Dijck" <kurt.van.dijck@eia.be>
Sent: Friday, February 11, 2011 8:50 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.

> 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] 157+ messages in thread

* Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
  2011-02-11 15:26     ` Michael Williamson
@ 2011-02-18  7:13       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:13 UTC (permalink / raw)
  To: Michael Williamson
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	open list, m-watkins, linux-arm-kernel

--------------------------------------------------
From: "Michael Williamson" <michael.williamson@criticallink.com>
Sent: Friday, February 11, 2011 8:56 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.

> Hi Subhasish,
>
> On 2/11/2011 9:51 AM, Subhasish Ghosh wrote:
>
>> This patch adds the pruss SUART pin mux and registers the device
>> with the pruss mfd driver.
>>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>> ---
>>  arch/arm/mach-davinci/board-da850-evm.c |   36 
>> +++++++++++++++++++++++++++++++
>>  1 files changed, 36 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index f9c38f8..3858516 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {
>>  -1
>>  };
>>
>> +const short da850_evm_pruss_suart_pins[] = {
>> + DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
>> + DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
>> + DA850_AXR_13, DA850_AXR_9, DA850_AXR_7,
>> + DA850_AXR_14, DA850_AXR_10, DA850_AXR_8,
>> + -1
>> +};
>> +
>
>
> Shouldn't this pins select PRU[0,1]_XXX type functions and not McASP 
> functions?
> E.G.: PRU0_R31[17] instead of AHCLKX, PRU0_R31[18] instead of AHCLKR, etc.
>

SG - The Soft-UART implementation uses the McASP as shift registers to push 
out the data sequentially.
            Hence, we configure the McASP PINS and not the PRU PINS.

>> +static int __init da850_evm_setup_pruss_suart(void)
>> +{
>> + int ret;
>> +
>> + ret = davinci_cfg_reg_list(da850_evm_pruss_suart_pins);
>> + if (ret)
>> + pr_warning("%s: da850_evm_pruss_suart_pins "
>> + "mux setup failed: %d\n", __func__, ret);
>> + return ret;
>> +}
>> +
>>  static int __init da850_evm_setup_pruss_can(void)
>>  {
>>  int ret, val = 0;
>> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>>  return ret;
>>  }
>>
>> +static struct da850_evm_pruss_suart_data suart_data = {
>> + .version = 1,
>> + .resource = {
>> + .name = "da8xx_mcasp0_iomem",
>> + .start = DAVINCI_DA8XX_MCASP0_REG_BASE,
>> + .end = DAVINCI_DA8XX_MCASP0_REG_BASE +
>> + (SZ_1K * 12) - 1,
>> + .flags = IORESOURCE_MEM,
>> + },
>> +};
>> +
>>  static struct da8xx_pruss_can_data can_data = {
>>  .version = 1,
>>  };
>> @@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] 
>> = {
>>  .dev_name = "da8xx_pruss_can",
>>  .pdata = &can_data,
>>  .pdata_size = sizeof(can_data),
>> + .setup = da850_evm_setup_pruss_suart,
>
>
> Should this be da850_evm_setup_pruss_can instead?

SG - This just the way the patch is displayed. In the code the order is 
correct.

>
>> + },
>> + {
>> + .dev_name = "da8xx_pruss_uart",
>> + .pdata = &suart_data,
>> + .pdata_size = sizeof(suart_data),
>>  .setup = da850_evm_setup_pruss_can,
>
>
> Should this be da850_evm_setup_pruss_suart instead?
SG - Ditto
>
>>  },
>>  {
>
>
> -Mike
> 

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

* [PATCH v2 11/13] da850: pruss SUART board specific additions.
@ 2011-02-18  7:13       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:13 UTC (permalink / raw)
  To: linux-arm-kernel

--------------------------------------------------
From: "Michael Williamson" <michael.williamson@criticallink.com>
Sent: Friday, February 11, 2011 8:56 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.

> Hi Subhasish,
>
> On 2/11/2011 9:51 AM, Subhasish Ghosh wrote:
>
>> This patch adds the pruss SUART pin mux and registers the device
>> with the pruss mfd driver.
>>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>> ---
>>  arch/arm/mach-davinci/board-da850-evm.c |   36 
>> +++++++++++++++++++++++++++++++
>>  1 files changed, 36 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index f9c38f8..3858516 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1060,6 +1060,25 @@ const short da850_evm_pruss_can_pins[] = {
>>  -1
>>  };
>>
>> +const short da850_evm_pruss_suart_pins[] = {
>> + DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
>> + DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
>> + DA850_AXR_13, DA850_AXR_9, DA850_AXR_7,
>> + DA850_AXR_14, DA850_AXR_10, DA850_AXR_8,
>> + -1
>> +};
>> +
>
>
> Shouldn't this pins select PRU[0,1]_XXX type functions and not McASP 
> functions?
> E.G.: PRU0_R31[17] instead of AHCLKX, PRU0_R31[18] instead of AHCLKR, etc.
>

SG - The Soft-UART implementation uses the McASP as shift registers to push 
out the data sequentially.
            Hence, we configure the McASP PINS and not the PRU PINS.

>> +static int __init da850_evm_setup_pruss_suart(void)
>> +{
>> + int ret;
>> +
>> + ret = davinci_cfg_reg_list(da850_evm_pruss_suart_pins);
>> + if (ret)
>> + pr_warning("%s: da850_evm_pruss_suart_pins "
>> + "mux setup failed: %d\n", __func__, ret);
>> + return ret;
>> +}
>> +
>>  static int __init da850_evm_setup_pruss_can(void)
>>  {
>>  int ret, val = 0;
>> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>>  return ret;
>>  }
>>
>> +static struct da850_evm_pruss_suart_data suart_data = {
>> + .version = 1,
>> + .resource = {
>> + .name = "da8xx_mcasp0_iomem",
>> + .start = DAVINCI_DA8XX_MCASP0_REG_BASE,
>> + .end = DAVINCI_DA8XX_MCASP0_REG_BASE +
>> + (SZ_1K * 12) - 1,
>> + .flags = IORESOURCE_MEM,
>> + },
>> +};
>> +
>>  static struct da8xx_pruss_can_data can_data = {
>>  .version = 1,
>>  };
>> @@ -1094,6 +1124,12 @@ static struct da8xx_pruss_devices pruss_devices[] 
>> = {
>>  .dev_name = "da8xx_pruss_can",
>>  .pdata = &can_data,
>>  .pdata_size = sizeof(can_data),
>> + .setup = da850_evm_setup_pruss_suart,
>
>
> Should this be da850_evm_setup_pruss_can instead?

SG - This just the way the patch is displayed. In the code the order is 
correct.

>
>> + },
>> + {
>> + .dev_name = "da8xx_pruss_uart",
>> + .pdata = &suart_data,
>> + .pdata_size = sizeof(suart_data),
>>  .setup = da850_evm_setup_pruss_can,
>
>
> Should this be da850_evm_setup_pruss_suart instead?
SG - Ditto
>
>>  },
>>  {
>
>
> -Mike
> 

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

* Re: [PATCH v2 02/13] da850: pruss platform specific additions.
  2011-02-11 18:41     ` Sergei Shtylyov
@ 2011-02-18  7:18       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:18 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi,
	Kevin Hilman (supporter:TI DAVINCI
	MACHIN...,commit_signer:16/18=89%),
	Russell King (maintainer:ARM PORT),
	Michael Williamson (commit_signer:5/18=28%),
	Cyril Chemparathy (commit_signer:3/18=17%),
	Sergei Shtylyov (commit_signer:3/18=17%),
	open list

--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:11 AM
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>; "Kevin Hilman (supporter:TI 
DAVINCI MACHIN...,commit_signer:16/18=89%)" <khilman@deeprootsystems.com>; 
"Russell King (maintainer:ARM PORT)" <linux@arm.linux.org.uk>; "Michael 
Williamson (commit_signer:5/18=28%)" <michael.williamson@criticallink.com>; 
"Cyril Chemparathy (commit_signer:3/18=17%)" <cyril@ti.com>; "Sergei 
Shtylyov (commit_signer:3/18=17%)" <sshtylyov@ru.mvista.com>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 02/13] da850: pruss platform specific additions.

> Hello.
>
> Subhasish Ghosh wrote:
>
>> This patch adds the platform device and assignes the platform resources
>> for the PRUSS mfd driver.
>
>    You also add the PRUSS clock (and I would have done that as a separate 
> patch).
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>
>    You should have noted the patch dependency here -- this patch depends 
> on the one nenaming DA8XX_LPSC0_DMAX.

SG - Will do
>
> WBR, Sergei 


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

* [PATCH v2 02/13] da850: pruss platform specific additions.
@ 2011-02-18  7:18       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:18 UTC (permalink / raw)
  To: linux-arm-kernel

--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:11 AM
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>; "Kevin Hilman (supporter:TI 
DAVINCI MACHIN...,commit_signer:16/18=89%)" <khilman@deeprootsystems.com>; 
"Russell King (maintainer:ARM PORT)" <linux@arm.linux.org.uk>; "Michael 
Williamson (commit_signer:5/18=28%)" <michael.williamson@criticallink.com>; 
"Cyril Chemparathy (commit_signer:3/18=17%)" <cyril@ti.com>; "Sergei 
Shtylyov (commit_signer:3/18=17%)" <sshtylyov@ru.mvista.com>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 02/13] da850: pruss platform specific additions.

> Hello.
>
> Subhasish Ghosh wrote:
>
>> This patch adds the platform device and assignes the platform resources
>> for the PRUSS mfd driver.
>
>    You also add the PRUSS clock (and I would have done that as a separate 
> patch).
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>
>    You should have noted the patch dependency here -- this patch depends 
> on the one nenaming DA8XX_LPSC0_DMAX.

SG - Will do
>
> WBR, Sergei 

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

* Re: [PATCH v2 03/13] da850: pruss board specific additions.
  2011-02-11 18:43     ` Sergei Shtylyov
@ 2011-02-18  7:18       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:18 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	open list, m-watkins, linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:13 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 03/13] da850: pruss board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds board specific initializations and setup routines.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index 11f986b..242d1ed 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)
>>  static __init int da850_evm_init_cpufreq(void) { return 0; }
>>  #endif
>>  +static struct da8xx_pruss_devices pruss_devices[] = {
>> + {.dev_name = NULL,},
>
>    No need to explicitly initialize to NULL.
>
SG - Ok, Will remove

> WBR, Sergei
> 

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

* [PATCH v2 03/13] da850: pruss board specific additions.
@ 2011-02-18  7:18       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:18 UTC (permalink / raw)
  To: linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:13 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 03/13] da850: pruss board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds board specific initializations and setup routines.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index 11f986b..242d1ed 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1053,6 +1053,26 @@ static __init int da850_evm_init_cpufreq(void)
>>  static __init int da850_evm_init_cpufreq(void) { return 0; }
>>  #endif
>>  +static struct da8xx_pruss_devices pruss_devices[] = {
>> + {.dev_name = NULL,},
>
>    No need to explicitly initialize to NULL.
>
SG - Ok, Will remove

> WBR, Sergei
> 

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

* Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
  2011-02-11 18:45     ` Sergei Shtylyov
@ 2011-02-18  7:19       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:19 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:15 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the pruss CAN pin mux and registers the device
>> with the pruss mfd driver.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index 242d1ed..2ce5536 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
> [...]
>>  static struct da8xx_pruss_devices pruss_devices[] = {
>> - {.dev_name = NULL,},
>> + {
>> + .dev_name = "da8xx_pruss_can",
>> + .pdata = &can_data,
>> + .pdata_size = sizeof(can_data),
>> + .setup = da850_evm_setup_pruss_can,
>> + },
>> + {
>> + .dev_name = NULL,
>> + },
>
>    No need to explicitly initialize to NULL.

SG -- ok, Will remove
>
> WBR, Sergei 


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

* Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.
  2011-02-11 18:45     ` Sergei Shtylyov
@ 2011-02-18  7:19       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:19 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:15 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the pruss CAN pin mux and registers the device
>> with the pruss mfd driver.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index 242d1ed..2ce5536 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
> [...]
>>  static struct da8xx_pruss_devices pruss_devices[] = {
>> - {.dev_name = NULL,},
>> + {
>> + .dev_name = "da8xx_pruss_can",
>> + .pdata = &can_data,
>> + .pdata_size = sizeof(can_data),
>> + .setup = da850_evm_setup_pruss_can,
>> + },
>> + {
>> + .dev_name = NULL,
>> + },
>
>    No need to explicitly initialize to NULL.

SG -- ok, Will remove
>
> WBR, Sergei 


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

* [PATCH v2 06/13] da850: pruss CAN board specific additions.
@ 2011-02-18  7:19       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:19 UTC (permalink / raw)
  To: linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:15 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the pruss CAN pin mux and registers the device
>> with the pruss mfd driver.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index 242d1ed..2ce5536 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
> [...]
>>  static struct da8xx_pruss_devices pruss_devices[] = {
>> - {.dev_name = NULL,},
>> + {
>> + .dev_name = "da8xx_pruss_can",
>> + .pdata = &can_data,
>> + .pdata_size = sizeof(can_data),
>> + .setup = da850_evm_setup_pruss_can,
>> + },
>> + {
>> + .dev_name = NULL,
>> + },
>
>    No need to explicitly initialize to NULL.

SG -- ok, Will remove
>
> WBR, Sergei 

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

* [PATCH v2 06/13] da850: pruss CAN board specific additions.
@ 2011-02-18  7:19       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:19 UTC (permalink / raw)
  To: linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:15 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 06/13] da850: pruss CAN board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the pruss CAN pin mux and registers the device
>> with the pruss mfd driver.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index 242d1ed..2ce5536 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
>> @@ -1053,8 +1053,43 @@ static __init int da850_evm_init_cpufreq(void)
> [...]
>>  static struct da8xx_pruss_devices pruss_devices[] = {
>> - {.dev_name = NULL,},
>> + {
>> + .dev_name = "da8xx_pruss_can",
>> + .pdata = &can_data,
>> + .pdata_size = sizeof(can_data),
>> + .setup = da850_evm_setup_pruss_can,
>> + },
>> + {
>> + .dev_name = NULL,
>> + },
>
>    No need to explicitly initialize to NULL.

SG -- ok, Will remove
>
> WBR, Sergei 

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

* Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
  2011-02-11 18:47     ` Sergei Shtylyov
@ 2011-02-18  7:20       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:20 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	Thomas Koeller, nsekhar, open list, Victor Rodriguez,
	Cyril Chemparathy, m-watkins, linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:17 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "Thomas Koeller" 
<thomas.koeller@baslerweb.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; "Victor Rodriguez" <vm.rod25@gmail.com>; 
"Cyril Chemparathy" <cyril@ti.com>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for 
gpios.

> Hello.
>
> Subhasish Ghosh wrote:
>
>> This patch adds the GPIOs for the pruss CAN device.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>
>    I still think this patch should be merged with patch 5, and patch 8 
> with patch 6...
>
SG -- Ok, Will do.

> WBR, Sergei 


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

* [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios.
@ 2011-02-18  7:20       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  7:20 UTC (permalink / raw)
  To: linux-arm-kernel



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:17 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "Thomas Koeller" 
<thomas.koeller@baslerweb.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; "Victor Rodriguez" <vm.rod25@gmail.com>; 
"Cyril Chemparathy" <cyril@ti.com>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 07/13] da850: pruss CAN platform specific changes for 
gpios.

> Hello.
>
> Subhasish Ghosh wrote:
>
>> This patch adds the GPIOs for the pruss CAN device.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>
>    I still think this patch should be merged with patch 5, and patch 8 
> with patch 6...
>
SG -- Ok, Will do.

> WBR, Sergei 

^ permalink raw reply	[flat|nested] 157+ 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
  2011-02-18  8:15           ` Subhasish Ghosh
  -1 siblings, 1 reply; 157+ 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] 157+ messages in thread

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

> On 02/18/2011 08:07 AM, Subhasish Ghosh wrote:
>> --------------------------------------------------
>> From: "Kurt Van Dijck" <kurt.van.dijck@eia.be>
>
> ...
>>>> + /* 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  8:15           ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  8:15           ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  8:15 UTC (permalink / raw)
  To: linux-arm-kernel

> On 02/18/2011 08:07 AM, Subhasish Ghosh wrote:
>> --------------------------------------------------
>> From: "Kurt Van Dijck" <kurt.van.dijck@eia.be>
>
> ...
>>>> + /* 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] 157+ 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
  -1 siblings, 0 replies; 157+ messages in thread
From: Marc Kleine-Budde @ 2011-02-18  8:36 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Wolfgang Grandegger, sachi, davinci-linux-open-source,
	CAN NETWORK DRIVERS, nsekhar, LKML, CAN NETWORK DRIVERS,
	m-watkins, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1036 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@eia.be>
>>
>> ...
>>>>> + /* 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 #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  8:36             ` Marc Kleine-Budde
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  8:36             ` Marc Kleine-Budde
  0 siblings, 0 replies; 157+ messages in thread
From: Marc Kleine-Budde @ 2011-02-18  8:36 UTC (permalink / raw)
  To: linux-arm-kernel

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@eia.be>
>>
>> ...
>>>>> + /* 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   |

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 262 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110218/ce017071/attachment.sig>

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  9:09               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  9:09 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Wolfgang Grandegger, sachi, davinci-linux-open-source,
	CAN NETWORK DRIVERS, nsekhar, LKML, CAN NETWORK DRIVERS,
	m-watkins, linux-arm-kernel

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@eia.be>
>>
>> ...
>>>>> + /* 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  9:09               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18  9:09               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

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@eia.be>
>>
>> ...
>>>>> + /* 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] 157+ messages in thread

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-11 16:28     ` Alan Cox
@ 2011-02-18 13:47       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18 13:47 UTC (permalink / raw)
  To: Alan Cox
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list

Hello,

Regarding the semaphore to mutex migration.
We are using down_trylock in interrupt context,
mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
our driver.

--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Friday, February 11, 2011 9:58 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>; "Greg Kroah-Hartman" 
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> Don't see why it needs its own sub-directory
>
>
>
>> +#ifdef __SUART_DEBUG
>> +#define __suart_debug(fmt, args...) \
>> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> +#else
>> +#define __suart_debug(fmt, args...)
>> +#endif
>> +
>> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## 
>> args)
>
> Use dev_dbg/dev_err/pr_debug/pr_err
>
>
>> +static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 
>> uart_no)
>> +{
>> + struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
>> + struct device *dev = soft_uart->dev;
>> + s32 count = 0;
>> +
>> + if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>> + return;
>> +
>> + if (down_trylock(&soft_uart->port_sem[uart_no]))
>> + return;
>
> Please use a mutex not a semaphore. We are trying to get almost all the
> kernel using mutexes as it is needed for hard real time.
>
>
>> + pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
>> +        suart_data, data_len + 1,
>> +        &data_len_read);
>> +
>> + for (i = 0; i <= data_len_read; i++) {
>> + soft_uart->port[uart_no].icount.rx++;
>> + /* check for sys rq */
>> + if (uart_handle_sysrq_char
>> +     (&soft_uart->port[uart_no], suart_data))
>> + continue;
>> + }
>> + /* update the tty data structure */
>> + tty_insert_flip_string(tty, suart_data, data_len_read);
>
> You can avoid a copy here by using tty_prepare_flip_string()
>
> Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty
> refcounting is right
>
>
>> +static void pruss_suart_set_termios(struct uart_port *port,
>> +   struct ktermios *termios,
>> +   struct ktermios *old)
>> +{
>> + struct omapl_pru_suart *soft_uart =
>> +     container_of(port, struct omapl_pru_suart, port[port->line]);
>> + struct device *dev = soft_uart->dev;
>> + u8 cval = 0;
>> + unsigned long flags = 0;
>> + u32 baud = 0;
>> + u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
>> +
>> +/*
>> + * Do not allow unsupported configurations to be set
>> + */
>> + if (1) {
>> + termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
>> +       | PARENB | PARODD | CMSPAR);
>> + termios->c_cflag |= CLOCAL;
>
> No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them
> even if in fact they have no effect, so leave those two alone. The rest
> is fine.
>
>
>> +/*
>> + * Characteres to ignore
>
> Typo
>
>
>
>> diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c 
>> b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> new file mode 100644
>> index 0000000..d809dd3
>> --- /dev/null
>> +++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> @@ -0,0 +1,2350 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
>> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
>> +#include <linux/mfd/pruss/da8xx_pru.h>
>> +#include <linux/io.h>
>> +#include <mach/hardware.h>
>> +#include "pruss_suart_api.h"
>> +#include "pruss_suart_regs.h"
>> +#include "pruss_suart_board.h"
>> +#include "pruss_suart_utils.h"
>> +#include "pruss_suart_err.h"
>> +
>> +static u8 g_uart_statu_table[8];
> Can you lose the g_, its  a windows naming convention we dont use
>
>
>> +s16 pru_softuart_open(suart_handle h_suart)
>> +{
>
> If you just used normal integers you could surely make this routine
> trivial and remove all the duplication in the switches
>
>> + s16 status = PRU_SUART_SUCCESS;
>
> And please stick to Linux error codes
>
>
>> +/* suart instance close routine */
>> +s16 pru_softuart_close(suart_handle h_uart)
>> +{
>> + s16 status = SUART_SUCCESS;
>> +
>> + if (h_uart == NULL) {
>> + return PRU_SUART_ERR_HANDLE_INVALID;
>
> Which is never checked. Far better to use WARN_ON and the like for such
> cases - or if like this one they don't appear to be possible to simply
> delete them
>
>> + if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>> + if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>
> [minor] Lots of excess brackets
>
>
>> + u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
>> + u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
>> + s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
>> + if (-1 == s16retval)
>> + return -1;
>
> If you fixed the API here you'd be able to just write
>
> if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF,
> PRU_INTC_BLAH)
>
> or similar which would clean up a lot of messy code and shrink it
> dramatically. Given you have lots of series of writes some kind of
>
> pruss_writel_multi(dev, array, len)
>
> that took an array of addr/value pairs might also clean up a ton of code
> and turn it into trivial tables
> 

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-18 13:47       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-18 13:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

Regarding the semaphore to mutex migration.
We are using down_trylock in interrupt context,
mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
our driver.

--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Friday, February 11, 2011 9:58 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>; "Greg Kroah-Hartman" 
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> Don't see why it needs its own sub-directory
>
>
>
>> +#ifdef __SUART_DEBUG
>> +#define __suart_debug(fmt, args...) \
>> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> +#else
>> +#define __suart_debug(fmt, args...)
>> +#endif
>> +
>> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ## 
>> args)
>
> Use dev_dbg/dev_err/pr_debug/pr_err
>
>
>> +static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32 
>> uart_no)
>> +{
>> + struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
>> + struct device *dev = soft_uart->dev;
>> + s32 count = 0;
>> +
>> + if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>> + return;
>> +
>> + if (down_trylock(&soft_uart->port_sem[uart_no]))
>> + return;
>
> Please use a mutex not a semaphore. We are trying to get almost all the
> kernel using mutexes as it is needed for hard real time.
>
>
>> + pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
>> +        suart_data, data_len + 1,
>> +        &data_len_read);
>> +
>> + for (i = 0; i <= data_len_read; i++) {
>> + soft_uart->port[uart_no].icount.rx++;
>> + /* check for sys rq */
>> + if (uart_handle_sysrq_char
>> +     (&soft_uart->port[uart_no], suart_data))
>> + continue;
>> + }
>> + /* update the tty data structure */
>> + tty_insert_flip_string(tty, suart_data, data_len_read);
>
> You can avoid a copy here by using tty_prepare_flip_string()
>
> Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty
> refcounting is right
>
>
>> +static void pruss_suart_set_termios(struct uart_port *port,
>> +   struct ktermios *termios,
>> +   struct ktermios *old)
>> +{
>> + struct omapl_pru_suart *soft_uart =
>> +     container_of(port, struct omapl_pru_suart, port[port->line]);
>> + struct device *dev = soft_uart->dev;
>> + u8 cval = 0;
>> + unsigned long flags = 0;
>> + u32 baud = 0;
>> + u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
>> +
>> +/*
>> + * Do not allow unsupported configurations to be set
>> + */
>> + if (1) {
>> + termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
>> +       | PARENB | PARODD | CMSPAR);
>> + termios->c_cflag |= CLOCAL;
>
> No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them
> even if in fact they have no effect, so leave those two alone. The rest
> is fine.
>
>
>> +/*
>> + * Characteres to ignore
>
> Typo
>
>
>
>> diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c 
>> b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> new file mode 100644
>> index 0000000..d809dd3
>> --- /dev/null
>> +++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> @@ -0,0 +1,2350 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
>> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
>> +#include <linux/mfd/pruss/da8xx_pru.h>
>> +#include <linux/io.h>
>> +#include <mach/hardware.h>
>> +#include "pruss_suart_api.h"
>> +#include "pruss_suart_regs.h"
>> +#include "pruss_suart_board.h"
>> +#include "pruss_suart_utils.h"
>> +#include "pruss_suart_err.h"
>> +
>> +static u8 g_uart_statu_table[8];
> Can you lose the g_, its  a windows naming convention we dont use
>
>
>> +s16 pru_softuart_open(suart_handle h_suart)
>> +{
>
> If you just used normal integers you could surely make this routine
> trivial and remove all the duplication in the switches
>
>> + s16 status = PRU_SUART_SUCCESS;
>
> And please stick to Linux error codes
>
>
>> +/* suart instance close routine */
>> +s16 pru_softuart_close(suart_handle h_uart)
>> +{
>> + s16 status = SUART_SUCCESS;
>> +
>> + if (h_uart == NULL) {
>> + return PRU_SUART_ERR_HANDLE_INVALID;
>
> Which is never checked. Far better to use WARN_ON and the like for such
> cases - or if like this one they don't appear to be possible to simply
> delete them
>
>> + if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>> + if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>
> [minor] Lots of excess brackets
>
>
>> + u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
>> + u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
>> + s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
>> + if (-1 == s16retval)
>> + return -1;
>
> If you fixed the API here you'd be able to just write
>
> if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF,
> PRU_INTC_BLAH)
>
> or similar which would clean up a lot of messy code and shrink it
> dramatically. Given you have lots of series of writes some kind of
>
> pruss_writel_multi(dev, array, len)
>
> that took an array of addr/value pairs might also clean up a ton of code
> and turn it into trivial tables
> 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-18 13:47       ` Subhasish Ghosh
@ 2011-02-18 14:35         ` Alan Cox
  -1 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-02-18 14:35 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list

On Fri, 18 Feb 2011 19:17:38 +0530
"Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:

> Hello,
> 
> Regarding the semaphore to mutex migration.
> We are using down_trylock in interrupt context,
> mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
> our driver.

Then you probably need to rework your locking. Best bet might be to fix
all the other stuff and report the driver, and people can think about the
locking problem.

Alan

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-18 14:35         ` Alan Cox
  0 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-02-18 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 18 Feb 2011 19:17:38 +0530
"Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:

> Hello,
> 
> Regarding the semaphore to mutex migration.
> We are using down_trylock in interrupt context,
> mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
> our driver.

Then you probably need to rework your locking. Best bet might be to fix
all the other stuff and report the driver, and people can think about the
locking problem.

Alan

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-18 15:07     ` Arnd Bergmann
  -1 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-02-18 15:07     ` Arnd Bergmann
  0 siblings, 0 replies; 157+ messages in thread
From: Arnd Bergmann @ 2011-02-18 15:07 UTC (permalink / raw)
  To: linux-arm-kernel

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] 157+ messages in thread

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-18 14:35         ` Alan Cox
@ 2011-02-18 18:23           ` Thomas Gleixner
  -1 siblings, 0 replies; 157+ messages in thread
From: Thomas Gleixner @ 2011-02-18 18:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: Subhasish Ghosh, davinci-linux-open-source, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Greg Kroah-Hartman, open list

On Fri, 18 Feb 2011, Alan Cox wrote:

> On Fri, 18 Feb 2011 19:17:38 +0530
> "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
> 
> > Hello,
> > 
> > Regarding the semaphore to mutex migration.
> > We are using down_trylock in interrupt context,
> > mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
> > our driver.
> 
> Then you probably need to rework your locking. Best bet might be to fix
> all the other stuff and report the driver, and people can think about the
> locking problem.

That semaphore is utterly useless to begin with. There are more
serious locking problems than this one. Non serialized calls to
suart_intr_clrmask/suart_intr_setmask are the most obvious ones.

Aside of that the code is complete unreadable.

Thanks,

	tglx

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-18 18:23           ` Thomas Gleixner
  0 siblings, 0 replies; 157+ messages in thread
From: Thomas Gleixner @ 2011-02-18 18:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 18 Feb 2011, Alan Cox wrote:

> On Fri, 18 Feb 2011 19:17:38 +0530
> "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
> 
> > Hello,
> > 
> > Regarding the semaphore to mutex migration.
> > We are using down_trylock in interrupt context,
> > mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
> > our driver.
> 
> Then you probably need to rework your locking. Best bet might be to fix
> all the other stuff and report the driver, and people can think about the
> locking problem.

That semaphore is utterly useless to begin with. There are more
serious locking problems than this one. Non serialized calls to
suart_intr_clrmask/suart_intr_setmask are the most obvious ones.

Aside of that the code is complete unreadable.

Thanks,

	tglx

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-18 18:23           ` Thomas Gleixner
@ 2011-02-18 18:51             ` Arnd Bergmann
  -1 siblings, 0 replies; 157+ messages in thread
From: Arnd Bergmann @ 2011-02-18 18:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Thomas Gleixner, Alan Cox, sachi, davinci-linux-open-source,
	Subhasish Ghosh, Greg Kroah-Hartman, nsekhar, open list,
	m-watkins

On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
> On Fri, 18 Feb 2011, Alan Cox wrote:
> 
> > On Fri, 18 Feb 2011 19:17:38 +0530
> > "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
> > 
> > > Hello,
> > > 
> > > Regarding the semaphore to mutex migration.
> > > We are using down_trylock in interrupt context,
> > > mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
> > > our driver.
> > 
> > Then you probably need to rework your locking. Best bet might be to fix
> > all the other stuff and report the driver, and people can think about the
> > locking problem.
> 
> That semaphore is utterly useless to begin with. There are more
> serious locking problems than this one. Non serialized calls to
> suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
> 
> Aside of that the code is complete unreadable.

I think it mostly suffers from the same problem as the CAN driver
I commented on earlier: One of the files (pruss_suart_api.c) was
clearly not written with Linux as the target, and the other files
try to work around this by wrapping a Linux driver around it.

The suart_api HAL stuff clearly needs to go away, so that the rest
can be rewritten into a proper device driver.

	Arnd

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-18 18:51             ` Arnd Bergmann
  0 siblings, 0 replies; 157+ messages in thread
From: Arnd Bergmann @ 2011-02-18 18:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
> On Fri, 18 Feb 2011, Alan Cox wrote:
> 
> > On Fri, 18 Feb 2011 19:17:38 +0530
> > "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
> > 
> > > Hello,
> > > 
> > > Regarding the semaphore to mutex migration.
> > > We are using down_trylock in interrupt context,
> > > mutex_trylock cannot be used in interrupt context, so we cannot use mutex in 
> > > our driver.
> > 
> > Then you probably need to rework your locking. Best bet might be to fix
> > all the other stuff and report the driver, and people can think about the
> > locking problem.
> 
> That semaphore is utterly useless to begin with. There are more
> serious locking problems than this one. Non serialized calls to
> suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
> 
> Aside of that the code is complete unreadable.

I think it mostly suffers from the same problem as the CAN driver
I commented on earlier: One of the files (pruss_suart_api.c) was
clearly not written with Linux as the target, and the other files
try to work around this by wrapping a Linux driver around it.

The suart_api HAL stuff clearly needs to go away, so that the rest
can be rewritten into a proper device driver.

	Arnd

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-21 16:30     ` Samuel Ortiz
  -1 siblings, 0 replies; 157+ messages in thread
From: Samuel Ortiz @ 2011-02-21 16:30 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, open list

Hi Subhasish,

On Fri, Feb 11, 2011 at 08:21:20PM +0530, Subhasish Ghosh wrote:
> This patch adds the pruss MFD driver and associated include files.
A more detailed changelog would be better. What is this device, why is it an
MFD and what are its potential subdevices ?

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index fd01836..6c437df 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>  	  boards.  MSP430 firmware manages resets and power sequencing,
>  	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
>  
> +config MFD_DA8XX_PRUSS
> +	tristate "Texas Instruments DA8XX PRUSS support"
> +	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
Why are we depending on those ?


> +	select MFD_CORE
> +	help
> +	    This driver provides support api's for the programmable
> +		realtime unit (PRU) present on TI's da8xx processors. It
> +		provides basic read, write, config, enable, disable
> +		routines to facilitate devices emulated on it.
Please fix your identation here.

> --- /dev/null
> +++ b/drivers/mfd/da8xx_pru.c
> @@ -0,0 +1,446 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
s/2010/2011/ ? 

> + * 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/init.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/bitops.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/mfd/pruss/da8xx_prucore.h>
> +#include <linux/mfd/pruss/da8xx_pru.h>
> +#include <linux/mfd/core.h>
> +#include <linux/io.h>
> +#include <mach/da8xx.h>
Is that include needed ?


> +struct da8xx_pruss {
What is the "ss" suffix for ?


> +u32 pruss_disable(struct device *dev, u8 pruss_num)
> +{
> +	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
> +	da8xx_prusscore_regs h_pruss;
> +	u32 temp_reg;
> +
> +	if (pruss_num == DA8XX_PRUCORE_0) {
> +		/* Disable PRU0  */
> +		h_pruss = (da8xx_prusscore_regs)
> +			((u32) pruss->ioaddr + 0x7000);
So it seems you're doing this in several places, and I have a few comments:

- You don't need the da8xx_prusscore_regs at all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.

Then routines like this one will look a lot more readable.

> +s16 pruss_writeb(struct device *dev, u32 u32offset,
> +		u8 *pu8datatowrite, u16 u16bytestowrite)
>From CodingStyle: "Encoding the type of a function into the name (so-called
Hungarian notation) is brain damaged"

Also, all your exported routines severely lack any sort of locking. An IO
mutex or spinlock is mandatory here. 

> +static int pruss_mfd_add_devices(struct platform_device *pdev)
> +{
> +	struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
> +	struct device *dev = &pdev->dev;
> +	struct mfd_cell cell;
> +	u32 err, count;
> +
> +	for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
> +		memset(&cell, 0, sizeof(struct mfd_cell));
> +		cell.id			= count;
> +		cell.name		= (dev_data + count)->dev_name;
> +		cell.platform_data	= (dev_data + count)->pdata;
> +		cell.data_size		= (dev_data + count)->pdata_size;
> +
> +		err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
> +		if (err) {
> +			dev_err(dev, "cannot add mfd cells\n");
> +			return err;
> +		}
> +	}
> +	return err;
> +}
So, what are the potential subdevices for this driver ? If it's a really
dynamic setup, I'm fine with passing those as platform data but then do it so
that you pass a NULL terminated da8xx_pruss_devices array. That will avoid
most of the ugly casts you're doing here.

> diff --git a/include/linux/mfd/pruss/da8xx_pru.h b/include/linux/mfd/pruss/da8xx_pru.h
> new file mode 100644
> index 0000000..68d8421
> --- /dev/null
> +++ b/include/linux/mfd/pruss/da8xx_pru.h
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
> + */
> +
> +#ifndef _PRUSS_H_
> +#define _PRUSS_H_
> +
> +#include <linux/types.h>
> +#include <linux/platform_device.h>
> +#include "da8xx_prucore.h"
> +
> +#define PRUSS_NUM0			DA8XX_PRUCORE_0
> +#define PRUSS_NUM1			DA8XX_PRUCORE_1
Those are unused.

> diff --git a/include/linux/mfd/pruss/da8xx_prucore.h b/include/linux/mfd/pruss/da8xx_prucore.h
> new file mode 100644
> index 0000000..81f2ff9
> --- /dev/null
> +++ b/include/linux/mfd/pruss/da8xx_prucore.h
Please rename your mfd include directory to include/linux/mfd/da8xx/, so that
one can match it with the drivers/mfd/da8xx driver code.


> +typedef struct {
> +	u32 CONTROL;
> +	u32 STATUS;
> +	u32 WAKEUP;
> +	u32 CYCLECNT;
> +	u32 STALLCNT;
> +	u8  RSVD0[12];
> +	u32 CONTABBLKIDX0;
> +	u32 CONTABBLKIDX1;
> +	u32 CONTABPROPTR0;
> +	u32 CONTABPROPTR1;
> +	u8  RSVD1[976];
> +	u32 INTGPR[32];
> +	u32 INTCTER[32];
> +} *da8xx_prusscore_regs;
Again, we don't need that structure.

Cheers,
Samuel.


-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-21 16:30     ` Samuel Ortiz
  0 siblings, 0 replies; 157+ messages in thread
From: Samuel Ortiz @ 2011-02-21 16:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Subhasish,

On Fri, Feb 11, 2011 at 08:21:20PM +0530, Subhasish Ghosh wrote:
> This patch adds the pruss MFD driver and associated include files.
A more detailed changelog would be better. What is this device, why is it an
MFD and what are its potential subdevices ?

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index fd01836..6c437df 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>  	  boards.  MSP430 firmware manages resets and power sequencing,
>  	  inputs from buttons and the IR remote, LEDs, an RTC, and more.
>  
> +config MFD_DA8XX_PRUSS
> +	tristate "Texas Instruments DA8XX PRUSS support"
> +	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
Why are we depending on those ?


> +	select MFD_CORE
> +	help
> +	    This driver provides support api's for the programmable
> +		realtime unit (PRU) present on TI's da8xx processors. It
> +		provides basic read, write, config, enable, disable
> +		routines to facilitate devices emulated on it.
Please fix your identation here.

> --- /dev/null
> +++ b/drivers/mfd/da8xx_pru.c
> @@ -0,0 +1,446 @@
> +/*
> + * Copyright (C) 2010 Texas Instruments Incorporated
s/2010/2011/ ? 

> + * 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/init.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/bitops.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/mfd/pruss/da8xx_prucore.h>
> +#include <linux/mfd/pruss/da8xx_pru.h>
> +#include <linux/mfd/core.h>
> +#include <linux/io.h>
> +#include <mach/da8xx.h>
Is that include needed ?


> +struct da8xx_pruss {
What is the "ss" suffix for ?


> +u32 pruss_disable(struct device *dev, u8 pruss_num)
> +{
> +	struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
> +	da8xx_prusscore_regs h_pruss;
> +	u32 temp_reg;
> +
> +	if (pruss_num == DA8XX_PRUCORE_0) {
> +		/* Disable PRU0  */
> +		h_pruss = (da8xx_prusscore_regs)
> +			((u32) pruss->ioaddr + 0x7000);
So it seems you're doing this in several places, and I have a few comments:

- You don't need the da8xx_prusscore_regs at all.
- Define the register map through a set of #define in your header file.
- Use a static routine that takes the core number and returns the register map
offset.

Then routines like this one will look a lot more readable.

> +s16 pruss_writeb(struct device *dev, u32 u32offset,
> +		u8 *pu8datatowrite, u16 u16bytestowrite)

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-21 16:30     ` Samuel Ortiz
@ 2011-02-22  5:43       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  5:43 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, open list

Thank you for your comments.

--------------------------------------------------
From: "Samuel Ortiz" <sameo@linux.intel.com>
Sent: Monday, February 21, 2011 10:00 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>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.

> Hi Subhasish,
>
> On Fri, Feb 11, 2011 at 08:21:20PM +0530, Subhasish Ghosh wrote:
>> This patch adds the pruss MFD driver and associated include files.
> A more detailed changelog would be better. What is this device, why is it 
> an
> MFD and what are its potential subdevices ?
>

SG -- Will add a more detailed change log.

>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index fd01836..6c437df 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>>    boards.  MSP430 firmware manages resets and power sequencing,
>>    inputs from buttons and the IR remote, LEDs, an RTC, and more.
>>
>> +config MFD_DA8XX_PRUSS
>> + tristate "Texas Instruments DA8XX PRUSS support"
>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> Why are we depending on those ?

SG -- The PRUSS core in only available within DA850 and DA830,
            DA830 support is not yet implemented.

>
>
>> + select MFD_CORE
>> + help
>> +     This driver provides support api's for the programmable
>> + realtime unit (PRU) present on TI's da8xx processors. It
>> + provides basic read, write, config, enable, disable
>> + routines to facilitate devices emulated on it.
> Please fix your identation here.

SG -- Will do.

>
>> --- /dev/null
>> +++ b/drivers/mfd/da8xx_pru.c
>> @@ -0,0 +1,446 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
> s/2010/2011/ ?
>
>> + * 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/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/module.h>
>> +#include <linux/bitops.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/errno.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/clk.h>
>> +#include <linux/mfd/pruss/da8xx_prucore.h>
>> +#include <linux/mfd/pruss/da8xx_pru.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/io.h>
>> +#include <mach/da8xx.h>
> Is that include needed ?

SG  - Will remove if not needed.

>
>
>> +struct da8xx_pruss {
> What is the "ss" suffix for ?

SG -- We call it the PRU Sub-System.

>
>
>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
>> +{
>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>> + da8xx_prusscore_regs h_pruss;
>> + u32 temp_reg;
>> +
>> + if (pruss_num == DA8XX_PRUCORE_0) {
>> + /* Disable PRU0  */
>> + h_pruss = (da8xx_prusscore_regs)
>> + ((u32) pruss->ioaddr + 0x7000);
> So it seems you're doing this in several places, and I have a few 
> comments:
>
> - You don't need the da8xx_prusscore_regs at all.
> - Define the register map through a set of #define in your header file.
> - Use a static routine that takes the core number and returns the register 
> map
> offset.
>
> Then routines like this one will look a lot more readable.

SG -- There are a huge number of PRUSS registers. A lot of them are reserved 
and are expected to change as development on the
            controller is still ongoing. If we use #defines to plot all the 
registers, then first, there are too many array type registers which will 
need to be duplicated.
            And if the offset of one of the macro changes in between, we 
will require to adjust all the rest of the macros. So I felt like a 
structure was a better option here.
            I also named the structure elements as per the register names. 
so why should it be less readable ?  But, we can definitely use macros to 
define the PRUSS0 & 1
            offsets instead of the magic numbers as above.
>
>> +s16 pruss_writeb(struct device *dev, u32 u32offset,
>> + u8 *pu8datatowrite, u16 u16bytestowrite)
> From CodingStyle: "Encoding the type of a function into the name 
> (so-called
> Hungarian notation) is brain damaged"

SG -- Will change.
>
> Also, all your exported routines severely lack any sort of locking. An IO
> mutex or spinlock is mandatory here.

SG - As per our current implementation, we do not have two devices running 
simultaneously on the PRU,
        so we do not have any way to test it. We have kept this as an 
enhancement if request comes in for
        multiple devices.

>
>> +static int pruss_mfd_add_devices(struct platform_device *pdev)
>> +{
>> + struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
>> + struct device *dev = &pdev->dev;
>> + struct mfd_cell cell;
>> + u32 err, count;
>> +
>> + for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
>> + memset(&cell, 0, sizeof(struct mfd_cell));
>> + cell.id = count;
>> + cell.name = (dev_data + count)->dev_name;
>> + cell.platform_data = (dev_data + count)->pdata;
>> + cell.data_size = (dev_data + count)->pdata_size;
>> +
>> + err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
>> + if (err) {
>> + dev_err(dev, "cannot add mfd cells\n");
>> + return err;
>> + }
>> + }
>> + return err;
>> +}
> So, what are the potential subdevices for this driver ? If it's a really
> dynamic setup, I'm fine with passing those as platform data but then do it 
> so
> that you pass a NULL terminated da8xx_pruss_devices array. That will avoid
> most of the ugly casts you're doing here.

SG -- I did not follow your recommendations here, could you please 
elaborate.
            I am already checking the dev_name for a NULL.
            This device is basically a microcontroller within DA850, so 
basically any device or protocol can be
            emulated on it. Currently, we have emulated 8 UARTS using the 
two PRUs and also a CAN device.
>
>> diff --git a/include/linux/mfd/pruss/da8xx_pru.h 
>> b/include/linux/mfd/pruss/da8xx_pru.h
>> new file mode 100644
>> index 0000000..68d8421
>> --- /dev/null
>> +++ b/include/linux/mfd/pruss/da8xx_pru.h
>> @@ -0,0 +1,122 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
>> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
>> + */
>> +
>> +#ifndef _PRUSS_H_
>> +#define _PRUSS_H_
>> +
>> +#include <linux/types.h>
>> +#include <linux/platform_device.h>
>> +#include "da8xx_prucore.h"
>> +
>> +#define PRUSS_NUM0 DA8XX_PRUCORE_0
>> +#define PRUSS_NUM1 DA8XX_PRUCORE_1
> Those are unused.

SG - These are getting used by the CAN & UART drivers.

>
>> diff --git a/include/linux/mfd/pruss/da8xx_prucore.h 
>> b/include/linux/mfd/pruss/da8xx_prucore.h
>> new file mode 100644
>> index 0000000..81f2ff9
>> --- /dev/null
>> +++ b/include/linux/mfd/pruss/da8xx_prucore.h
> Please rename your mfd include directory to include/linux/mfd/da8xx/, so 
> that
> one can match it with the drivers/mfd/da8xx driver code.

SG - Will do.

>
>
>> +typedef struct {
>> + u32 CONTROL;
>> + u32 STATUS;
>> + u32 WAKEUP;
>> + u32 CYCLECNT;
>> + u32 STALLCNT;
>> + u8  RSVD0[12];
>> + u32 CONTABBLKIDX0;
>> + u32 CONTABBLKIDX1;
>> + u32 CONTABPROPTR0;
>> + u32 CONTABPROPTR1;
>> + u8  RSVD1[976];
>> + u32 INTGPR[32];
>> + u32 INTCTER[32];
>> +} *da8xx_prusscore_regs;
> Again, we don't need that structure.

SG - As mentioned above.

>
> Cheers,
> Samuel.
>
>
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/ 


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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-22  5:43       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  5:43 UTC (permalink / raw)
  To: linux-arm-kernel

Thank you for your comments.

--------------------------------------------------
From: "Samuel Ortiz" <sameo@linux.intel.com>
Sent: Monday, February 21, 2011 10:00 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>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.

> Hi Subhasish,
>
> On Fri, Feb 11, 2011 at 08:21:20PM +0530, Subhasish Ghosh wrote:
>> This patch adds the pruss MFD driver and associated include files.
> A more detailed changelog would be better. What is this device, why is it 
> an
> MFD and what are its potential subdevices ?
>

SG -- Will add a more detailed change log.

>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index fd01836..6c437df 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>>    boards.  MSP430 firmware manages resets and power sequencing,
>>    inputs from buttons and the IR remote, LEDs, an RTC, and more.
>>
>> +config MFD_DA8XX_PRUSS
>> + tristate "Texas Instruments DA8XX PRUSS support"
>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> Why are we depending on those ?

SG -- The PRUSS core in only available within DA850 and DA830,
            DA830 support is not yet implemented.

>
>
>> + select MFD_CORE
>> + help
>> +     This driver provides support api's for the programmable
>> + realtime unit (PRU) present on TI's da8xx processors. It
>> + provides basic read, write, config, enable, disable
>> + routines to facilitate devices emulated on it.
> Please fix your identation here.

SG -- Will do.

>
>> --- /dev/null
>> +++ b/drivers/mfd/da8xx_pru.c
>> @@ -0,0 +1,446 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
> s/2010/2011/ ?
>
>> + * 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/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/module.h>
>> +#include <linux/bitops.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/errno.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/clk.h>
>> +#include <linux/mfd/pruss/da8xx_prucore.h>
>> +#include <linux/mfd/pruss/da8xx_pru.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/io.h>
>> +#include <mach/da8xx.h>
> Is that include needed ?

SG  - Will remove if not needed.

>
>
>> +struct da8xx_pruss {
> What is the "ss" suffix for ?

SG -- We call it the PRU Sub-System.

>
>
>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
>> +{
>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>> + da8xx_prusscore_regs h_pruss;
>> + u32 temp_reg;
>> +
>> + if (pruss_num == DA8XX_PRUCORE_0) {
>> + /* Disable PRU0  */
>> + h_pruss = (da8xx_prusscore_regs)
>> + ((u32) pruss->ioaddr + 0x7000);
> So it seems you're doing this in several places, and I have a few 
> comments:
>
> - You don't need the da8xx_prusscore_regs at all.
> - Define the register map through a set of #define in your header file.
> - Use a static routine that takes the core number and returns the register 
> map
> offset.
>
> Then routines like this one will look a lot more readable.

SG -- There are a huge number of PRUSS registers. A lot of them are reserved 
and are expected to change as development on the
            controller is still ongoing. If we use #defines to plot all the 
registers, then first, there are too many array type registers which will 
need to be duplicated.
            And if the offset of one of the macro changes in between, we 
will require to adjust all the rest of the macros. So I felt like a 
structure was a better option here.
            I also named the structure elements as per the register names. 
so why should it be less readable ?  But, we can definitely use macros to 
define the PRUSS0 & 1
            offsets instead of the magic numbers as above.
>
>> +s16 pruss_writeb(struct device *dev, u32 u32offset,
>> + u8 *pu8datatowrite, u16 u16bytestowrite)
> From CodingStyle: "Encoding the type of a function into the name 
> (so-called
> Hungarian notation) is brain damaged"

SG -- Will change.
>
> Also, all your exported routines severely lack any sort of locking. An IO
> mutex or spinlock is mandatory here.

SG - As per our current implementation, we do not have two devices running 
simultaneously on the PRU,
        so we do not have any way to test it. We have kept this as an 
enhancement if request comes in for
        multiple devices.

>
>> +static int pruss_mfd_add_devices(struct platform_device *pdev)
>> +{
>> + struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
>> + struct device *dev = &pdev->dev;
>> + struct mfd_cell cell;
>> + u32 err, count;
>> +
>> + for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
>> + memset(&cell, 0, sizeof(struct mfd_cell));
>> + cell.id = count;
>> + cell.name = (dev_data + count)->dev_name;
>> + cell.platform_data = (dev_data + count)->pdata;
>> + cell.data_size = (dev_data + count)->pdata_size;
>> +
>> + err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
>> + if (err) {
>> + dev_err(dev, "cannot add mfd cells\n");
>> + return err;
>> + }
>> + }
>> + return err;
>> +}
> So, what are the potential subdevices for this driver ? If it's a really
> dynamic setup, I'm fine with passing those as platform data but then do it 
> so
> that you pass a NULL terminated da8xx_pruss_devices array. That will avoid
> most of the ugly casts you're doing here.

SG -- I did not follow your recommendations here, could you please 
elaborate.
            I am already checking the dev_name for a NULL.
            This device is basically a microcontroller within DA850, so 
basically any device or protocol can be
            emulated on it. Currently, we have emulated 8 UARTS using the 
two PRUs and also a CAN device.
>
>> diff --git a/include/linux/mfd/pruss/da8xx_pru.h 
>> b/include/linux/mfd/pruss/da8xx_pru.h
>> new file mode 100644
>> index 0000000..68d8421
>> --- /dev/null
>> +++ b/include/linux/mfd/pruss/da8xx_pru.h
>> @@ -0,0 +1,122 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
>> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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.
>> + */
>> +
>> +#ifndef _PRUSS_H_
>> +#define _PRUSS_H_
>> +
>> +#include <linux/types.h>
>> +#include <linux/platform_device.h>
>> +#include "da8xx_prucore.h"
>> +
>> +#define PRUSS_NUM0 DA8XX_PRUCORE_0
>> +#define PRUSS_NUM1 DA8XX_PRUCORE_1
> Those are unused.

SG - These are getting used by the CAN & UART drivers.

>
>> diff --git a/include/linux/mfd/pruss/da8xx_prucore.h 
>> b/include/linux/mfd/pruss/da8xx_prucore.h
>> new file mode 100644
>> index 0000000..81f2ff9
>> --- /dev/null
>> +++ b/include/linux/mfd/pruss/da8xx_prucore.h
> Please rename your mfd include directory to include/linux/mfd/da8xx/, so 
> that
> one can match it with the drivers/mfd/da8xx driver code.

SG - Will do.

>
>
>> +typedef struct {
>> + u32 CONTROL;
>> + u32 STATUS;
>> + u32 WAKEUP;
>> + u32 CYCLECNT;
>> + u32 STALLCNT;
>> + u8  RSVD0[12];
>> + u32 CONTABBLKIDX0;
>> + u32 CONTABBLKIDX1;
>> + u32 CONTABPROPTR0;
>> + u32 CONTABPROPTR1;
>> + u8  RSVD1[976];
>> + u32 INTGPR[32];
>> + u32 INTCTER[32];
>> +} *da8xx_prusscore_regs;
> Again, we don't need that structure.

SG - As mentioned above.

>
> Cheers,
> Samuel.
>
>
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/ 

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

* Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.
  2011-02-11 18:50     ` Sergei Shtylyov
@ 2011-02-22  6:22       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  6:22 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Hello,

Have modified this as shown below:
Please let me know if this looks ok.

diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
b/arch/arm/mach-davinci/board-da850-evm.c
+static struct da850_evm_pruss_can_data can_data = {
        .version        = 1,
 };

+static struct resource da850_evm_suart_resource[] = 
  ------------------------->>> Added a separate resource structure for 
suart.
+       {
+               .name   = "da8xx_mcasp0_iomem",
+               .start  = DAVINCI_DA8XX_MCASP0_REG_BASE,
+               .end    = DAVINCI_DA8XX_MCASP0_REG_BASE +
+                               (SZ_1K * 12) - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
 static struct da8xx_pruss_devices pruss_devices[] = {
        {
                .dev_name       = "da8xx_pruss_can",
                .pdata          = &can_data,
                .pdata_size     = sizeof(can_data),
                .setup          = da850_evm_setup_pruss_can,
+               .num_resources  = 0,
+               .resources      = NULL,
        },
        {
                .dev_name       = "da8xx_pruss_uart",
                .pdata          = &suart_data,
                .pdata_size     = sizeof(suart_data),
                .setup          = da850_evm_setup_pruss_suart,
+               .num_resources  = ARRAY_SIZE(da850_evm_suart_resource),
+               .resources      = 
a850_evm_suart_resource,  ---------------------------- >>>>> Initialized it 
here
        },
        {
                .dev_name       = NULL,


diff --git a/drivers/mfd/da8xx_pru.c b/drivers/mfd/da8xx_pru.c
index f7868a4..140bf14 100644
--- a/drivers/mfd/da8xx_pru.c
+++ b/drivers/mfd/da8xx_pru.c
@@ -332,6 +332,8 @@ static int pruss_mfd_add_devices(struct platform_device 
*pdev)
                cell.name               = (dev_data + count)->dev_name;
                cell.platform_data      = (dev_data + count)->pdata;
                cell.data_size          = (dev_data + count)->pdata_size;
+               cell.resources          = (dev_data + 
ount)->resources;  ---------------------->>>Modified the MFD driver to add 
the resources.
+               cell.num_resources      = (dev_data + count)->num_resources;


diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart.c 
b/drivers/tty/serial/da8xx_pruss/pruss_suart.c

+       res = platform_get_resource(pdev, IORESOURCE_MEM, 
0); ------------------>> Used platform infrastructure to get the data.
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to get resource");
+               return -ENOMEM;
+       }
+
+       if (!request_mem_region(res->start,
+                       resource_size(res),



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:20 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the pruss SUART pin mux and registers the device
>> with the pruss mfd driver.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>> ---
>>  arch/arm/mach-davinci/board-da850-evm.c |   36 
>> +++++++++++++++++++++++++++++++
>>  1 files changed, 36 insertions(+), 0 deletions(-)
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index f9c38f8..3858516 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> [...]
>> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>>  return ret;
>>  }
>>  +static struct da850_evm_pruss_suart_data suart_data = {
>> + .version = 1,
>> + .resource = {
>> + .name = "da8xx_mcasp0_iomem",
>> + .start = DAVINCI_DA8XX_MCASP0_REG_BASE,
>> + .end = DAVINCI_DA8XX_MCASP0_REG_BASE +
>> + (SZ_1K * 12) - 1,
>> + .flags = IORESOURCE_MEM,
>> + },
>> +};
>> +
>
>    I don't think passing a resource thru platform data is good idea... 
> Resources should be bound to the platform device.
>
> WBR, Sergei 


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

* [PATCH v2 11/13] da850: pruss SUART board specific additions.
@ 2011-02-22  6:22       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  6:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

Have modified this as shown below:
Please let me know if this looks ok.

diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
b/arch/arm/mach-davinci/board-da850-evm.c
+static struct da850_evm_pruss_can_data can_data = {
        .version        = 1,
 };

+static struct resource da850_evm_suart_resource[] = 
  ------------------------->>> Added a separate resource structure for 
suart.
+       {
+               .name   = "da8xx_mcasp0_iomem",
+               .start  = DAVINCI_DA8XX_MCASP0_REG_BASE,
+               .end    = DAVINCI_DA8XX_MCASP0_REG_BASE +
+                               (SZ_1K * 12) - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
 static struct da8xx_pruss_devices pruss_devices[] = {
        {
                .dev_name       = "da8xx_pruss_can",
                .pdata          = &can_data,
                .pdata_size     = sizeof(can_data),
                .setup          = da850_evm_setup_pruss_can,
+               .num_resources  = 0,
+               .resources      = NULL,
        },
        {
                .dev_name       = "da8xx_pruss_uart",
                .pdata          = &suart_data,
                .pdata_size     = sizeof(suart_data),
                .setup          = da850_evm_setup_pruss_suart,
+               .num_resources  = ARRAY_SIZE(da850_evm_suart_resource),
+               .resources      = 
a850_evm_suart_resource,  ---------------------------- >>>>> Initialized it 
here
        },
        {
                .dev_name       = NULL,


diff --git a/drivers/mfd/da8xx_pru.c b/drivers/mfd/da8xx_pru.c
index f7868a4..140bf14 100644
--- a/drivers/mfd/da8xx_pru.c
+++ b/drivers/mfd/da8xx_pru.c
@@ -332,6 +332,8 @@ static int pruss_mfd_add_devices(struct platform_device 
*pdev)
                cell.name               = (dev_data + count)->dev_name;
                cell.platform_data      = (dev_data + count)->pdata;
                cell.data_size          = (dev_data + count)->pdata_size;
+               cell.resources          = (dev_data + 
ount)->resources;  ---------------------->>>Modified the MFD driver to add 
the resources.
+               cell.num_resources      = (dev_data + count)->num_resources;


diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart.c 
b/drivers/tty/serial/da8xx_pruss/pruss_suart.c

+       res = platform_get_resource(pdev, IORESOURCE_MEM, 
0); ------------------>> Used platform infrastructure to get the data.
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to get resource");
+               return -ENOMEM;
+       }
+
+       if (!request_mem_region(res->start,
+                       resource_size(res),



--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:20 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 11/13] da850: pruss SUART board specific additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the pruss SUART pin mux and registers the device
>> with the pruss mfd driver.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>> ---
>>  arch/arm/mach-davinci/board-da850-evm.c |   36 
>> +++++++++++++++++++++++++++++++
>>  1 files changed, 36 insertions(+), 0 deletions(-)
>
>> diff --git a/arch/arm/mach-davinci/board-da850-evm.c 
>> b/arch/arm/mach-davinci/board-da850-evm.c
>> index f9c38f8..3858516 100644
>> --- a/arch/arm/mach-davinci/board-da850-evm.c
>> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> [...]
>> @@ -1085,6 +1104,17 @@ static int __init da850_evm_setup_pruss_can(void)
>>  return ret;
>>  }
>>  +static struct da850_evm_pruss_suart_data suart_data = {
>> + .version = 1,
>> + .resource = {
>> + .name = "da8xx_mcasp0_iomem",
>> + .start = DAVINCI_DA8XX_MCASP0_REG_BASE,
>> + .end = DAVINCI_DA8XX_MCASP0_REG_BASE +
>> + (SZ_1K * 12) - 1,
>> + .flags = IORESOURCE_MEM,
>> + },
>> +};
>> +
>
>    I don't think passing a resource thru platform data is good idea... 
> Resources should be bound to the platform device.
>
> WBR, Sergei 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-18 18:51             ` Arnd Bergmann
@ 2011-02-22  8:42               ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  8:42 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: Thomas Gleixner, Alan Cox, sachi, davinci-linux-open-source,
	Greg Kroah-Hartman, nsekhar, open list, m-watkins

Hello,

I had kept separate files to affirm the modularity and ease of portability 
of the system.

There are three different interfaces,
1. The Linux driver interface
2. The PRU control interface
3. The McASP serializer interface.

To maintain modularity, I  had classified the files respectively as :
1.  pruss_suart.c
2.  pruss_suart_api.c
3.  pruss_suart_utils.c

This is not a single device which can be expressed as a single file,
but functionally different devices logically cascaded together to work in 
unison.

We use the PRU for packet processing, but the actual data is 
transmitted/received through the
McASP, which we use as a serializer.

I feel to combine these disparate functionalities into a single file will 
not

1. Help better understanding the device. I mean, why should a TTY UART 
driver be aware of the McASP or the PRU.
2. In case of a bug in the API layer or McASP, the driver need not be 
touched, thus improve maintainability.
3. If we need to port it to another Linux version, just editing the driver 
file should suffice, this will reduce bugs while porting.

To me, combining all of these into a single file only creates a mess. This 
is the reason I had separated them into different files!!
I don't understand why should it be better to have all of these into a 
single file.

--------------------------------------------------
From: "Arnd Bergmann" <arnd@arndb.de>
Sent: Saturday, February 19, 2011 12:21 AM
To: <linux-arm-kernel@lists.infradead.org>
Cc: "Thomas Gleixner" <tglx@linutronix.de>; "Alan Cox" 
<alan@lxorguk.ukuu.org.uk>; <sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; "Greg Kroah-Hartman" <gregkh@suse.de>; 
<nsekhar@ti.com>; "open list" <linux-kernel@vger.kernel.org>; 
<m-watkins@ti.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
>> On Fri, 18 Feb 2011, Alan Cox wrote:
>>
>> > On Fri, 18 Feb 2011 19:17:38 +0530
>> > "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
>> >
>> > > Hello,
>> > >
>> > > Regarding the semaphore to mutex migration.
>> > > We are using down_trylock in interrupt context,
>> > > mutex_trylock cannot be used in interrupt context, so we cannot use 
>> > > mutex in
>> > > our driver.
>> >
>> > Then you probably need to rework your locking. Best bet might be to fix
>> > all the other stuff and report the driver, and people can think about 
>> > the
>> > locking problem.
>>
>> That semaphore is utterly useless to begin with. There are more
>> serious locking problems than this one. Non serialized calls to
>> suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
>>
>> Aside of that the code is complete unreadable.
>
> I think it mostly suffers from the same problem as the CAN driver
> I commented on earlier: One of the files (pruss_suart_api.c) was
> clearly not written with Linux as the target, and the other files
> try to work around this by wrapping a Linux driver around it.
>
> The suart_api HAL stuff clearly needs to go away, so that the rest
> can be rewritten into a proper device driver.
>
> Arnd 


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-22  8:42               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  8:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

I had kept separate files to affirm the modularity and ease of portability 
of the system.

There are three different interfaces,
1. The Linux driver interface
2. The PRU control interface
3. The McASP serializer interface.

To maintain modularity, I  had classified the files respectively as :
1.  pruss_suart.c
2.  pruss_suart_api.c
3.  pruss_suart_utils.c

This is not a single device which can be expressed as a single file,
but functionally different devices logically cascaded together to work in 
unison.

We use the PRU for packet processing, but the actual data is 
transmitted/received through the
McASP, which we use as a serializer.

I feel to combine these disparate functionalities into a single file will 
not

1. Help better understanding the device. I mean, why should a TTY UART 
driver be aware of the McASP or the PRU.
2. In case of a bug in the API layer or McASP, the driver need not be 
touched, thus improve maintainability.
3. If we need to port it to another Linux version, just editing the driver 
file should suffice, this will reduce bugs while porting.

To me, combining all of these into a single file only creates a mess. This 
is the reason I had separated them into different files!!
I don't understand why should it be better to have all of these into a 
single file.

--------------------------------------------------
From: "Arnd Bergmann" <arnd@arndb.de>
Sent: Saturday, February 19, 2011 12:21 AM
To: <linux-arm-kernel@lists.infradead.org>
Cc: "Thomas Gleixner" <tglx@linutronix.de>; "Alan Cox" 
<alan@lxorguk.ukuu.org.uk>; <sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; "Greg Kroah-Hartman" <gregkh@suse.de>; 
<nsekhar@ti.com>; "open list" <linux-kernel@vger.kernel.org>; 
<m-watkins@ti.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
>> On Fri, 18 Feb 2011, Alan Cox wrote:
>>
>> > On Fri, 18 Feb 2011 19:17:38 +0530
>> > "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
>> >
>> > > Hello,
>> > >
>> > > Regarding the semaphore to mutex migration.
>> > > We are using down_trylock in interrupt context,
>> > > mutex_trylock cannot be used in interrupt context, so we cannot use 
>> > > mutex in
>> > > our driver.
>> >
>> > Then you probably need to rework your locking. Best bet might be to fix
>> > all the other stuff and report the driver, and people can think about 
>> > the
>> > locking problem.
>>
>> That semaphore is utterly useless to begin with. There are more
>> serious locking problems than this one. Non serialized calls to
>> suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
>>
>> Aside of that the code is complete unreadable.
>
> I think it mostly suffers from the same problem as the CAN driver
> I commented on earlier: One of the files (pruss_suart_api.c) was
> clearly not written with Linux as the target, and the other files
> try to work around this by wrapping a Linux driver around it.
>
> The suart_api HAL stuff clearly needs to go away, so that the rest
> can be rewritten into a proper device driver.
>
> Arnd 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-18 18:51             ` Arnd Bergmann
@ 2011-02-22  8:43               ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  8:43 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: Thomas Gleixner, Alan Cox, sachi, davinci-linux-open-source,
	Greg Kroah-Hartman, nsekhar, open list, m-watkins

I agree with the Codingstyle which needs to be fixed and would appreciate 
more feedback on it.

I have also gotten rid of the semaphore completely, please let me know what 
you feel of this implementation:
I have tested this without any problem.
What I am basically doing below is that, I am getting the data from the circ 
buff and then using the interrupt handler to
pump out the data. As the circ buff empties, I am accepting another request 
from the TTY.
Are you noticing any problems with this:

diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart.c 
b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
index d222e2e..edc3863 100644
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -72,7 +72,7 @@ struct suart_fifo {
 struct omapl_pru_suart {
        struct uart_port port[NR_SUART];
        struct device *dev; /* pdev->dev */
-       struct semaphore port_sem[NR_SUART];
+       bool tx_empty[NR_SUART];
        struct clk *clk_mcasp;
        struct suart_fifo suart_fifo_addr[NR_SUART];
        const struct firmware *fw;
@@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
        if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
                return;

-       if (down_trylock(&soft_uart->port_sem[uart_no]))
-               return;
-
        if (uart_circ_empty(xmit) ||
                        uart_tx_stopped(&soft_uart->port[uart_no])) {
                pruss_suart_stop_tx(&soft_uart->port[uart_no]);
-               up(&soft_uart->port_sem[uart_no]);
+               soft_uart->tx_empty[uart_no] = true;
                return;
        }

@@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, void 
*dev_id)
                        pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
                        pru_softuart_clr_tx_status(dev, 
&soft_uart->suart_hdl
                                                 [port->line]);
-                       up(&soft_uart->port_sem[port->line]);
                        omapl_pru_tx_chars(soft_uart, port->line);
                }
        } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
@@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port 
*port)

        suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
                           PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
-       omapl_pru_tx_chars(soft_uart, port->line);
+       if (soft_uart->tx_empty[port->line] == true) {
+               soft_uart->tx_empty[port->line] = false;
+               omapl_pru_tx_chars(soft_uart, port->line);
+       }
 }


--------------------------------------------------
From: "Arnd Bergmann" <arnd@arndb.de>
Sent: Saturday, February 19, 2011 12:21 AM
To: <linux-arm-kernel@lists.infradead.org>
Cc: "Thomas Gleixner" <tglx@linutronix.de>; "Alan Cox" 
<alan@lxorguk.ukuu.org.uk>; <sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; "Greg Kroah-Hartman" <gregkh@suse.de>; 
<nsekhar@ti.com>; "open list" <linux-kernel@vger.kernel.org>; 
<m-watkins@ti.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
>> On Fri, 18 Feb 2011, Alan Cox wrote:
>>
>> > On Fri, 18 Feb 2011 19:17:38 +0530
>> > "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
>> >
>> > > Hello,
>> > >
>> > > Regarding the semaphore to mutex migration.
>> > > We are using down_trylock in interrupt context,
>> > > mutex_trylock cannot be used in interrupt context, so we cannot use 
>> > > mutex in
>> > > our driver.
>> >
>> > Then you probably need to rework your locking. Best bet might be to fix
>> > all the other stuff and report the driver, and people can think about 
>> > the
>> > locking problem.
>>
>> That semaphore is utterly useless to begin with. There are more
>> serious locking problems than this one. Non serialized calls to
>> suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
>>
>> Aside of that the code is complete unreadable.
>
> I think it mostly suffers from the same problem as the CAN driver
> I commented on earlier: One of the files (pruss_suart_api.c) was
> clearly not written with Linux as the target, and the other files
> try to work around this by wrapping a Linux driver around it.
>
> The suart_api HAL stuff clearly needs to go away, so that the rest
> can be rewritten into a proper device driver.
>
> Arnd 


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-22  8:43               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  8:43 UTC (permalink / raw)
  To: linux-arm-kernel

I agree with the Codingstyle which needs to be fixed and would appreciate 
more feedback on it.

I have also gotten rid of the semaphore completely, please let me know what 
you feel of this implementation:
I have tested this without any problem.
What I am basically doing below is that, I am getting the data from the circ 
buff and then using the interrupt handler to
pump out the data. As the circ buff empties, I am accepting another request 
from the TTY.
Are you noticing any problems with this:

diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart.c 
b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
index d222e2e..edc3863 100644
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -72,7 +72,7 @@ struct suart_fifo {
 struct omapl_pru_suart {
        struct uart_port port[NR_SUART];
        struct device *dev; /* pdev->dev */
-       struct semaphore port_sem[NR_SUART];
+       bool tx_empty[NR_SUART];
        struct clk *clk_mcasp;
        struct suart_fifo suart_fifo_addr[NR_SUART];
        const struct firmware *fw;
@@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
        if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
                return;

-       if (down_trylock(&soft_uart->port_sem[uart_no]))
-               return;
-
        if (uart_circ_empty(xmit) ||
                        uart_tx_stopped(&soft_uart->port[uart_no])) {
                pruss_suart_stop_tx(&soft_uart->port[uart_no]);
-               up(&soft_uart->port_sem[uart_no]);
+               soft_uart->tx_empty[uart_no] = true;
                return;
        }

@@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, void 
*dev_id)
                        pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
                        pru_softuart_clr_tx_status(dev, 
&soft_uart->suart_hdl
                                                 [port->line]);
-                       up(&soft_uart->port_sem[port->line]);
                        omapl_pru_tx_chars(soft_uart, port->line);
                }
        } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
@@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port 
*port)

        suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
                           PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
-       omapl_pru_tx_chars(soft_uart, port->line);
+       if (soft_uart->tx_empty[port->line] == true) {
+               soft_uart->tx_empty[port->line] = false;
+               omapl_pru_tx_chars(soft_uart, port->line);
+       }
 }


--------------------------------------------------
From: "Arnd Bergmann" <arnd@arndb.de>
Sent: Saturday, February 19, 2011 12:21 AM
To: <linux-arm-kernel@lists.infradead.org>
Cc: "Thomas Gleixner" <tglx@linutronix.de>; "Alan Cox" 
<alan@lxorguk.ukuu.org.uk>; <sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; "Greg Kroah-Hartman" <gregkh@suse.de>; 
<nsekhar@ti.com>; "open list" <linux-kernel@vger.kernel.org>; 
<m-watkins@ti.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> On Friday 18 February 2011 19:23:49 Thomas Gleixner wrote:
>> On Fri, 18 Feb 2011, Alan Cox wrote:
>>
>> > On Fri, 18 Feb 2011 19:17:38 +0530
>> > "Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:
>> >
>> > > Hello,
>> > >
>> > > Regarding the semaphore to mutex migration.
>> > > We are using down_trylock in interrupt context,
>> > > mutex_trylock cannot be used in interrupt context, so we cannot use 
>> > > mutex in
>> > > our driver.
>> >
>> > Then you probably need to rework your locking. Best bet might be to fix
>> > all the other stuff and report the driver, and people can think about 
>> > the
>> > locking problem.
>>
>> That semaphore is utterly useless to begin with. There are more
>> serious locking problems than this one. Non serialized calls to
>> suart_intr_clrmask/suart_intr_setmask are the most obvious ones.
>>
>> Aside of that the code is complete unreadable.
>
> I think it mostly suffers from the same problem as the CAN driver
> I commented on earlier: One of the files (pruss_suart_api.c) was
> clearly not written with Linux as the target, and the other files
> try to work around this by wrapping a Linux driver around it.
>
> The suart_api HAL stuff clearly needs to go away, so that the rest
> can be rewritten into a proper device driver.
>
> Arnd 

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

* Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
  2011-02-11 18:55     ` Sergei Shtylyov
@ 2011-02-22  9:18       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  9:18 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Hello,

I could not follow your recommendations clearly, are you suggesting this:

int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
{
#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
        int ret;

        ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
                            NULL, &da850_mcasp_device.dev);
        if (ret < 0)
                return ret;
#endif
        da8xx_pruss_dev.dev.platform_data = pruss_device;
        return platform_device_register(&da8xx_pruss_dev);
}

--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:25 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 12/13] da850: pruss SUART platform specific 
additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the McASP clock alias.
>> The alias is used by the pruss suart driver
>> for enabling the McASP PSC.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/devices-da8xx.c 
>> b/arch/arm/mach-davinci/devices-da8xx.c
>> index e15de72..f1cf605 100644
>> --- a/arch/arm/mach-davinci/devices-da8xx.c
>> +++ b/arch/arm/mach-davinci/devices-da8xx.c
>> @@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {
>>  int __init da8xx_register_pruss(struct da8xx_pruss_devices 
>> *pruss_device)
>>  {
>> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
>
>    #ifdef's in the function body are generally fromned upon.
>
>> + int ret;
>> +#endif
>> +
>
>    This line should have been inside #ifdef...
>
>>  da8xx_pruss_dev.dev.platform_data = pruss_device;
>> +
>> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
>
>    Why not do it before assigning the platform data and avoid extra 
> #ifdef?
>
>> + ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
>> + NULL, &da850_mcasp_device.dev);
>
>    This line should be indented more to the right.
>
>> + if (ret < 0)
>> + return ret;
>> +#endif
>
> WBR, Sergei 


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

* [PATCH v2 12/13] da850: pruss SUART platform specific additions.
@ 2011-02-22  9:18       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22  9:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

I could not follow your recommendations clearly, are you suggesting this:

int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
{
#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
        int ret;

        ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
                            NULL, &da850_mcasp_device.dev);
        if (ret < 0)
                return ret;
#endif
        da8xx_pruss_dev.dev.platform_data = pruss_device;
        return platform_device_register(&da8xx_pruss_dev);
}

--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Saturday, February 12, 2011 12:25 AM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 12/13] da850: pruss SUART platform specific 
additions.

> Subhasish Ghosh wrote:
>
>> This patch adds the McASP clock alias.
>> The alias is used by the pruss suart driver
>> for enabling the McASP PSC.
>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> [...]
>
>> diff --git a/arch/arm/mach-davinci/devices-da8xx.c 
>> b/arch/arm/mach-davinci/devices-da8xx.c
>> index e15de72..f1cf605 100644
>> --- a/arch/arm/mach-davinci/devices-da8xx.c
>> +++ b/arch/arm/mach-davinci/devices-da8xx.c
>> @@ -560,7 +560,18 @@ struct platform_device da8xx_pruss_dev = {
>>  int __init da8xx_register_pruss(struct da8xx_pruss_devices 
>> *pruss_device)
>>  {
>> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
>
>    #ifdef's in the function body are generally fromned upon.
>
>> + int ret;
>> +#endif
>> +
>
>    This line should have been inside #ifdef...
>
>>  da8xx_pruss_dev.dev.platform_data = pruss_device;
>> +
>> +#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
>
>    Why not do it before assigning the platform data and avoid extra 
> #ifdef?
>
>> + ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
>> + NULL, &da850_mcasp_device.dev);
>
>    This line should be indented more to the right.
>
>> + if (ret < 0)
>> + return ret;
>> +#endif
>
> WBR, Sergei 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-11 16:28     ` Alan Cox
@ 2011-02-22 10:26       ` Subhasish
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish @ 2011-02-22 10:26 UTC (permalink / raw)
  To: Alan Cox
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list, Stalin Srinivasan

--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Friday, February 11, 2011 9:58 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>; "Greg Kroah-Hartman"
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> Don't see why it needs its own sub-directory

SG - We have two different layers of implementation. One is the driver
layer, which interacts with the TTY sub-system and the other is the API 
layer,
which interacts with the PRUSS. To maintain this (also explained in the 
other mail),
we used separate files and hence we decided to keep the code in a separate
directory so that the related files can be identified easily.

>
>
>
>> +#ifdef __SUART_DEBUG
>> +#define __suart_debug(fmt, args...) \
>> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> +#else
>> +#define __suart_debug(fmt, args...)
>> +#endif
>> +
>> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##
>> args)
>
> Use dev_dbg/dev_err/pr_debug/pr_err

SG - did you mean replace the printks above with dev_dgb/err or the 
suart_dbg/err.

>
>
>> +static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32
>> uart_no)
>> +{
>> + struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
>> + struct device *dev = soft_uart->dev;
>> + s32 count = 0;
>> +
>> + if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>> + return;
>> +
>> + if (down_trylock(&soft_uart->port_sem[uart_no]))
>> + return;
>
> Please use a mutex not a semaphore. We are trying to get almost all the
> kernel using mutexes as it is needed for hard real time.

SG - Have removed, need your feedback.

>
>
>> + pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
>> +        suart_data, data_len + 1,
>> +        &data_len_read);
>> +
>> + for (i = 0; i <= data_len_read; i++) {
>> + soft_uart->port[uart_no].icount.rx++;
>> + /* check for sys rq */
>> + if (uart_handle_sysrq_char
>> +     (&soft_uart->port[uart_no], suart_data))
>> + continue;
>> + }
>> + /* update the tty data structure */
>> + tty_insert_flip_string(tty, suart_data, data_len_read);
>
> You can avoid a copy here by using tty_prepare_flip_string()

SG - Ok, Thus this look ok ?
==================================================================================
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
        s8 flags = TTY_NORMAL;
        u16 rx_status, data_len = SUART_FIFO_LEN;
        u32 data_len_read;
-       u8 suart_data[SUART_FIFO_LEN + 1];
+       u8 *suart_data = NULL;
        s32 i = 0;
+       s32 alloc_len = 0;

        if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
                return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
                soft_uart->port[uart_no].sysrq = 0;
 #endif
        } else {
+               alloc_len = tty_prepare_flip_string(tty, &suart_data, 
data_len + 1);
                pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
-                                      suart_data, data_len + 1,
-                                      &data_len_read);
+                                               suart_data, alloc_len,
+                                               &data_len_read);

                for (i = 0; i <= data_len_read; i++) {
                        soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
                            (&soft_uart->port[uart_no], suart_data))
                                continue;
                }
-               /* update the tty data structure */
-               tty_insert_flip_string(tty, suart_data, data_len_read);
        }
============================================================================================

> Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty
> refcounting is right

SG - Ok, Will do.

>
>
>> +static void pruss_suart_set_termios(struct uart_port *port,
>> +   struct ktermios *termios,
>> +   struct ktermios *old)
>> +{
>> + struct omapl_pru_suart *soft_uart =
>> +     container_of(port, struct omapl_pru_suart, port[port->line]);
>> + struct device *dev = soft_uart->dev;
>> + u8 cval = 0;
>> + unsigned long flags = 0;
>> + u32 baud = 0;
>> + u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
>> +
>> +/*
>> + * Do not allow unsupported configurations to be set
>> + */
>> + if (1) {
>> + termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
>> +       | PARENB | PARODD | CMSPAR);
>> + termios->c_cflag |= CLOCAL;
>
> No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them
> even if in fact they have no effect, so leave those two alone. The rest
> is fine.

SG -Ok, will do.

>
>
>> +/*
>> + * Characteres to ignore
>
> Typo
>

SG - ok.

>
>
>> diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> new file mode 100644
>> index 0000000..d809dd3
>> --- /dev/null
>> +++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> @@ -0,0 +1,2350 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
>> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
>> +#include <linux/mfd/pruss/da8xx_pru.h>
>> +#include <linux/io.h>
>> +#include <mach/hardware.h>
>> +#include "pruss_suart_api.h"
>> +#include "pruss_suart_regs.h"
>> +#include "pruss_suart_board.h"
>> +#include "pruss_suart_utils.h"
>> +#include "pruss_suart_err.h"
>> +
>> +static u8 g_uart_statu_table[8];
> Can you lose the g_, its  a windows naming convention we dont use

SG -- Ok, I can also see the Hungarian style like u32Offset, will get rid of 
these as well.
            Would really appreciate if you may please point me out more such 
problems.

>
>
>> +s16 pru_softuart_open(suart_handle h_suart)
>> +{
>
> If you just used normal integers you could surely make this routine
> trivial and remove all the duplication in the switches

SG -- Ok, will do.

>
>> + s16 status = PRU_SUART_SUCCESS;
>
> And please stick to Linux error codes

SG - Ok, Will do
>
>
>> +/* suart instance close routine */
>> +s16 pru_softuart_close(suart_handle h_uart)
>> +{
>> + s16 status = SUART_SUCCESS;
>> +
>> + if (h_uart == NULL) {
>> + return PRU_SUART_ERR_HANDLE_INVALID;
>
> Which is never checked. Far better to use WARN_ON and the like for such
> cases - or if like this one they don't appear to be possible to simply
> delete them

SG -- OK, does this look ok ?
=================================
if (h_uart == NULL) {
+WARN_ON(1);
- return PRU_SUART_ERR_HANDLE_INVALID;
+return -EINVAL;
}
=================================

>
>> + if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>> + if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>
> [minor] Lots of excess brackets

Ok - Will do.
>
>
>> + u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
>> + u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
>> + s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
>> + if (-1 == s16retval)
>> + return -1;
>
> If you fixed the API here you'd be able to just write
>
> if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF,
> PRU_INTC_BLAH)
>
> or similar which would clean up a lot of messy code and shrink it
> dramatically. Given you have lots of series of writes some kind of
>
> pruss_writel_multi(dev, array, len)
>
> that took an array of addr/value pairs might also clean up a ton of code
> and turn it into trivial tables

SG -- Will shrink this function.

> 

Please do not print this email unless it is absolutely necessary. Spread environmental awareness.

-------------------------------------------------------DISCLAIMER------------------------------------------------------
The information transmitted herewith is confidential and proprietary information intended only for use by the individual or entity to which it is addressed. If the reader of this message is not the intended recipient, you are hereby notified that any review, retransmission, dissemination, distribution, copying or other use of, or taking of any action in reliance upon this information is strictly prohibited. If you have received this communication in error, please contact the sender and delete the material from your computer.
---------------------------------------------------------------------------------------------------------------------------


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-22 10:26       ` Subhasish
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish @ 2011-02-22 10:26 UTC (permalink / raw)
  To: linux-arm-kernel

--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Friday, February 11, 2011 9:58 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>; "Greg Kroah-Hartman"
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> Don't see why it needs its own sub-directory

SG - We have two different layers of implementation. One is the driver
layer, which interacts with the TTY sub-system and the other is the API 
layer,
which interacts with the PRUSS. To maintain this (also explained in the 
other mail),
we used separate files and hence we decided to keep the code in a separate
directory so that the related files can be identified easily.

>
>
>
>> +#ifdef __SUART_DEBUG
>> +#define __suart_debug(fmt, args...) \
>> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> +#else
>> +#define __suart_debug(fmt, args...)
>> +#endif
>> +
>> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##
>> args)
>
> Use dev_dbg/dev_err/pr_debug/pr_err

SG - did you mean replace the printks above with dev_dgb/err or the 
suart_dbg/err.

>
>
>> +static void omapl_pru_tx_chars(struct omapl_pru_suart *soft_uart, u32
>> uart_no)
>> +{
>> + struct circ_buf *xmit = &soft_uart->port[uart_no].state->xmit;
>> + struct device *dev = soft_uart->dev;
>> + s32 count = 0;
>> +
>> + if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>> + return;
>> +
>> + if (down_trylock(&soft_uart->port_sem[uart_no]))
>> + return;
>
> Please use a mutex not a semaphore. We are trying to get almost all the
> kernel using mutexes as it is needed for hard real time.

SG - Have removed, need your feedback.

>
>
>> + pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
>> +        suart_data, data_len + 1,
>> +        &data_len_read);
>> +
>> + for (i = 0; i <= data_len_read; i++) {
>> + soft_uart->port[uart_no].icount.rx++;
>> + /* check for sys rq */
>> + if (uart_handle_sysrq_char
>> +     (&soft_uart->port[uart_no], suart_data))
>> + continue;
>> + }
>> + /* update the tty data structure */
>> + tty_insert_flip_string(tty, suart_data, data_len_read);
>
> You can avoid a copy here by using tty_prepare_flip_string()

SG - Ok, Thus this look ok ?
==================================================================================
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
        s8 flags = TTY_NORMAL;
        u16 rx_status, data_len = SUART_FIFO_LEN;
        u32 data_len_read;
-       u8 suart_data[SUART_FIFO_LEN + 1];
+       u8 *suart_data = NULL;
        s32 i = 0;
+       s32 alloc_len = 0;

        if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
                return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
                soft_uart->port[uart_no].sysrq = 0;
 #endif
        } else {
+               alloc_len = tty_prepare_flip_string(tty, &suart_data, 
data_len + 1);
                pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
-                                      suart_data, data_len + 1,
-                                      &data_len_read);
+                                               suart_data, alloc_len,
+                                               &data_len_read);

                for (i = 0; i <= data_len_read; i++) {
                        soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart 
*soft_uart, u32 uart_no)
                            (&soft_uart->port[uart_no], suart_data))
                                continue;
                }
-               /* update the tty data structure */
-               tty_insert_flip_string(tty, suart_data, data_len_read);
        }
============================================================================================

> Also please use the tty_port_tty_get/tty_kref_put interfaces so the tty
> refcounting is right

SG - Ok, Will do.

>
>
>> +static void pruss_suart_set_termios(struct uart_port *port,
>> +   struct ktermios *termios,
>> +   struct ktermios *old)
>> +{
>> + struct omapl_pru_suart *soft_uart =
>> +     container_of(port, struct omapl_pru_suart, port[port->line]);
>> + struct device *dev = soft_uart->dev;
>> + u8 cval = 0;
>> + unsigned long flags = 0;
>> + u32 baud = 0;
>> + u32 old_csize = old ? old->c_cflag & CSIZE : CS8;
>> +
>> +/*
>> + * Do not allow unsupported configurations to be set
>> + */
>> + if (1) {
>> + termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR | CSTOPB
>> +       | PARENB | PARODD | CMSPAR);
>> + termios->c_cflag |= CLOCAL;
>
> No. CLOCAL and HUPCL are user side flags. Apps expect to able to set them
> even if in fact they have no effect, so leave those two alone. The rest
> is fine.

SG -Ok, will do.

>
>
>> +/*
>> + * Characteres to ignore
>
> Typo
>

SG - ok.

>
>
>> diff --git a/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> new file mode 100644
>> index 0000000..d809dd3
>> --- /dev/null
>> +++ b/drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
>> @@ -0,0 +1,2350 @@
>> +/*
>> + * Copyright (C) 2010 Texas Instruments Incorporated
>> + * Author: Jitendra Kumar <jitendra@mistralsolutions.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/types.h>
>> +#include <linux/mfd/pruss/da8xx_pru.h>
>> +#include <linux/io.h>
>> +#include <mach/hardware.h>
>> +#include "pruss_suart_api.h"
>> +#include "pruss_suart_regs.h"
>> +#include "pruss_suart_board.h"
>> +#include "pruss_suart_utils.h"
>> +#include "pruss_suart_err.h"
>> +
>> +static u8 g_uart_statu_table[8];
> Can you lose the g_, its  a windows naming convention we dont use

SG -- Ok, I can also see the Hungarian style like u32Offset, will get rid of 
these as well.
            Would really appreciate if you may please point me out more such 
problems.

>
>
>> +s16 pru_softuart_open(suart_handle h_suart)
>> +{
>
> If you just used normal integers you could surely make this routine
> trivial and remove all the duplication in the switches

SG -- Ok, will do.

>
>> + s16 status = PRU_SUART_SUCCESS;
>
> And please stick to Linux error codes

SG - Ok, Will do
>
>
>> +/* suart instance close routine */
>> +s16 pru_softuart_close(suart_handle h_uart)
>> +{
>> + s16 status = SUART_SUCCESS;
>> +
>> + if (h_uart == NULL) {
>> + return PRU_SUART_ERR_HANDLE_INVALID;
>
> Which is never checked. Far better to use WARN_ON and the like for such
> cases - or if like this one they don't appear to be possible to simply
> delete them

SG -- OK, does this look ok ?
=================================
if (h_uart == NULL) {
+WARN_ON(1);
- return PRU_SUART_ERR_HANDLE_INVALID;
+return -EINVAL;
}
=================================

>
>> + if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>> + if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
>> + return SUART_INVALID_CLKDIVISOR;
>
> [minor] Lots of excess brackets

Ok - Will do.
>
>
>> + u32offset = (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF);
>> + u32value = PRU_INTC_CHAN_34_SYSEVT_36_39;
>> + s16retval = pruss_writel(dev, u32offset, (u32 *)&u32value, 1);
>> + if (-1 == s16retval)
>> + return -1;
>
> If you fixed the API here you'd be able to just write
>
> if (pruss_writel(dev, PRUSS_INTC_CHANMAP9 & 0xFFFF,
> PRU_INTC_BLAH)
>
> or similar which would clean up a lot of messy code and shrink it
> dramatically. Given you have lots of series of writes some kind of
>
> pruss_writel_multi(dev, array, len)
>
> that took an array of addr/value pairs might also clean up a ton of code
> and turn it into trivial tables

SG -- Will shrink this function.

> 

Please do not print this email unless it is absolutely necessary. Spread environmental awareness.

-------------------------------------------------------DISCLAIMER------------------------------------------------------
The information transmitted herewith is confidential and proprietary information intended only for use by the individual or entity to which it is addressed. If the reader of this message is not the intended recipient, you are hereby notified that any review, retransmission, dissemination, distribution, copying or other use of, or taking of any action in reliance upon this information is strictly prohibited. If you have received this communication in error, please contact the sender and delete the material from your computer.
---------------------------------------------------------------------------------------------------------------------------

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22  5:43       ` Subhasish Ghosh
@ 2011-02-22 10:31         ` Samuel Ortiz
  -1 siblings, 0 replies; 157+ messages in thread
From: Samuel Ortiz @ 2011-02-22 10:31 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, open list

Hi Subhasish,

On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
> Thank you for your comments.
No problem.

> >>diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >>index fd01836..6c437df 100644
> >>--- a/drivers/mfd/Kconfig
> >>+++ b/drivers/mfd/Kconfig
> >>@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
> >>   boards.  MSP430 firmware manages resets and power sequencing,
> >>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
> >>
> >>+config MFD_DA8XX_PRUSS
> >>+ tristate "Texas Instruments DA8XX PRUSS support"
> >>+ depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> >Why are we depending on those ?
> 
> SG -- The PRUSS core in only available within DA850 and DA830,
>            DA830 support is not yet implemented.
Sure, but if there are no actual code dependencies, I'd like to get rid of
those depends.

> >>+u32 pruss_disable(struct device *dev, u8 pruss_num)
> >>+{
> >>+ struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
> >>+ da8xx_prusscore_regs h_pruss;
> >>+ u32 temp_reg;
> >>+
> >>+ if (pruss_num == DA8XX_PRUCORE_0) {
> >>+ /* Disable PRU0  */
> >>+ h_pruss = (da8xx_prusscore_regs)
> >>+ ((u32) pruss->ioaddr + 0x7000);
> >So it seems you're doing this in several places, and I have a few
> >comments:
> >
> >- You don't need the da8xx_prusscore_regs at all.
> >- Define the register map through a set of #define in your header file.
> >- Use a static routine that takes the core number and returns the
> >register map
> >offset.
> >
> >Then routines like this one will look a lot more readable.
> 
> SG -- There are a huge number of PRUSS registers. A lot of them are
> reserved and are expected to change as development on the
>            controller is still ongoing. 
First of all, from what I read in your patch you're only using the CONTROL
offset.

> If we use #defines to plot
> all the registers, then first, there are too many array type
> registers which will need to be duplicated.
What I'm expecting is a small set of defines for the register offsets. You
have 13 fields in your da8xx_prusscore_regs, you only need to define 13
register offsets.

So, if you have a:

static u32 reg_offset(struct device *dev, u8 pru_num)
{
	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);

	switch (pru_num) {
	case DA8XX_PRUCORE_0:
		return (u32) pru->ioaddr + 0x7000;
	case DA8XX_PRUCORE_1:
		return (u32) pru->ioaddr + 0x7800;
	default:
		return 0;
}


then routines like pruss_enable (which should return an int, btw) would look
like:

int pruss_enable(struct device *dev, u8 pruss_num)
{
	u32 offset = reg_offset(dev, pruss_num);

	if (offset == 0)
		return -EINVAL;

	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
			offset + PRU_CORE_CONTROL);

	return 0;
}

> >Also, all your exported routines severely lack any sort of locking. An IO
> >mutex or spinlock is mandatory here.
> 
> SG - As per our current implementation, we do not have two devices
> running simultaneously on the PRU,
>        so we do not have any way to test it. We have kept this as an
> enhancement if request comes in for
>        multiple devices.
It's not about having multiple devices at the same time, it's about having
multiple callers writing and reading to the same registers. Since you're
exporting all your I/O routines you have no way to prevent 2 drivers from
writing to the same register at the "same" time. You need locking here,
regardless of the number of devices that you can have on a system.

 
> >>+static int pruss_mfd_add_devices(struct platform_device *pdev)
> >>+{
> >>+ struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
> >>+ struct device *dev = &pdev->dev;
> >>+ struct mfd_cell cell;
> >>+ u32 err, count;
> >>+
> >>+ for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
> >>+ memset(&cell, 0, sizeof(struct mfd_cell));
> >>+ cell.id = count;
> >>+ cell.name = (dev_data + count)->dev_name;
> >>+ cell.platform_data = (dev_data + count)->pdata;
> >>+ cell.data_size = (dev_data + count)->pdata_size;
> >>+
> >>+ err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
> >>+ if (err) {
> >>+ dev_err(dev, "cannot add mfd cells\n");
> >>+ return err;
> >>+ }
> >>+ }
> >>+ return err;
> >>+}
> >So, what are the potential subdevices for this driver ? If it's a really
> >dynamic setup, I'm fine with passing those as platform data but
> >then do it so
> >that you pass a NULL terminated da8xx_pruss_devices array. That will avoid
> >most of the ugly casts you're doing here.
> 
> SG -- I did not follow your recommendations here, could you please
> elaborate.
>            I am already checking the dev_name for a NULL.
>            This device is basically a microcontroller within DA850,
> so basically any device or protocol can be
>            emulated on it. Currently, we have emulated 8 UARTS using
> the two PRUs and also a CAN device.
Ok, I wasnt sure you can emulate anything on that thing. So I'm fine with you
passing all your devices through platform_data. But I'd prefer this routine to
look like:

[...]
	for (count = 0; dev_data[count] != NULL; count++) {
		memset(&cell, 0, sizeof(struct mfd_cell));
		cell.id			= count;
		cell.name		= dev_data[count]->dev_name;
		cell.platform_data	= dev_data[count]->pdata;
		cell.data_size		= dev_data[count]->pdata_size;

Looks nicer to me.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-22 10:31         ` Samuel Ortiz
  0 siblings, 0 replies; 157+ messages in thread
From: Samuel Ortiz @ 2011-02-22 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Subhasish,

On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
> Thank you for your comments.
No problem.

> >>diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >>index fd01836..6c437df 100644
> >>--- a/drivers/mfd/Kconfig
> >>+++ b/drivers/mfd/Kconfig
> >>@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
> >>   boards.  MSP430 firmware manages resets and power sequencing,
> >>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
> >>
> >>+config MFD_DA8XX_PRUSS
> >>+ tristate "Texas Instruments DA8XX PRUSS support"
> >>+ depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> >Why are we depending on those ?
> 
> SG -- The PRUSS core in only available within DA850 and DA830,
>            DA830 support is not yet implemented.
Sure, but if there are no actual code dependencies, I'd like to get rid of
those depends.

> >>+u32 pruss_disable(struct device *dev, u8 pruss_num)
> >>+{
> >>+ struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
> >>+ da8xx_prusscore_regs h_pruss;
> >>+ u32 temp_reg;
> >>+
> >>+ if (pruss_num == DA8XX_PRUCORE_0) {
> >>+ /* Disable PRU0  */
> >>+ h_pruss = (da8xx_prusscore_regs)
> >>+ ((u32) pruss->ioaddr + 0x7000);
> >So it seems you're doing this in several places, and I have a few
> >comments:
> >
> >- You don't need the da8xx_prusscore_regs at all.
> >- Define the register map through a set of #define in your header file.
> >- Use a static routine that takes the core number and returns the
> >register map
> >offset.
> >
> >Then routines like this one will look a lot more readable.
> 
> SG -- There are a huge number of PRUSS registers. A lot of them are
> reserved and are expected to change as development on the
>            controller is still ongoing. 
First of all, from what I read in your patch you're only using the CONTROL
offset.

> If we use #defines to plot
> all the registers, then first, there are too many array type
> registers which will need to be duplicated.
What I'm expecting is a small set of defines for the register offsets. You
have 13 fields in your da8xx_prusscore_regs, you only need to define 13
register offsets.

So, if you have a:

static u32 reg_offset(struct device *dev, u8 pru_num)
{
	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);

	switch (pru_num) {
	case DA8XX_PRUCORE_0:
		return (u32) pru->ioaddr + 0x7000;
	case DA8XX_PRUCORE_1:
		return (u32) pru->ioaddr + 0x7800;
	default:
		return 0;
}


then routines like pruss_enable (which should return an int, btw) would look
like:

int pruss_enable(struct device *dev, u8 pruss_num)
{
	u32 offset = reg_offset(dev, pruss_num);

	if (offset == 0)
		return -EINVAL;

	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
			offset + PRU_CORE_CONTROL);

	return 0;
}

> >Also, all your exported routines severely lack any sort of locking. An IO
> >mutex or spinlock is mandatory here.
> 
> SG - As per our current implementation, we do not have two devices
> running simultaneously on the PRU,
>        so we do not have any way to test it. We have kept this as an
> enhancement if request comes in for
>        multiple devices.
It's not about having multiple devices at the same time, it's about having
multiple callers writing and reading to the same registers. Since you're
exporting all your I/O routines you have no way to prevent 2 drivers from
writing to the same register at the "same" time. You need locking here,
regardless of the number of devices that you can have on a system.

 
> >>+static int pruss_mfd_add_devices(struct platform_device *pdev)
> >>+{
> >>+ struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
> >>+ struct device *dev = &pdev->dev;
> >>+ struct mfd_cell cell;
> >>+ u32 err, count;
> >>+
> >>+ for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
> >>+ memset(&cell, 0, sizeof(struct mfd_cell));
> >>+ cell.id = count;
> >>+ cell.name = (dev_data + count)->dev_name;
> >>+ cell.platform_data = (dev_data + count)->pdata;
> >>+ cell.data_size = (dev_data + count)->pdata_size;
> >>+
> >>+ err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
> >>+ if (err) {
> >>+ dev_err(dev, "cannot add mfd cells\n");
> >>+ return err;
> >>+ }
> >>+ }
> >>+ return err;
> >>+}
> >So, what are the potential subdevices for this driver ? If it's a really
> >dynamic setup, I'm fine with passing those as platform data but
> >then do it so
> >that you pass a NULL terminated da8xx_pruss_devices array. That will avoid
> >most of the ugly casts you're doing here.
> 
> SG -- I did not follow your recommendations here, could you please
> elaborate.
>            I am already checking the dev_name for a NULL.
>            This device is basically a microcontroller within DA850,
> so basically any device or protocol can be
>            emulated on it. Currently, we have emulated 8 UARTS using
> the two PRUs and also a CAN device.
Ok, I wasnt sure you can emulate anything on that thing. So I'm fine with you
passing all your devices through platform_data. But I'd prefer this routine to
look like:

[...]
	for (count = 0; dev_data[count] != NULL; count++) {
		memset(&cell, 0, sizeof(struct mfd_cell));
		cell.id			= count;
		cell.name		= dev_data[count]->dev_name;
		cell.platform_data	= dev_data[count]->pdata;
		cell.data_size		= dev_data[count]->pdata_size;

Looks nicer to me.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22 10:31         ` Samuel Ortiz
@ 2011-02-22 10:48           ` Wolfgang Grandegger
  -1 siblings, 0 replies; 157+ messages in thread
From: Wolfgang Grandegger @ 2011-02-22 10:48 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Subhasish Ghosh, sachi, davinci-linux-open-source, nsekhar,
	open list, m-watkins, linux-arm-kernel

On 02/22/2011 11:31 AM, Samuel Ortiz wrote:
> Hi Subhasish,
> 
> On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
>> Thank you for your comments.
> No problem.
> 
>>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>>>> index fd01836..6c437df 100644
>>>> --- a/drivers/mfd/Kconfig
>>>> +++ b/drivers/mfd/Kconfig
>>>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>>>>   boards.  MSP430 firmware manages resets and power sequencing,
>>>>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
>>>>
>>>> +config MFD_DA8XX_PRUSS
>>>> + tristate "Texas Instruments DA8XX PRUSS support"
>>>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
>>> Why are we depending on those ?
>>
>> SG -- The PRUSS core in only available within DA850 and DA830,
>>            DA830 support is not yet implemented.
> Sure, but if there are no actual code dependencies, I'd like to get rid of
> those depends.
> 
>>>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
>>>> +{
>>>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>>>> + da8xx_prusscore_regs h_pruss;
>>>> + u32 temp_reg;
>>>> +
>>>> + if (pruss_num == DA8XX_PRUCORE_0) {
>>>> + /* Disable PRU0  */
>>>> + h_pruss = (da8xx_prusscore_regs)
>>>> + ((u32) pruss->ioaddr + 0x7000);
>>> So it seems you're doing this in several places, and I have a few
>>> comments:
>>>
>>> - You don't need the da8xx_prusscore_regs at all.
>>> - Define the register map through a set of #define in your header file.
>>> - Use a static routine that takes the core number and returns the
>>> register map
>>> offset.
>>>
>>> Then routines like this one will look a lot more readable.
>>
>> SG -- There are a huge number of PRUSS registers. A lot of them are
>> reserved and are expected to change as development on the
>>            controller is still ongoing. 
> First of all, from what I read in your patch you're only using the CONTROL
> offset.
> 
>> If we use #defines to plot
>> all the registers, then first, there are too many array type
>> registers which will need to be duplicated.
> What I'm expecting is a small set of defines for the register offsets. You
> have 13 fields in your da8xx_prusscore_regs, you only need to define 13
> register offsets.
> 
> So, if you have a:
> 
> static u32 reg_offset(struct device *dev, u8 pru_num)
> {
> 	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
> 
> 	switch (pru_num) {
> 	case DA8XX_PRUCORE_0:
> 		return (u32) pru->ioaddr + 0x7000;
> 	case DA8XX_PRUCORE_1:
> 		return (u32) pru->ioaddr + 0x7800;
> 	default:
> 		return 0;
> }
> 
> 
> then routines like pruss_enable (which should return an int, btw) would look
> like:
> 
> int pruss_enable(struct device *dev, u8 pruss_num)
> {
> 	u32 offset = reg_offset(dev, pruss_num);
> 
> 	if (offset == 0)
> 		return -EINVAL;
> 
> 	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> 			offset + PRU_CORE_CONTROL);
> 
> 	return 0;
> }

All registers are memory mapped and could nicely be described by
structures (and sub-structures). Therefore we asked to considerer
structs, at least for the Pruss SocketCAN drivers. That would result in
much much clearer and better readable code. The code above would shrink to:

	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
		     &prucore[pruss_num].control);

And proper type checking would be ensured as well.

Wolfgang.




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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-22 10:48           ` Wolfgang Grandegger
  0 siblings, 0 replies; 157+ messages in thread
From: Wolfgang Grandegger @ 2011-02-22 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/22/2011 11:31 AM, Samuel Ortiz wrote:
> Hi Subhasish,
> 
> On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
>> Thank you for your comments.
> No problem.
> 
>>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>>>> index fd01836..6c437df 100644
>>>> --- a/drivers/mfd/Kconfig
>>>> +++ b/drivers/mfd/Kconfig
>>>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>>>>   boards.  MSP430 firmware manages resets and power sequencing,
>>>>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
>>>>
>>>> +config MFD_DA8XX_PRUSS
>>>> + tristate "Texas Instruments DA8XX PRUSS support"
>>>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
>>> Why are we depending on those ?
>>
>> SG -- The PRUSS core in only available within DA850 and DA830,
>>            DA830 support is not yet implemented.
> Sure, but if there are no actual code dependencies, I'd like to get rid of
> those depends.
> 
>>>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
>>>> +{
>>>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>>>> + da8xx_prusscore_regs h_pruss;
>>>> + u32 temp_reg;
>>>> +
>>>> + if (pruss_num == DA8XX_PRUCORE_0) {
>>>> + /* Disable PRU0  */
>>>> + h_pruss = (da8xx_prusscore_regs)
>>>> + ((u32) pruss->ioaddr + 0x7000);
>>> So it seems you're doing this in several places, and I have a few
>>> comments:
>>>
>>> - You don't need the da8xx_prusscore_regs at all.
>>> - Define the register map through a set of #define in your header file.
>>> - Use a static routine that takes the core number and returns the
>>> register map
>>> offset.
>>>
>>> Then routines like this one will look a lot more readable.
>>
>> SG -- There are a huge number of PRUSS registers. A lot of them are
>> reserved and are expected to change as development on the
>>            controller is still ongoing. 
> First of all, from what I read in your patch you're only using the CONTROL
> offset.
> 
>> If we use #defines to plot
>> all the registers, then first, there are too many array type
>> registers which will need to be duplicated.
> What I'm expecting is a small set of defines for the register offsets. You
> have 13 fields in your da8xx_prusscore_regs, you only need to define 13
> register offsets.
> 
> So, if you have a:
> 
> static u32 reg_offset(struct device *dev, u8 pru_num)
> {
> 	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
> 
> 	switch (pru_num) {
> 	case DA8XX_PRUCORE_0:
> 		return (u32) pru->ioaddr + 0x7000;
> 	case DA8XX_PRUCORE_1:
> 		return (u32) pru->ioaddr + 0x7800;
> 	default:
> 		return 0;
> }
> 
> 
> then routines like pruss_enable (which should return an int, btw) would look
> like:
> 
> int pruss_enable(struct device *dev, u8 pruss_num)
> {
> 	u32 offset = reg_offset(dev, pruss_num);
> 
> 	if (offset == 0)
> 		return -EINVAL;
> 
> 	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> 			offset + PRU_CORE_CONTROL);
> 
> 	return 0;
> }

All registers are memory mapped and could nicely be described by
structures (and sub-structures). Therefore we asked to considerer
structs, at least for the Pruss SocketCAN drivers. That would result in
much much clearer and better readable code. The code above would shrink to:

	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
		     &prucore[pruss_num].control);

And proper type checking would be ensured as well.

Wolfgang.

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-22 10:26       ` Subhasish
@ 2011-02-22 11:11         ` Alan Cox
  -1 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-02-22 11:11 UTC (permalink / raw)
  To: Subhasish
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list, Stalin Srinivasan

> we used separate files and hence we decided to keep the code in a separate
> directory so that the related files can be identified easily.

Fair enough but I would have thought you could drop the two files in the
serial directory if they have obviously related names- trivial item/
> 
> >
> >
> >
> >> +#ifdef __SUART_DEBUG
> >> +#define __suart_debug(fmt, args...) \
> >> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
> >> +#else
> >> +#define __suart_debug(fmt, args...)
> >> +#endif
> >> +
> >> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##
> >> args)
> >
> > Use dev_dbg/dev_err/pr_debug/pr_err
> 
> SG - did you mean replace the printks above with dev_dgb/err or the 
> suart_dbg/err.

Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you
to configure debug levels and the like nicely as well as producing
clearer printk info. In some cases with tty code you may not know the
device so have to use pr_err/pr_debug etc.

Ok

> > Which is never checked. Far better to use WARN_ON and the like for such
> > cases - or if like this one they don't appear to be possible to simply
> > delete them
> 
> SG -- OK, does this look ok ?
> =================================
> if (h_uart == NULL) {
> +WARN_ON(1);
> - return PRU_SUART_ERR_HANDLE_INVALID;
> +return -EINVAL;
> }

Yep - the user will now get a backtrace, and in addition kerneloops.org
can capture it if that is set up in the distro in use.

Alan

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-22 11:11         ` Alan Cox
  0 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-02-22 11:11 UTC (permalink / raw)
  To: linux-arm-kernel

> we used separate files and hence we decided to keep the code in a separate
> directory so that the related files can be identified easily.

Fair enough but I would have thought you could drop the two files in the
serial directory if they have obviously related names- trivial item/
> 
> >
> >
> >
> >> +#ifdef __SUART_DEBUG
> >> +#define __suart_debug(fmt, args...) \
> >> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
> >> +#else
> >> +#define __suart_debug(fmt, args...)
> >> +#endif
> >> +
> >> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, ##
> >> args)
> >
> > Use dev_dbg/dev_err/pr_debug/pr_err
> 
> SG - did you mean replace the printks above with dev_dgb/err or the 
> suart_dbg/err.

Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you
to configure debug levels and the like nicely as well as producing
clearer printk info. In some cases with tty code you may not know the
device so have to use pr_err/pr_debug etc.

Ok

> > Which is never checked. Far better to use WARN_ON and the like for such
> > cases - or if like this one they don't appear to be possible to simply
> > delete them
> 
> SG -- OK, does this look ok ?
> =================================
> if (h_uart == NULL) {
> +WARN_ON(1);
> - return PRU_SUART_ERR_HANDLE_INVALID;
> +return -EINVAL;
> }

Yep - the user will now get a backtrace, and in addition kerneloops.org
can capture it if that is set up in the distro in use.

Alan

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

* Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
  2011-02-22  9:18       ` Subhasish Ghosh
@ 2011-02-22 11:20         ` Sergei Shtylyov
  -1 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-22 11:20 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Hello.

On 22-02-2011 12:18, Subhasish Ghosh wrote:

> I could not follow your recommendations clearly, are you suggesting this:

> int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
> {
> #ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
> int ret;
>
> ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
> NULL, &da850_mcasp_device.dev);
> if (ret < 0)
> return ret;
> #endif
> da8xx_pruss_dev.dev.platform_data = pruss_device;
> return platform_device_register(&da8xx_pruss_dev);
> }

    Yes. But still better would be to wrap clk_add_alias() into a function of 
its own (defining it empty if CONFIG_SERIAL_PRUSS_SUART_MODULE is not defined).

WBR, Sergei

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

* [PATCH v2 12/13] da850: pruss SUART platform specific additions.
@ 2011-02-22 11:20         ` Sergei Shtylyov
  0 siblings, 0 replies; 157+ messages in thread
From: Sergei Shtylyov @ 2011-02-22 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

On 22-02-2011 12:18, Subhasish Ghosh wrote:

> I could not follow your recommendations clearly, are you suggesting this:

> int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
> {
> #ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
> int ret;
>
> ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
> NULL, &da850_mcasp_device.dev);
> if (ret < 0)
> return ret;
> #endif
> da8xx_pruss_dev.dev.platform_data = pruss_device;
> return platform_device_register(&da8xx_pruss_dev);
> }

    Yes. But still better would be to wrap clk_add_alias() into a function of 
its own (defining it empty if CONFIG_SERIAL_PRUSS_SUART_MODULE is not defined).

WBR, Sergei

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22 10:48           ` Wolfgang Grandegger
@ 2011-02-22 11:33             ` Samuel Ortiz
  -1 siblings, 0 replies; 157+ messages in thread
From: Samuel Ortiz @ 2011-02-22 11:33 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: Subhasish Ghosh, sachi, davinci-linux-open-source, nsekhar,
	open list, m-watkins, linux-arm-kernel

On Tue, Feb 22, 2011 at 11:48:51AM +0100, Wolfgang Grandegger wrote:
> On 02/22/2011 11:31 AM, Samuel Ortiz wrote:
> > Hi Subhasish,
> > 
> > On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
> >> Thank you for your comments.
> > No problem.
> > 
> >>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >>>> index fd01836..6c437df 100644
> >>>> --- a/drivers/mfd/Kconfig
> >>>> +++ b/drivers/mfd/Kconfig
> >>>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
> >>>>   boards.  MSP430 firmware manages resets and power sequencing,
> >>>>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
> >>>>
> >>>> +config MFD_DA8XX_PRUSS
> >>>> + tristate "Texas Instruments DA8XX PRUSS support"
> >>>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> >>> Why are we depending on those ?
> >>
> >> SG -- The PRUSS core in only available within DA850 and DA830,
> >>            DA830 support is not yet implemented.
> > Sure, but if there are no actual code dependencies, I'd like to get rid of
> > those depends.
> > 
> >>>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
> >>>> +{
> >>>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
> >>>> + da8xx_prusscore_regs h_pruss;
> >>>> + u32 temp_reg;
> >>>> +
> >>>> + if (pruss_num == DA8XX_PRUCORE_0) {
> >>>> + /* Disable PRU0  */
> >>>> + h_pruss = (da8xx_prusscore_regs)
> >>>> + ((u32) pruss->ioaddr + 0x7000);
> >>> So it seems you're doing this in several places, and I have a few
> >>> comments:
> >>>
> >>> - You don't need the da8xx_prusscore_regs at all.
> >>> - Define the register map through a set of #define in your header file.
> >>> - Use a static routine that takes the core number and returns the
> >>> register map
> >>> offset.
> >>>
> >>> Then routines like this one will look a lot more readable.
> >>
> >> SG -- There are a huge number of PRUSS registers. A lot of them are
> >> reserved and are expected to change as development on the
> >>            controller is still ongoing. 
> > First of all, from what I read in your patch you're only using the CONTROL
> > offset.
> > 
> >> If we use #defines to plot
> >> all the registers, then first, there are too many array type
> >> registers which will need to be duplicated.
> > What I'm expecting is a small set of defines for the register offsets. You
> > have 13 fields in your da8xx_prusscore_regs, you only need to define 13
> > register offsets.
> > 
> > So, if you have a:
> > 
> > static u32 reg_offset(struct device *dev, u8 pru_num)
> > {
> > 	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
> > 
> > 	switch (pru_num) {
> > 	case DA8XX_PRUCORE_0:
> > 		return (u32) pru->ioaddr + 0x7000;
> > 	case DA8XX_PRUCORE_1:
> > 		return (u32) pru->ioaddr + 0x7800;
> > 	default:
> > 		return 0;
> > }
> > 
> > 
> > then routines like pruss_enable (which should return an int, btw) would look
> > like:
> > 
> > int pruss_enable(struct device *dev, u8 pruss_num)
> > {
> > 	u32 offset = reg_offset(dev, pruss_num);
> > 
> > 	if (offset == 0)
> > 		return -EINVAL;
> > 
> > 	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> > 			offset + PRU_CORE_CONTROL);
> > 
> > 	return 0;
> > }
> 
> All registers are memory mapped and could nicely be described by
> structures (and sub-structures). Therefore we asked to considerer
> structs, at least for the Pruss SocketCAN drivers. 
>
> That would result in
> much much clearer and better readable code. The code above would shrink to:
> 
> 	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> 		     &prucore[pruss_num].control);
This driver seems to exclusively use the control offset, which is why I don't
see an absolute need for doing this mapping.
But if both maps are contiguous then doing the mapping would prevent us from
calling reg_offset() and would bring some advantage. I'd then be fine with it.
For now, da8xx_prusscore_regs seems to be larger than the 0x800 interval
between the 2 maps, so I have no idea if both maps are indeed contiguous.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-22 11:33             ` Samuel Ortiz
  0 siblings, 0 replies; 157+ messages in thread
From: Samuel Ortiz @ 2011-02-22 11:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Feb 22, 2011 at 11:48:51AM +0100, Wolfgang Grandegger wrote:
> On 02/22/2011 11:31 AM, Samuel Ortiz wrote:
> > Hi Subhasish,
> > 
> > On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
> >> Thank you for your comments.
> > No problem.
> > 
> >>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >>>> index fd01836..6c437df 100644
> >>>> --- a/drivers/mfd/Kconfig
> >>>> +++ b/drivers/mfd/Kconfig
> >>>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
> >>>>   boards.  MSP430 firmware manages resets and power sequencing,
> >>>>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
> >>>>
> >>>> +config MFD_DA8XX_PRUSS
> >>>> + tristate "Texas Instruments DA8XX PRUSS support"
> >>>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> >>> Why are we depending on those ?
> >>
> >> SG -- The PRUSS core in only available within DA850 and DA830,
> >>            DA830 support is not yet implemented.
> > Sure, but if there are no actual code dependencies, I'd like to get rid of
> > those depends.
> > 
> >>>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
> >>>> +{
> >>>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
> >>>> + da8xx_prusscore_regs h_pruss;
> >>>> + u32 temp_reg;
> >>>> +
> >>>> + if (pruss_num == DA8XX_PRUCORE_0) {
> >>>> + /* Disable PRU0  */
> >>>> + h_pruss = (da8xx_prusscore_regs)
> >>>> + ((u32) pruss->ioaddr + 0x7000);
> >>> So it seems you're doing this in several places, and I have a few
> >>> comments:
> >>>
> >>> - You don't need the da8xx_prusscore_regs at all.
> >>> - Define the register map through a set of #define in your header file.
> >>> - Use a static routine that takes the core number and returns the
> >>> register map
> >>> offset.
> >>>
> >>> Then routines like this one will look a lot more readable.
> >>
> >> SG -- There are a huge number of PRUSS registers. A lot of them are
> >> reserved and are expected to change as development on the
> >>            controller is still ongoing. 
> > First of all, from what I read in your patch you're only using the CONTROL
> > offset.
> > 
> >> If we use #defines to plot
> >> all the registers, then first, there are too many array type
> >> registers which will need to be duplicated.
> > What I'm expecting is a small set of defines for the register offsets. You
> > have 13 fields in your da8xx_prusscore_regs, you only need to define 13
> > register offsets.
> > 
> > So, if you have a:
> > 
> > static u32 reg_offset(struct device *dev, u8 pru_num)
> > {
> > 	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
> > 
> > 	switch (pru_num) {
> > 	case DA8XX_PRUCORE_0:
> > 		return (u32) pru->ioaddr + 0x7000;
> > 	case DA8XX_PRUCORE_1:
> > 		return (u32) pru->ioaddr + 0x7800;
> > 	default:
> > 		return 0;
> > }
> > 
> > 
> > then routines like pruss_enable (which should return an int, btw) would look
> > like:
> > 
> > int pruss_enable(struct device *dev, u8 pruss_num)
> > {
> > 	u32 offset = reg_offset(dev, pruss_num);
> > 
> > 	if (offset == 0)
> > 		return -EINVAL;
> > 
> > 	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> > 			offset + PRU_CORE_CONTROL);
> > 
> > 	return 0;
> > }
> 
> All registers are memory mapped and could nicely be described by
> structures (and sub-structures). Therefore we asked to considerer
> structs, at least for the Pruss SocketCAN drivers. 
>
> That would result in
> much much clearer and better readable code. The code above would shrink to:
> 
> 	__raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> 		     &prucore[pruss_num].control);
This driver seems to exclusively use the control offset, which is why I don't
see an absolute need for doing this mapping.
But if both maps are contiguous then doing the mapping would prevent us from
calling reg_offset() and would bring some advantage. I'd then be fine with it.
For now, da8xx_prusscore_regs seems to be larger than the 0x800 interval
between the 2 maps, so I have no idea if both maps are indeed contiguous.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22 11:33             ` Samuel Ortiz
@ 2011-02-22 12:49               ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22 12:49 UTC (permalink / raw)
  To: Samuel Ortiz, Wolfgang Grandegger
  Cc: sachi, davinci-linux-open-source, nsekhar, open list, m-watkins,
	linux-arm-kernel

I am not sure if I understood you correctly, but the current sizeof the 
structure da8xx_prusscore_regs  is 0x500.

Here is a link to the PRUSS memory map:
http://processors.wiki.ti.com/index.php/PRUSS_Memory_Map

The offset 0x00007000 is the PRU0 reg offset and 0x00007800 is the PRU1 reg 
offset.
We cannot have a register file larger than this, but lot of space is left 
out, possibly for future development.

--------------------------------------------------
From: "Samuel Ortiz" <sameo@linux.intel.com>
Sent: Tuesday, February 22, 2011 5:03 PM
To: "Wolfgang Grandegger" <wg@grandegger.com>
Cc: "Subhasish Ghosh" <subhasish@mistralsolutions.com>; 
<sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; <nsekhar@ti.com>; "open 
list" <linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.

> On Tue, Feb 22, 2011 at 11:48:51AM +0100, Wolfgang Grandegger wrote:
>> On 02/22/2011 11:31 AM, Samuel Ortiz wrote:
>> > Hi Subhasish,
>> >
>> > On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
>> >> Thank you for your comments.
>> > No problem.
>> >
>> >>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> >>>> index fd01836..6c437df 100644
>> >>>> --- a/drivers/mfd/Kconfig
>> >>>> +++ b/drivers/mfd/Kconfig
>> >>>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>> >>>>   boards.  MSP430 firmware manages resets and power sequencing,
>> >>>>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
>> >>>>
>> >>>> +config MFD_DA8XX_PRUSS
>> >>>> + tristate "Texas Instruments DA8XX PRUSS support"
>> >>>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
>> >>> Why are we depending on those ?
>> >>
>> >> SG -- The PRUSS core in only available within DA850 and DA830,
>> >>            DA830 support is not yet implemented.
>> > Sure, but if there are no actual code dependencies, I'd like to get rid 
>> > of
>> > those depends.
>> >
>> >>>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
>> >>>> +{
>> >>>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>> >>>> + da8xx_prusscore_regs h_pruss;
>> >>>> + u32 temp_reg;
>> >>>> +
>> >>>> + if (pruss_num == DA8XX_PRUCORE_0) {
>> >>>> + /* Disable PRU0  */
>> >>>> + h_pruss = (da8xx_prusscore_regs)
>> >>>> + ((u32) pruss->ioaddr + 0x7000);
>> >>> So it seems you're doing this in several places, and I have a few
>> >>> comments:
>> >>>
>> >>> - You don't need the da8xx_prusscore_regs at all.
>> >>> - Define the register map through a set of #define in your header 
>> >>> file.
>> >>> - Use a static routine that takes the core number and returns the
>> >>> register map
>> >>> offset.
>> >>>
>> >>> Then routines like this one will look a lot more readable.
>> >>
>> >> SG -- There are a huge number of PRUSS registers. A lot of them are
>> >> reserved and are expected to change as development on the
>> >>            controller is still ongoing.
>> > First of all, from what I read in your patch you're only using the 
>> > CONTROL
>> > offset.
>> >
>> >> If we use #defines to plot
>> >> all the registers, then first, there are too many array type
>> >> registers which will need to be duplicated.
>> > What I'm expecting is a small set of defines for the register offsets. 
>> > You
>> > have 13 fields in your da8xx_prusscore_regs, you only need to define 13
>> > register offsets.
>> >
>> > So, if you have a:
>> >
>> > static u32 reg_offset(struct device *dev, u8 pru_num)
>> > {
>> > struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
>> >
>> > switch (pru_num) {
>> > case DA8XX_PRUCORE_0:
>> > return (u32) pru->ioaddr + 0x7000;
>> > case DA8XX_PRUCORE_1:
>> > return (u32) pru->ioaddr + 0x7800;
>> > default:
>> > return 0;
>> > }
>> >
>> >
>> > then routines like pruss_enable (which should return an int, btw) would 
>> > look
>> > like:
>> >
>> > int pruss_enable(struct device *dev, u8 pruss_num)
>> > {
>> > u32 offset = reg_offset(dev, pruss_num);
>> >
>> > if (offset == 0)
>> > return -EINVAL;
>> >
>> > __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
>> > offset + PRU_CORE_CONTROL);
>> >
>> > return 0;
>> > }
>>
>> All registers are memory mapped and could nicely be described by
>> structures (and sub-structures). Therefore we asked to considerer
>> structs, at least for the Pruss SocketCAN drivers.
>>
>> That would result in
>> much much clearer and better readable code. The code above would shrink 
>> to:
>>
>> __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
>>      &prucore[pruss_num].control);
> This driver seems to exclusively use the control offset, which is why I 
> don't
> see an absolute need for doing this mapping.
> But if both maps are contiguous then doing the mapping would prevent us 
> from
> calling reg_offset() and would bring some advantage. I'd then be fine with 
> it.
> For now, da8xx_prusscore_regs seems to be larger than the 0x800 interval
> between the 2 maps, so I have no idea if both maps are indeed contiguous.
>
> Cheers,
> Samuel.
>
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/ 


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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-22 12:49               ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22 12:49 UTC (permalink / raw)
  To: linux-arm-kernel

I am not sure if I understood you correctly, but the current sizeof the 
structure da8xx_prusscore_regs  is 0x500.

Here is a link to the PRUSS memory map:
http://processors.wiki.ti.com/index.php/PRUSS_Memory_Map

The offset 0x00007000 is the PRU0 reg offset and 0x00007800 is the PRU1 reg 
offset.
We cannot have a register file larger than this, but lot of space is left 
out, possibly for future development.

--------------------------------------------------
From: "Samuel Ortiz" <sameo@linux.intel.com>
Sent: Tuesday, February 22, 2011 5:03 PM
To: "Wolfgang Grandegger" <wg@grandegger.com>
Cc: "Subhasish Ghosh" <subhasish@mistralsolutions.com>; 
<sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; <nsekhar@ti.com>; "open 
list" <linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.

> On Tue, Feb 22, 2011 at 11:48:51AM +0100, Wolfgang Grandegger wrote:
>> On 02/22/2011 11:31 AM, Samuel Ortiz wrote:
>> > Hi Subhasish,
>> >
>> > On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
>> >> Thank you for your comments.
>> > No problem.
>> >
>> >>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> >>>> index fd01836..6c437df 100644
>> >>>> --- a/drivers/mfd/Kconfig
>> >>>> +++ b/drivers/mfd/Kconfig
>> >>>> @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>> >>>>   boards.  MSP430 firmware manages resets and power sequencing,
>> >>>>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
>> >>>>
>> >>>> +config MFD_DA8XX_PRUSS
>> >>>> + tristate "Texas Instruments DA8XX PRUSS support"
>> >>>> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
>> >>> Why are we depending on those ?
>> >>
>> >> SG -- The PRUSS core in only available within DA850 and DA830,
>> >>            DA830 support is not yet implemented.
>> > Sure, but if there are no actual code dependencies, I'd like to get rid 
>> > of
>> > those depends.
>> >
>> >>>> +u32 pruss_disable(struct device *dev, u8 pruss_num)
>> >>>> +{
>> >>>> + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>> >>>> + da8xx_prusscore_regs h_pruss;
>> >>>> + u32 temp_reg;
>> >>>> +
>> >>>> + if (pruss_num == DA8XX_PRUCORE_0) {
>> >>>> + /* Disable PRU0  */
>> >>>> + h_pruss = (da8xx_prusscore_regs)
>> >>>> + ((u32) pruss->ioaddr + 0x7000);
>> >>> So it seems you're doing this in several places, and I have a few
>> >>> comments:
>> >>>
>> >>> - You don't need the da8xx_prusscore_regs at all.
>> >>> - Define the register map through a set of #define in your header 
>> >>> file.
>> >>> - Use a static routine that takes the core number and returns the
>> >>> register map
>> >>> offset.
>> >>>
>> >>> Then routines like this one will look a lot more readable.
>> >>
>> >> SG -- There are a huge number of PRUSS registers. A lot of them are
>> >> reserved and are expected to change as development on the
>> >>            controller is still ongoing.
>> > First of all, from what I read in your patch you're only using the 
>> > CONTROL
>> > offset.
>> >
>> >> If we use #defines to plot
>> >> all the registers, then first, there are too many array type
>> >> registers which will need to be duplicated.
>> > What I'm expecting is a small set of defines for the register offsets. 
>> > You
>> > have 13 fields in your da8xx_prusscore_regs, you only need to define 13
>> > register offsets.
>> >
>> > So, if you have a:
>> >
>> > static u32 reg_offset(struct device *dev, u8 pru_num)
>> > {
>> > struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
>> >
>> > switch (pru_num) {
>> > case DA8XX_PRUCORE_0:
>> > return (u32) pru->ioaddr + 0x7000;
>> > case DA8XX_PRUCORE_1:
>> > return (u32) pru->ioaddr + 0x7800;
>> > default:
>> > return 0;
>> > }
>> >
>> >
>> > then routines like pruss_enable (which should return an int, btw) would 
>> > look
>> > like:
>> >
>> > int pruss_enable(struct device *dev, u8 pruss_num)
>> > {
>> > u32 offset = reg_offset(dev, pruss_num);
>> >
>> > if (offset == 0)
>> > return -EINVAL;
>> >
>> > __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
>> > offset + PRU_CORE_CONTROL);
>> >
>> > return 0;
>> > }
>>
>> All registers are memory mapped and could nicely be described by
>> structures (and sub-structures). Therefore we asked to considerer
>> structs, at least for the Pruss SocketCAN drivers.
>>
>> That would result in
>> much much clearer and better readable code. The code above would shrink 
>> to:
>>
>> __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
>>      &prucore[pruss_num].control);
> This driver seems to exclusively use the control offset, which is why I 
> don't
> see an absolute need for doing this mapping.
> But if both maps are contiguous then doing the mapping would prevent us 
> from
> calling reg_offset() and would bring some advantage. I'd then be fine with 
> it.
> For now, da8xx_prusscore_regs seems to be larger than the 0x800 interval
> between the 2 maps, so I have no idea if both maps are indeed contiguous.
>
> Cheers,
> Samuel.
>
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/ 

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

* Re: [PATCH v2 12/13] da850: pruss SUART platform specific additions.
  2011-02-22 11:20         ` Sergei Shtylyov
@ 2011-02-22 13:24           ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22 13:24 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, sachi, Russell King, Kevin Hilman,
	nsekhar, open list, m-watkins, linux-arm-kernel

Ok, will do.

--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Tuesday, February 22, 2011 4:50 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 12/13] da850: pruss SUART platform specific 
additions.

> Hello.
>
> On 22-02-2011 12:18, Subhasish Ghosh wrote:
>
>> I could not follow your recommendations clearly, are you suggesting this:
>
>> int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
>> {
>> #ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
>> int ret;
>>
>> ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
>> NULL, &da850_mcasp_device.dev);
>> if (ret < 0)
>> return ret;
>> #endif
>> da8xx_pruss_dev.dev.platform_data = pruss_device;
>> return platform_device_register(&da8xx_pruss_dev);
>> }
>
>    Yes. But still better would be to wrap clk_add_alias() into a function 
> of its own (defining it empty if CONFIG_SERIAL_PRUSS_SUART_MODULE is not 
> defined).
>
> WBR, Sergei 


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

* [PATCH v2 12/13] da850: pruss SUART platform specific additions.
@ 2011-02-22 13:24           ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-22 13:24 UTC (permalink / raw)
  To: linux-arm-kernel

Ok, will do.

--------------------------------------------------
From: "Sergei Shtylyov" <sshtylyov@mvista.com>
Sent: Tuesday, February 22, 2011 4:50 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: <davinci-linux-open-source@linux.davincidsp.com>; 
<sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; <nsekhar@ti.com>; "open list" 
<linux-kernel@vger.kernel.org>; <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v2 12/13] da850: pruss SUART platform specific 
additions.

> Hello.
>
> On 22-02-2011 12:18, Subhasish Ghosh wrote:
>
>> I could not follow your recommendations clearly, are you suggesting this:
>
>> int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
>> {
>> #ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
>> int ret;
>>
>> ret = clk_add_alias(NULL, "da8xx_pruss_uart.1",
>> NULL, &da850_mcasp_device.dev);
>> if (ret < 0)
>> return ret;
>> #endif
>> da8xx_pruss_dev.dev.platform_data = pruss_device;
>> return platform_device_register(&da8xx_pruss_dev);
>> }
>
>    Yes. But still better would be to wrap clk_add_alias() into a function 
> of its own (defining it empty if CONFIG_SERIAL_PRUSS_SUART_MODULE is not 
> defined).
>
> WBR, Sergei 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-22  8:42               ` Subhasish Ghosh
@ 2011-02-22 14:37                 ` Greg KH
  -1 siblings, 0 replies; 157+ messages in thread
From: Greg KH @ 2011-02-22 14:37 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Arnd Bergmann, linux-arm-kernel, Thomas Gleixner, Alan Cox,
	sachi, davinci-linux-open-source, nsekhar, open list, m-watkins

On Tue, Feb 22, 2011 at 02:12:32PM +0530, Subhasish Ghosh wrote:
> Hello,
> 
> I had kept separate files to affirm the modularity and ease of
> portability of the system.
> 
> There are three different interfaces,
> 1. The Linux driver interface
> 2. The PRU control interface
> 3. The McASP serializer interface.
> 
> To maintain modularity, I  had classified the files respectively as :
> 1.  pruss_suart.c
> 2.  pruss_suart_api.c
> 3.  pruss_suart_utils.c
> 
> This is not a single device which can be expressed as a single file,
> but functionally different devices logically cascaded together to
> work in unison.
> 
> We use the PRU for packet processing, but the actual data is
> transmitted/received through the
> McASP, which we use as a serializer.
> 
> I feel to combine these disparate functionalities into a single file
> will not
> 
> 1. Help better understanding the device. I mean, why should a TTY
> UART driver be aware of the McASP or the PRU.
> 2. In case of a bug in the API layer or McASP, the driver need not
> be touched, thus improve maintainability.
> 3. If we need to port it to another Linux version, just editing the
> driver file should suffice, this will reduce bugs while porting.

If your code is in the kernel tree, you do not need to ever port it to a
new version, as it will happen automatically as new kernels are
released, so this really isn't anything to worry about.

> To me, combining all of these into a single file only creates a
> mess. This is the reason I had separated them into different files!!
> I don't understand why should it be better to have all of these into
> a single file.

As Alan stated, just use 3 files in the directory with the other
drivers, you don't need a subdir for something small like this.

thanks,

greg k-h

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-22 14:37                 ` Greg KH
  0 siblings, 0 replies; 157+ messages in thread
From: Greg KH @ 2011-02-22 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Feb 22, 2011 at 02:12:32PM +0530, Subhasish Ghosh wrote:
> Hello,
> 
> I had kept separate files to affirm the modularity and ease of
> portability of the system.
> 
> There are three different interfaces,
> 1. The Linux driver interface
> 2. The PRU control interface
> 3. The McASP serializer interface.
> 
> To maintain modularity, I  had classified the files respectively as :
> 1.  pruss_suart.c
> 2.  pruss_suart_api.c
> 3.  pruss_suart_utils.c
> 
> This is not a single device which can be expressed as a single file,
> but functionally different devices logically cascaded together to
> work in unison.
> 
> We use the PRU for packet processing, but the actual data is
> transmitted/received through the
> McASP, which we use as a serializer.
> 
> I feel to combine these disparate functionalities into a single file
> will not
> 
> 1. Help better understanding the device. I mean, why should a TTY
> UART driver be aware of the McASP or the PRU.
> 2. In case of a bug in the API layer or McASP, the driver need not
> be touched, thus improve maintainability.
> 3. If we need to port it to another Linux version, just editing the
> driver file should suffice, this will reduce bugs while porting.

If your code is in the kernel tree, you do not need to ever port it to a
new version, as it will happen automatically as new kernels are
released, so this really isn't anything to worry about.

> To me, combining all of these into a single file only creates a
> mess. This is the reason I had separated them into different files!!
> I don't understand why should it be better to have all of these into
> a single file.

As Alan stated, just use 3 files in the directory with the other
drivers, you don't need a subdir for something small like this.

thanks,

greg k-h

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22 12:49               ` Subhasish Ghosh
@ 2011-02-22 16:27                 ` Wolfgang Grandegger
  -1 siblings, 0 replies; 157+ messages in thread
From: Wolfgang Grandegger @ 2011-02-22 16:27 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Samuel Ortiz, sachi, davinci-linux-open-source, nsekhar,
	open list, m-watkins, linux-arm-kernel

On 02/22/2011 01:49 PM, Subhasish Ghosh wrote:
> I am not sure if I understood you correctly, but the current sizeof the
> structure da8xx_prusscore_regs  is 0x500.
> 
> Here is a link to the PRUSS memory map:
> http://processors.wiki.ti.com/index.php/PRUSS_Memory_Map
> 
> The offset 0x00007000 is the PRU0 reg offset and 0x00007800 is the PRU1
> reg offset.
> We cannot have a register file larger than this, but lot of space is
> left out, possibly for future development.

What do you mean with "larger than this"? You ioremap the whole space
and unsued space could be filled with padding bytes:

struct pruss_regs {
	u8 ram0[0x0200];
	u8 res0[0x1e00];
	u8 ram1[0x0200];
	u8 res1[0x1e00];
	struct pruss_intc_regs intc;
	struct pruss_core_regs core[2];
};

Then:

  pruss_dev->regs = ioremap(pruss_dev->res->start,
	   	    resource_size(pruss_dev->res));

  __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
               &pruss_dev->regs.core[pruss_num].control);

That's simple, transparent and save without magic offset handling.

Wolfgang.

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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-22 16:27                 ` Wolfgang Grandegger
  0 siblings, 0 replies; 157+ messages in thread
From: Wolfgang Grandegger @ 2011-02-22 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/22/2011 01:49 PM, Subhasish Ghosh wrote:
> I am not sure if I understood you correctly, but the current sizeof the
> structure da8xx_prusscore_regs  is 0x500.
> 
> Here is a link to the PRUSS memory map:
> http://processors.wiki.ti.com/index.php/PRUSS_Memory_Map
> 
> The offset 0x00007000 is the PRU0 reg offset and 0x00007800 is the PRU1
> reg offset.
> We cannot have a register file larger than this, but lot of space is
> left out, possibly for future development.

What do you mean with "larger than this"? You ioremap the whole space
and unsued space could be filled with padding bytes:

struct pruss_regs {
	u8 ram0[0x0200];
	u8 res0[0x1e00];
	u8 ram1[0x0200];
	u8 res1[0x1e00];
	struct pruss_intc_regs intc;
	struct pruss_core_regs core[2];
};

Then:

  pruss_dev->regs = ioremap(pruss_dev->res->start,
	   	    resource_size(pruss_dev->res));

  __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
               &pruss_dev->regs.core[pruss_num].control);

That's simple, transparent and save without magic offset handling.

Wolfgang.

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-22  8:43               ` Subhasish Ghosh
@ 2011-02-22 16:34                 ` Arnd Bergmann
  -1 siblings, 0 replies; 157+ messages in thread
From: Arnd Bergmann @ 2011-02-22 16:34 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: linux-arm-kernel, Thomas Gleixner, Alan Cox, sachi,
	davinci-linux-open-source, Greg Kroah-Hartman, nsekhar,
	open list, m-watkins

On Tuesday 22 February 2011, Subhasish Ghosh wrote:

> @@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct omapl_pru_suart 
> *soft_uart, u32 uart_no)
>         if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>                 return;
> 
> -       if (down_trylock(&soft_uart->port_sem[uart_no]))
> -               return;
> -
>         if (uart_circ_empty(xmit) ||
>                         uart_tx_stopped(&soft_uart->port[uart_no])) {
>                 pruss_suart_stop_tx(&soft_uart->port[uart_no]);
> -               up(&soft_uart->port_sem[uart_no]);
> +               soft_uart->tx_empty[uart_no] = true;
>                 return;
>         }
> 
> @@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, void 
> *dev_id)
>                         pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
>                         pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl
>                                                  [port->line]);
> -                       up(&soft_uart->port_sem[port->line]);
>                         omapl_pru_tx_chars(soft_uart, port->line);
>                 }
>         } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
> @@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port 
> *port)
> 
>         suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
>                            PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
> -       omapl_pru_tx_chars(soft_uart, port->line);
> +       if (soft_uart->tx_empty[port->line] == true) {
> +               soft_uart->tx_empty[port->line] = false;
> +               omapl_pru_tx_chars(soft_uart, port->line);
> +       }
>  }

This looks racy, and I think you at least need to take the spinlock in
pruss_suart_start_tx(), but I don't fully understand the intention of the
code.

I guess you could also use a bitmask for tx_empty and use test_and_clear_bit()
on that to guarantee atomicity.

	Arnd

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-22 16:34                 ` Arnd Bergmann
  0 siblings, 0 replies; 157+ messages in thread
From: Arnd Bergmann @ 2011-02-22 16:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 22 February 2011, Subhasish Ghosh wrote:

> @@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct omapl_pru_suart 
> *soft_uart, u32 uart_no)
>         if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>                 return;
> 
> -       if (down_trylock(&soft_uart->port_sem[uart_no]))
> -               return;
> -
>         if (uart_circ_empty(xmit) ||
>                         uart_tx_stopped(&soft_uart->port[uart_no])) {
>                 pruss_suart_stop_tx(&soft_uart->port[uart_no]);
> -               up(&soft_uart->port_sem[uart_no]);
> +               soft_uart->tx_empty[uart_no] = true;
>                 return;
>         }
> 
> @@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, void 
> *dev_id)
>                         pru_intr_clr_isrstatus(dev, uart_num, PRU_TX_INTR);
>                         pru_softuart_clr_tx_status(dev, &soft_uart->suart_hdl
>                                                  [port->line]);
> -                       up(&soft_uart->port_sem[port->line]);
>                         omapl_pru_tx_chars(soft_uart, port->line);
>                 }
>         } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
> @@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port 
> *port)
> 
>         suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
>                            PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
> -       omapl_pru_tx_chars(soft_uart, port->line);
> +       if (soft_uart->tx_empty[port->line] == true) {
> +               soft_uart->tx_empty[port->line] = false;
> +               omapl_pru_tx_chars(soft_uart, port->line);
> +       }
>  }

This looks racy, and I think you at least need to take the spinlock in
pruss_suart_start_tx(), but I don't fully understand the intention of the
code.

I guess you could also use a bitmask for tx_empty and use test_and_clear_bit()
on that to guarantee atomicity.

	Arnd

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-22 14:37                 ` Greg KH
@ 2011-02-23  5:30                   ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-23  5:30 UTC (permalink / raw)
  To: Greg KH, Alan Cox
  Cc: Arnd Bergmann, linux-arm-kernel, Thomas Gleixner, sachi,
	davinci-linux-open-source, nsekhar, open list, m-watkins,
	Stalin Srinivasan

I could not follow the recommendations clearly.
This is just to clarify.

Currently, I have the following files for the suart implementation:

drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h

drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
drivers/tty/serial/da8xx_pruss/pruss_suart.c
drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c

Of these, I will be removing pruss_suart_err.h as part of the Linux error 
code cleanup.
But, I need to keep at least  pruss_suart_board.h as a separate file, as 
this defines
configurations which will be often modified by users, I don't want to mix it 
with other files.

Should I combine rest of the headers into a single file ? and keep the other 
three .c files under "drivers/tty/serial/"
and remove the da8xx_pruss directory altogether.


--------------------------------------------------
From: "Greg KH" <gregkh@suse.de>
Sent: Tuesday, February 22, 2011 8:07 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: "Arnd Bergmann" <arnd@arndb.de>; <linux-arm-kernel@lists.infradead.org>; 
"Thomas Gleixner" <tglx@linutronix.de>; "Alan Cox" 
<alan@lxorguk.ukuu.org.uk>; <sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; <nsekhar@ti.com>; "open 
list" <linux-kernel@vger.kernel.org>; <m-watkins@ti.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> On Tue, Feb 22, 2011 at 02:12:32PM +0530, Subhasish Ghosh wrote:
>> Hello,
>>
>> I had kept separate files to affirm the modularity and ease of
>> portability of the system.
>>
>> There are three different interfaces,
>> 1. The Linux driver interface
>> 2. The PRU control interface
>> 3. The McASP serializer interface.
>>
>> To maintain modularity, I  had classified the files respectively as :
>> 1.  pruss_suart.c
>> 2.  pruss_suart_api.c
>> 3.  pruss_suart_utils.c
>>
>> This is not a single device which can be expressed as a single file,
>> but functionally different devices logically cascaded together to
>> work in unison.
>>
>> We use the PRU for packet processing, but the actual data is
>> transmitted/received through the
>> McASP, which we use as a serializer.
>>
>> I feel to combine these disparate functionalities into a single file
>> will not
>>
>> 1. Help better understanding the device. I mean, why should a TTY
>> UART driver be aware of the McASP or the PRU.
>> 2. In case of a bug in the API layer or McASP, the driver need not
>> be touched, thus improve maintainability.
>> 3. If we need to port it to another Linux version, just editing the
>> driver file should suffice, this will reduce bugs while porting.
>
> If your code is in the kernel tree, you do not need to ever port it to a
> new version, as it will happen automatically as new kernels are
> released, so this really isn't anything to worry about.
>
>> To me, combining all of these into a single file only creates a
>> mess. This is the reason I had separated them into different files!!
>> I don't understand why should it be better to have all of these into
>> a single file.
>
> As Alan stated, just use 3 files in the directory with the other
> drivers, you don't need a subdir for something small like this.
>
> thanks,
>
> greg k-h 


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-23  5:30                   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-23  5:30 UTC (permalink / raw)
  To: linux-arm-kernel

I could not follow the recommendations clearly.
This is just to clarify.

Currently, I have the following files for the suart implementation:

drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h

drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
drivers/tty/serial/da8xx_pruss/pruss_suart.c
drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c

Of these, I will be removing pruss_suart_err.h as part of the Linux error 
code cleanup.
But, I need to keep at least  pruss_suart_board.h as a separate file, as 
this defines
configurations which will be often modified by users, I don't want to mix it 
with other files.

Should I combine rest of the headers into a single file ? and keep the other 
three .c files under "drivers/tty/serial/"
and remove the da8xx_pruss directory altogether.


--------------------------------------------------
From: "Greg KH" <gregkh@suse.de>
Sent: Tuesday, February 22, 2011 8:07 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Cc: "Arnd Bergmann" <arnd@arndb.de>; <linux-arm-kernel@lists.infradead.org>; 
"Thomas Gleixner" <tglx@linutronix.de>; "Alan Cox" 
<alan@lxorguk.ukuu.org.uk>; <sachi@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; <nsekhar@ti.com>; "open 
list" <linux-kernel@vger.kernel.org>; <m-watkins@ti.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

> On Tue, Feb 22, 2011 at 02:12:32PM +0530, Subhasish Ghosh wrote:
>> Hello,
>>
>> I had kept separate files to affirm the modularity and ease of
>> portability of the system.
>>
>> There are three different interfaces,
>> 1. The Linux driver interface
>> 2. The PRU control interface
>> 3. The McASP serializer interface.
>>
>> To maintain modularity, I  had classified the files respectively as :
>> 1.  pruss_suart.c
>> 2.  pruss_suart_api.c
>> 3.  pruss_suart_utils.c
>>
>> This is not a single device which can be expressed as a single file,
>> but functionally different devices logically cascaded together to
>> work in unison.
>>
>> We use the PRU for packet processing, but the actual data is
>> transmitted/received through the
>> McASP, which we use as a serializer.
>>
>> I feel to combine these disparate functionalities into a single file
>> will not
>>
>> 1. Help better understanding the device. I mean, why should a TTY
>> UART driver be aware of the McASP or the PRU.
>> 2. In case of a bug in the API layer or McASP, the driver need not
>> be touched, thus improve maintainability.
>> 3. If we need to port it to another Linux version, just editing the
>> driver file should suffice, this will reduce bugs while porting.
>
> If your code is in the kernel tree, you do not need to ever port it to a
> new version, as it will happen automatically as new kernels are
> released, so this really isn't anything to worry about.
>
>> To me, combining all of these into a single file only creates a
>> mess. This is the reason I had separated them into different files!!
>> I don't understand why should it be better to have all of these into
>> a single file.
>
> As Alan stated, just use 3 files in the directory with the other
> drivers, you don't need a subdir for something small like this.
>
> thanks,
>
> greg k-h 

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22 10:31         ` Samuel Ortiz
@ 2011-02-23 12:25           ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-23 12:25 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, open list

--------------------------------------------------
From: "Samuel Ortiz" <sameo@linux.intel.com>
Sent: Tuesday, February 22, 2011 4:01 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>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.

> Hi Subhasish,
>
> On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
>> Thank you for your comments.
> No problem.
>
>> >>diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> >>index fd01836..6c437df 100644
>> >>--- a/drivers/mfd/Kconfig
>> >>+++ b/drivers/mfd/Kconfig
>> >>@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>> >>   boards.  MSP430 firmware manages resets and power sequencing,
>> >>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
>> >>
>> >>+config MFD_DA8XX_PRUSS
>> >>+ tristate "Texas Instruments DA8XX PRUSS support"
>> >>+ depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
>> >Why are we depending on those ?
>>
>> SG -- The PRUSS core in only available within DA850 and DA830,
>>            DA830 support is not yet implemented.
> Sure, but if there are no actual code dependencies, I'd like to get rid of
> those depends.


SG -- The PRU Clock and Power is the dependency here.
            This is available in arch/arm/mach-davinci/da850.c
            The source is specific to the SOC clock tree.

>
>> >>+u32 pruss_disable(struct device *dev, u8 pruss_num)
>> >>+{
>> >>+ struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>> >>+ da8xx_prusscore_regs h_pruss;
>> >>+ u32 temp_reg;
>> >>+
>> >>+ if (pruss_num == DA8XX_PRUCORE_0) {
>> >>+ /* Disable PRU0  */
>> >>+ h_pruss = (da8xx_prusscore_regs)
>> >>+ ((u32) pruss->ioaddr + 0x7000);
>> >So it seems you're doing this in several places, and I have a few
>> >comments:
>> >
>> >- You don't need the da8xx_prusscore_regs at all.
>> >- Define the register map through a set of #define in your header file.
>> >- Use a static routine that takes the core number and returns the
>> >register map
>> >offset.
>> >
>> >Then routines like this one will look a lot more readable.
>>
>> SG -- There are a huge number of PRUSS registers. A lot of them are
>> reserved and are expected to change as development on the
>>            controller is still ongoing.
> First of all, from what I read in your patch you're only using the CONTROL
> offset.
>
>> If we use #defines to plot
>> all the registers, then first, there are too many array type
>> registers which will need to be duplicated.
> What I'm expecting is a small set of defines for the register offsets. You
> have 13 fields in your da8xx_prusscore_regs, you only need to define 13
> register offsets.
>
> So, if you have a:
>
> static u32 reg_offset(struct device *dev, u8 pru_num)
> {
> struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
>
> switch (pru_num) {
> case DA8XX_PRUCORE_0:
> return (u32) pru->ioaddr + 0x7000;
> case DA8XX_PRUCORE_1:
> return (u32) pru->ioaddr + 0x7800;
> default:
> return 0;
> }
>
>
> then routines like pruss_enable (which should return an int, btw) would 
> look
> like:
>
> int pruss_enable(struct device *dev, u8 pruss_num)
> {
> u32 offset = reg_offset(dev, pruss_num);
>
> if (offset == 0)
> return -EINVAL;
>
> __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> offset + PRU_CORE_CONTROL);
>
> return 0;
> }
>
>> >Also, all your exported routines severely lack any sort of locking. An 
>> >IO
>> >mutex or spinlock is mandatory here.
>>
>> SG - As per our current implementation, we do not have two devices
>> running simultaneously on the PRU,
>>        so we do not have any way to test it. We have kept this as an
>> enhancement if request comes in for
>>        multiple devices.
> It's not about having multiple devices at the same time, it's about having
> multiple callers writing and reading to the same registers. Since you're
> exporting all your I/O routines you have no way to prevent 2 drivers from
> writing to the same register at the "same" time. You need locking here,
> regardless of the number of devices that you can have on a system.
>

SG - Ok, will do

>
>> >>+static int pruss_mfd_add_devices(struct platform_device *pdev)
>> >>+{
>> >>+ struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
>> >>+ struct device *dev = &pdev->dev;
>> >>+ struct mfd_cell cell;
>> >>+ u32 err, count;
>> >>+
>> >>+ for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
>> >>+ memset(&cell, 0, sizeof(struct mfd_cell));
>> >>+ cell.id = count;
>> >>+ cell.name = (dev_data + count)->dev_name;
>> >>+ cell.platform_data = (dev_data + count)->pdata;
>> >>+ cell.data_size = (dev_data + count)->pdata_size;
>> >>+
>> >>+ err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
>> >>+ if (err) {
>> >>+ dev_err(dev, "cannot add mfd cells\n");
>> >>+ return err;
>> >>+ }
>> >>+ }
>> >>+ return err;
>> >>+}
>> >So, what are the potential subdevices for this driver ? If it's a really
>> >dynamic setup, I'm fine with passing those as platform data but
>> >then do it so
>> >that you pass a NULL terminated da8xx_pruss_devices array. That will 
>> >avoid
>> >most of the ugly casts you're doing here.
>>
>> SG -- I did not follow your recommendations here, could you please
>> elaborate.
>>            I am already checking the dev_name for a NULL.
>>            This device is basically a microcontroller within DA850,
>> so basically any device or protocol can be
>>            emulated on it. Currently, we have emulated 8 UARTS using
>> the two PRUs and also a CAN device.
> Ok, I wasnt sure you can emulate anything on that thing. So I'm fine with 
> you
> passing all your devices through platform_data. But I'd prefer this 
> routine to
> look like:
>
> [...]
> for (count = 0; dev_data[count] != NULL; count++) {
> memset(&cell, 0, sizeof(struct mfd_cell));
> cell.id = count;
> cell.name = dev_data[count]->dev_name;
> cell.platform_data = dev_data[count]->pdata;
> cell.data_size = dev_data[count]->pdata_size;
>
> Looks nicer to me.

SG - I have a problem here, dev_data was initialized as a structure array.

static struct da8xx_pruss_devices pruss_devices[] = {
        {
                .dev_name       = "da8xx_pruss_can",
                .pdata          = &can_data,
                .pdata_size     = sizeof(can_data),
                .setup          = da850_evm_setup_pruss_can,
                .num_resources  = 0,
                .resources      = NULL,
        },
        {
                .dev_name       = "da8xx_pruss_uart",
                .pdata          = &suart_data,
                .pdata_size     = sizeof(suart_data),
                .setup          = da850_evm_setup_pruss_suart,
                .num_resources  = ARRAY_SIZE(da850_evm_suart_resource),
                .resources      = da850_evm_suart_resource,
        },
        {
                .dev_name       = NULL,
        },
};

How can I initialize the last array element to NULL!
I think, I must have some type of delimiter.

>
> Cheers,
> Samuel.
>
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/ 


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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-23 12:25           ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-23 12:25 UTC (permalink / raw)
  To: linux-arm-kernel

--------------------------------------------------
From: "Samuel Ortiz" <sameo@linux.intel.com>
Sent: Tuesday, February 22, 2011 4:01 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>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 01/13] mfd: pruss mfd driver.

> Hi Subhasish,
>
> On Tue, Feb 22, 2011 at 11:13:38AM +0530, Subhasish Ghosh wrote:
>> Thank you for your comments.
> No problem.
>
>> >>diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> >>index fd01836..6c437df 100644
>> >>--- a/drivers/mfd/Kconfig
>> >>+++ b/drivers/mfd/Kconfig
>> >>@@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP
>> >>   boards.  MSP430 firmware manages resets and power sequencing,
>> >>   inputs from buttons and the IR remote, LEDs, an RTC, and more.
>> >>
>> >>+config MFD_DA8XX_PRUSS
>> >>+ tristate "Texas Instruments DA8XX PRUSS support"
>> >>+ depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
>> >Why are we depending on those ?
>>
>> SG -- The PRUSS core in only available within DA850 and DA830,
>>            DA830 support is not yet implemented.
> Sure, but if there are no actual code dependencies, I'd like to get rid of
> those depends.


SG -- The PRU Clock and Power is the dependency here.
            This is available in arch/arm/mach-davinci/da850.c
            The source is specific to the SOC clock tree.

>
>> >>+u32 pruss_disable(struct device *dev, u8 pruss_num)
>> >>+{
>> >>+ struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent);
>> >>+ da8xx_prusscore_regs h_pruss;
>> >>+ u32 temp_reg;
>> >>+
>> >>+ if (pruss_num == DA8XX_PRUCORE_0) {
>> >>+ /* Disable PRU0  */
>> >>+ h_pruss = (da8xx_prusscore_regs)
>> >>+ ((u32) pruss->ioaddr + 0x7000);
>> >So it seems you're doing this in several places, and I have a few
>> >comments:
>> >
>> >- You don't need the da8xx_prusscore_regs at all.
>> >- Define the register map through a set of #define in your header file.
>> >- Use a static routine that takes the core number and returns the
>> >register map
>> >offset.
>> >
>> >Then routines like this one will look a lot more readable.
>>
>> SG -- There are a huge number of PRUSS registers. A lot of them are
>> reserved and are expected to change as development on the
>>            controller is still ongoing.
> First of all, from what I read in your patch you're only using the CONTROL
> offset.
>
>> If we use #defines to plot
>> all the registers, then first, there are too many array type
>> registers which will need to be duplicated.
> What I'm expecting is a small set of defines for the register offsets. You
> have 13 fields in your da8xx_prusscore_regs, you only need to define 13
> register offsets.
>
> So, if you have a:
>
> static u32 reg_offset(struct device *dev, u8 pru_num)
> {
> struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
>
> switch (pru_num) {
> case DA8XX_PRUCORE_0:
> return (u32) pru->ioaddr + 0x7000;
> case DA8XX_PRUCORE_1:
> return (u32) pru->ioaddr + 0x7800;
> default:
> return 0;
> }
>
>
> then routines like pruss_enable (which should return an int, btw) would 
> look
> like:
>
> int pruss_enable(struct device *dev, u8 pruss_num)
> {
> u32 offset = reg_offset(dev, pruss_num);
>
> if (offset == 0)
> return -EINVAL;
>
> __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL,
> offset + PRU_CORE_CONTROL);
>
> return 0;
> }
>
>> >Also, all your exported routines severely lack any sort of locking. An 
>> >IO
>> >mutex or spinlock is mandatory here.
>>
>> SG - As per our current implementation, we do not have two devices
>> running simultaneously on the PRU,
>>        so we do not have any way to test it. We have kept this as an
>> enhancement if request comes in for
>>        multiple devices.
> It's not about having multiple devices at the same time, it's about having
> multiple callers writing and reading to the same registers. Since you're
> exporting all your I/O routines you have no way to prevent 2 drivers from
> writing to the same register at the "same" time. You need locking here,
> regardless of the number of devices that you can have on a system.
>

SG - Ok, will do

>
>> >>+static int pruss_mfd_add_devices(struct platform_device *pdev)
>> >>+{
>> >>+ struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data;
>> >>+ struct device *dev = &pdev->dev;
>> >>+ struct mfd_cell cell;
>> >>+ u32 err, count;
>> >>+
>> >>+ for (count = 0; (dev_data + count)->dev_name != NULL; count++) {
>> >>+ memset(&cell, 0, sizeof(struct mfd_cell));
>> >>+ cell.id = count;
>> >>+ cell.name = (dev_data + count)->dev_name;
>> >>+ cell.platform_data = (dev_data + count)->pdata;
>> >>+ cell.data_size = (dev_data + count)->pdata_size;
>> >>+
>> >>+ err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0);
>> >>+ if (err) {
>> >>+ dev_err(dev, "cannot add mfd cells\n");
>> >>+ return err;
>> >>+ }
>> >>+ }
>> >>+ return err;
>> >>+}
>> >So, what are the potential subdevices for this driver ? If it's a really
>> >dynamic setup, I'm fine with passing those as platform data but
>> >then do it so
>> >that you pass a NULL terminated da8xx_pruss_devices array. That will 
>> >avoid
>> >most of the ugly casts you're doing here.
>>
>> SG -- I did not follow your recommendations here, could you please
>> elaborate.
>>            I am already checking the dev_name for a NULL.
>>            This device is basically a microcontroller within DA850,
>> so basically any device or protocol can be
>>            emulated on it. Currently, we have emulated 8 UARTS using
>> the two PRUs and also a CAN device.
> Ok, I wasnt sure you can emulate anything on that thing. So I'm fine with 
> you
> passing all your devices through platform_data. But I'd prefer this 
> routine to
> look like:
>
> [...]
> for (count = 0; dev_data[count] != NULL; count++) {
> memset(&cell, 0, sizeof(struct mfd_cell));
> cell.id = count;
> cell.name = dev_data[count]->dev_name;
> cell.platform_data = dev_data[count]->pdata;
> cell.data_size = dev_data[count]->pdata_size;
>
> Looks nicer to me.

SG - I have a problem here, dev_data was initialized as a structure array.

static struct da8xx_pruss_devices pruss_devices[] = {
        {
                .dev_name       = "da8xx_pruss_can",
                .pdata          = &can_data,
                .pdata_size     = sizeof(can_data),
                .setup          = da850_evm_setup_pruss_can,
                .num_resources  = 0,
                .resources      = NULL,
        },
        {
                .dev_name       = "da8xx_pruss_uart",
                .pdata          = &suart_data,
                .pdata_size     = sizeof(suart_data),
                .setup          = da850_evm_setup_pruss_suart,
                .num_resources  = ARRAY_SIZE(da850_evm_suart_resource),
                .resources      = da850_evm_suart_resource,
        },
        {
                .dev_name       = NULL,
        },
};

How can I initialize the last array element to NULL!
I think, I must have some type of delimiter.

>
> Cheers,
> Samuel.
>
> -- 
> Intel Open Source Technology Centre
> http://oss.intel.com/ 

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

* Re: [PATCH v2 01/13] mfd: pruss mfd driver.
  2011-02-22 10:31         ` Samuel Ortiz
@ 2011-02-23 13:09           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 157+ messages in thread
From: Russell King - ARM Linux @ 2011-02-23 13:09 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Subhasish Ghosh, sachi, davinci-linux-open-source, nsekhar,
	open list, m-watkins, linux-arm-kernel

On Tue, Feb 22, 2011 at 11:31:27AM +0100, Samuel Ortiz wrote:
> So, if you have a:
> 
> static u32 reg_offset(struct device *dev, u8 pru_num)
> {
> 	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
> 
> 	switch (pru_num) {
> 	case DA8XX_PRUCORE_0:
> 		return (u32) pru->ioaddr + 0x7000;
> 	case DA8XX_PRUCORE_1:
> 		return (u32) pru->ioaddr + 0x7800;
> 	default:
> 		return 0;
> }

No.  Please don't encourage people to have 'u32' as valid cookies for
readl,writel et.al.  Always make the mmio cookies __iomem pointer like.

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

* [PATCH v2 01/13] mfd: pruss mfd driver.
@ 2011-02-23 13:09           ` Russell King - ARM Linux
  0 siblings, 0 replies; 157+ messages in thread
From: Russell King - ARM Linux @ 2011-02-23 13:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Feb 22, 2011 at 11:31:27AM +0100, Samuel Ortiz wrote:
> So, if you have a:
> 
> static u32 reg_offset(struct device *dev, u8 pru_num)
> {
> 	struct da8xx_pruss *pru = dev_get_drvdata(dev->parent);
> 
> 	switch (pru_num) {
> 	case DA8XX_PRUCORE_0:
> 		return (u32) pru->ioaddr + 0x7000;
> 	case DA8XX_PRUCORE_1:
> 		return (u32) pru->ioaddr + 0x7800;
> 	default:
> 		return 0;
> }

No.  Please don't encourage people to have 'u32' as valid cookies for
readl,writel et.al.  Always make the mmio cookies __iomem pointer like.

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-23  5:30                   ` Subhasish Ghosh
@ 2011-02-23 18:20                     ` Greg KH
  -1 siblings, 0 replies; 157+ messages in thread
From: Greg KH @ 2011-02-23 18:20 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Alan Cox, Arnd Bergmann, linux-arm-kernel, Thomas Gleixner,
	sachi, davinci-linux-open-source, nsekhar, open list, m-watkins,
	Stalin Srinivasan

On Wed, Feb 23, 2011 at 11:00:25AM +0530, Subhasish Ghosh wrote:
> I could not follow the recommendations clearly.
> This is just to clarify.
> 
> Currently, I have the following files for the suart implementation:
> 
> drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
> 
> drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
> drivers/tty/serial/da8xx_pruss/pruss_suart.c
> drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
> 
> Of these, I will be removing pruss_suart_err.h as part of the Linux
> error code cleanup.
> But, I need to keep at least  pruss_suart_board.h as a separate
> file, as this defines
> configurations which will be often modified by users, I don't want
> to mix it with other files.

Why would a .h file ever need to be "modified by users"?  That sounds
wrong to me.

> Should I combine rest of the headers into a single file ?

Yes, why would they need to be separate?

> and keep the other three .c files under "drivers/tty/serial/" and
> remove the da8xx_pruss directory altogether.

Yes.

thanks,

greg k-h

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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-23 18:20                     ` Greg KH
  0 siblings, 0 replies; 157+ messages in thread
From: Greg KH @ 2011-02-23 18:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 23, 2011 at 11:00:25AM +0530, Subhasish Ghosh wrote:
> I could not follow the recommendations clearly.
> This is just to clarify.
> 
> Currently, I have the following files for the suart implementation:
> 
> drivers/tty/serial/da8xx_pruss/pruss_suart_api.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_err.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_regs.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_board.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_mcasp.h
> drivers/tty/serial/da8xx_pruss/pruss_suart_utils.h
> 
> drivers/tty/serial/da8xx_pruss/pruss_suart_api.c
> drivers/tty/serial/da8xx_pruss/pruss_suart.c
> drivers/tty/serial/da8xx_pruss/pruss_suart_utils.c
> 
> Of these, I will be removing pruss_suart_err.h as part of the Linux
> error code cleanup.
> But, I need to keep at least  pruss_suart_board.h as a separate
> file, as this defines
> configurations which will be often modified by users, I don't want
> to mix it with other files.

Why would a .h file ever need to be "modified by users"?  That sounds
wrong to me.

> Should I combine rest of the headers into a single file ?

Yes, why would they need to be separate?

> and keep the other three .c files under "drivers/tty/serial/" and
> remove the da8xx_pruss directory altogether.

Yes.

thanks,

greg k-h

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-22 16:34                 ` Arnd Bergmann
@ 2011-02-24 10:31                   ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-24 10:31 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Thomas Gleixner, Alan Cox, sachi,
	davinci-linux-open-source, Greg Kroah-Hartman, nsekhar,
	open list, m-watkins

Hello,

Ok, have implemented the test_and_clear_bit.


> On Tuesday 22 February 2011, Subhasish Ghosh wrote:
>
>> @@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct 
>> omapl_pru_suart
>> *soft_uart, u32 uart_no)
>>         if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>>                 return;
>>
>> -       if (down_trylock(&soft_uart->port_sem[uart_no]))
>> -               return;
>> -
>>         if (uart_circ_empty(xmit) ||
>>                         uart_tx_stopped(&soft_uart->port[uart_no])) {
>>                 pruss_suart_stop_tx(&soft_uart->port[uart_no]);
>> -               up(&soft_uart->port_sem[uart_no]);
>> +               soft_uart->tx_empty[uart_no] = true;
>>                 return;
>>         }
>>
>> @@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, 
>> void
>> *dev_id)
>>                         pru_intr_clr_isrstatus(dev, uart_num, 
>> PRU_TX_INTR);
>>                         pru_softuart_clr_tx_status(dev, 
>> &soft_uart->suart_hdl
>>                                                  [port->line]);
>> -                       up(&soft_uart->port_sem[port->line]);
>>                         omapl_pru_tx_chars(soft_uart, port->line);
>>                 }
>>         } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
>> @@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port
>> *port)
>>
>>         suart_intr_setmask(dev, 
>> soft_uart->suart_hdl[port->line].uart_num,
>>                            PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
>> -       omapl_pru_tx_chars(soft_uart, port->line);
>> +       if (soft_uart->tx_empty[port->line] == true) {
>> +               soft_uart->tx_empty[port->line] = false;
>> +               omapl_pru_tx_chars(soft_uart, port->line);
>> +       }
>>  }
>
> This looks racy, and I think you at least need to take the spinlock in
> pruss_suart_start_tx(), but I don't fully understand the intention of the
> code.
>
> I guess you could also use a bitmask for tx_empty and use 
> test_and_clear_bit()
> on that to guarantee atomicity.
>
> Arnd 


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-02-24 10:31                   ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-02-24 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

Ok, have implemented the test_and_clear_bit.


> On Tuesday 22 February 2011, Subhasish Ghosh wrote:
>
>> @@ -122,13 +122,10 @@ static void omapl_pru_tx_chars(struct 
>> omapl_pru_suart
>> *soft_uart, u32 uart_no)
>>         if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_TX))
>>                 return;
>>
>> -       if (down_trylock(&soft_uart->port_sem[uart_no]))
>> -               return;
>> -
>>         if (uart_circ_empty(xmit) ||
>>                         uart_tx_stopped(&soft_uart->port[uart_no])) {
>>                 pruss_suart_stop_tx(&soft_uart->port[uart_no]);
>> -               up(&soft_uart->port_sem[uart_no]);
>> +               soft_uart->tx_empty[uart_no] = true;
>>                 return;
>>         }
>>
>> @@ -259,7 +256,6 @@ static irqreturn_t pruss_suart_interrupt(s32 irq, 
>> void
>> *dev_id)
>>                         pru_intr_clr_isrstatus(dev, uart_num, 
>> PRU_TX_INTR);
>>                         pru_softuart_clr_tx_status(dev, 
>> &soft_uart->suart_hdl
>>                                                  [port->line]);
>> -                       up(&soft_uart->port_sem[port->line]);
>>                         omapl_pru_tx_chars(soft_uart, port->line);
>>                 }
>>         } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
>> @@ -294,7 +290,10 @@ static void pruss_suart_start_tx(struct uart_port
>> *port)
>>
>>         suart_intr_setmask(dev, 
>> soft_uart->suart_hdl[port->line].uart_num,
>>                            PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
>> -       omapl_pru_tx_chars(soft_uart, port->line);
>> +       if (soft_uart->tx_empty[port->line] == true) {
>> +               soft_uart->tx_empty[port->line] = false;
>> +               omapl_pru_tx_chars(soft_uart, port->line);
>> +       }
>>  }
>
> This looks racy, and I think you at least need to take the spinlock in
> pruss_suart_start_tx(), but I don't fully understand the intention of the
> code.
>
> I guess you could also use a bitmask for tx_empty and use 
> test_and_clear_bit()
> on that to guarantee atomicity.
>
> Arnd 

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

* RE: [PATCH v2 02/13] da850: pruss platform specific additions.
  2011-02-11 14:51   ` Subhasish Ghosh
@ 2011-02-28 13:04     ` TK, Pratheesh Gangadhar
  -1 siblings, 0 replies; 157+ messages in thread
From: TK, Pratheesh Gangadhar @ 2011-02-28 13:04 UTC (permalink / raw)
  To: Subhasish Ghosh, davinci-linux-open-source
  Cc: sachi, Russell King, Kevin Hilman, open list, Watkins, Melissa,
	linux-arm-kernel

Hi,

> -----Original Message-----
> From: davinci-linux-open-source-bounces@linux.davincidsp.com
> [mailto:davinci-linux-open-source-bounces@linux.davincidsp.com] On Behalf
> Of Subhasish Ghosh
> Sent: Friday, February 11, 2011 8:21 PM
> To: davinci-linux-open-source@linux.davincidsp.com
> Cc: sachi@mistralsolutions.com; Russell King; Kevin Hilman; Subhasish
> Ghosh; open list; Watkins, Melissa; linux-arm-kernel@lists.infradead.org
> Subject: [PATCH v2 02/13] da850: pruss platform specific additions.
> 
> This patch adds the platform device and assignes the platform resources
> for the PRUSS mfd driver.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
> +struct platform_device da8xx_pruss_dev = {
Can you please rename this to da8xx_pruss_mfddev?
> +	.name		= "da8xx_pruss",
Can you please rename name string as pruss_mfd? This will help to
base my UIO patches on top of yours.
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(da8xx_pruss_resources),
> +	.resource	= da8xx_pruss_resources,
> +};
> +
> +int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
Please rename this to da8xx_register_pruss_mfd

Thanks,
Pratheesh

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

* [PATCH v2 02/13] da850: pruss platform specific additions.
@ 2011-02-28 13:04     ` TK, Pratheesh Gangadhar
  0 siblings, 0 replies; 157+ messages in thread
From: TK, Pratheesh Gangadhar @ 2011-02-28 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

> -----Original Message-----
> From: davinci-linux-open-source-bounces at linux.davincidsp.com
> [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf
> Of Subhasish Ghosh
> Sent: Friday, February 11, 2011 8:21 PM
> To: davinci-linux-open-source at linux.davincidsp.com
> Cc: sachi at mistralsolutions.com; Russell King; Kevin Hilman; Subhasish
> Ghosh; open list; Watkins, Melissa; linux-arm-kernel at lists.infradead.org
> Subject: [PATCH v2 02/13] da850: pruss platform specific additions.
> 
> This patch adds the platform device and assignes the platform resources
> for the PRUSS mfd driver.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
> +struct platform_device da8xx_pruss_dev = {
Can you please rename this to da8xx_pruss_mfddev?
> +	.name		= "da8xx_pruss",
Can you please rename name string as pruss_mfd? This will help to
base my UIO patches on top of yours.
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(da8xx_pruss_resources),
> +	.resource	= da8xx_pruss_resources,
> +};
> +
> +int __init da8xx_register_pruss(struct da8xx_pruss_devices *pruss_device)
Please rename this to da8xx_register_pruss_mfd

Thanks,
Pratheesh

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

* Re: [PATCH v2 02/13] da850: pruss platform specific additions.
  2011-02-28 13:04     ` TK, Pratheesh Gangadhar
@ 2011-03-01  6:59       ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-03-01  6:59 UTC (permalink / raw)
  To: TK, Pratheesh Gangadhar, davinci-linux-open-source
  Cc: sachi, Russell King, Kevin Hilman, open list, Watkins, Melissa,
	linux-arm-kernel

Hello,

Can we not have the PRU UIO also as a part of the MFD framework.
I know that the UIO is not really a device, but I feel its incorrect to 
register the same device twice.
Instead we can have a single entry as the MFD framework and the UIO, as a 
child device, based upon the MFD driver APIs.

All that we need to do is add an entry into the da8xx_pruss_devices 
structure
and the MFD driver will do the rest to get the UIO probe called.

--------------------------------------------------
From: "TK, Pratheesh Gangadhar" <pratheesh@ti.com>
Sent: Monday, February 28, 2011 6:34 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>
Cc: <sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "open list" 
<linux-kernel@vger.kernel.org>; "Watkins, Melissa" <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: RE: [PATCH v2 02/13] da850: pruss platform specific additions.

> Hi,
>
>> -----Original Message-----
>> From: davinci-linux-open-source-bounces@linux.davincidsp.com
>> [mailto:davinci-linux-open-source-bounces@linux.davincidsp.com] On Behalf
>> Of Subhasish Ghosh
>> Sent: Friday, February 11, 2011 8:21 PM
>> To: davinci-linux-open-source@linux.davincidsp.com
>> Cc: sachi@mistralsolutions.com; Russell King; Kevin Hilman; Subhasish
>> Ghosh; open list; Watkins, Melissa; linux-arm-kernel@lists.infradead.org
>> Subject: [PATCH v2 02/13] da850: pruss platform specific additions.
>>
>> This patch adds the platform device and assignes the platform resources
>> for the PRUSS mfd driver.
>>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>> ---
>> +struct platform_device da8xx_pruss_dev = {
> Can you please rename this to da8xx_pruss_mfddev?
>> + .name = "da8xx_pruss",
> Can you please rename name string as pruss_mfd? This will help to
> base my UIO patches on top of yours.
>> + .id = -1,
>> + .num_resources = ARRAY_SIZE(da8xx_pruss_resources),
>> + .resource = da8xx_pruss_resources,
>> +};
>> +
>> +int __init da8xx_register_pruss(struct da8xx_pruss_devices 
>> *pruss_device)
> Please rename this to da8xx_register_pruss_mfd
>
> Thanks,
> Pratheesh 


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

* [PATCH v2 02/13] da850: pruss platform specific additions.
@ 2011-03-01  6:59       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-03-01  6:59 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

Can we not have the PRU UIO also as a part of the MFD framework.
I know that the UIO is not really a device, but I feel its incorrect to 
register the same device twice.
Instead we can have a single entry as the MFD framework and the UIO, as a 
child device, based upon the MFD driver APIs.

All that we need to do is add an entry into the da8xx_pruss_devices 
structure
and the MFD driver will do the rest to get the UIO probe called.

--------------------------------------------------
From: "TK, Pratheesh Gangadhar" <pratheesh@ti.com>
Sent: Monday, February 28, 2011 6:34 PM
To: "Subhasish Ghosh" <subhasish@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>
Cc: <sachi@mistralsolutions.com>; "Russell King" <linux@arm.linux.org.uk>; 
"Kevin Hilman" <khilman@deeprootsystems.com>; "open list" 
<linux-kernel@vger.kernel.org>; "Watkins, Melissa" <m-watkins@ti.com>; 
<linux-arm-kernel@lists.infradead.org>
Subject: RE: [PATCH v2 02/13] da850: pruss platform specific additions.

> Hi,
>
>> -----Original Message-----
>> From: davinci-linux-open-source-bounces at linux.davincidsp.com
>> [mailto:davinci-linux-open-source-bounces at linux.davincidsp.com] On Behalf
>> Of Subhasish Ghosh
>> Sent: Friday, February 11, 2011 8:21 PM
>> To: davinci-linux-open-source at linux.davincidsp.com
>> Cc: sachi at mistralsolutions.com; Russell King; Kevin Hilman; Subhasish
>> Ghosh; open list; Watkins, Melissa; linux-arm-kernel at lists.infradead.org
>> Subject: [PATCH v2 02/13] da850: pruss platform specific additions.
>>
>> This patch adds the platform device and assignes the platform resources
>> for the PRUSS mfd driver.
>>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>> ---
>> +struct platform_device da8xx_pruss_dev = {
> Can you please rename this to da8xx_pruss_mfddev?
>> + .name = "da8xx_pruss",
> Can you please rename name string as pruss_mfd? This will help to
> base my UIO patches on top of yours.
>> + .id = -1,
>> + .num_resources = ARRAY_SIZE(da8xx_pruss_resources),
>> + .resource = da8xx_pruss_resources,
>> +};
>> +
>> +int __init da8xx_register_pruss(struct da8xx_pruss_devices 
>> *pruss_device)
> Please rename this to da8xx_register_pruss_mfd
>
> Thanks,
> Pratheesh 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-02-22 11:11         ` Alan Cox
@ 2011-03-01 13:37           ` Subhasish Ghosh
  -1 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-03-01 13:37 UTC (permalink / raw)
  To: Alan Cox
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list, Stalin Srinivasan,
	Stalin Srinivasan

Hello,

I tried using the tty_prepare_flip_string as shown below, but this is 
causing some latency issues.

Problem is, we do not have any flow control, so we must copy the FIFO data 
before the next data
is available. As we are using the tty_prepare_flip_string just before the 
read API, the FIFO is getting
overwritten and we are ending up missing chunks (FIFO sized) of data.

I tried using a tasklet for the TX part, but that did not help.
Another way is to prepare the buffer for the next read and read the data 
immediately.
Something like this:

1. Call tty_prepare_flip_string while startup.
2. When the read interrupt arrives, read the data immediately.
3. Call tty_prepare_flip_string for the next read.

Again, the problem here is that we need to use global variables to store the 
pre-allocated buffers
and at the last read, we allocated the buffer but never used it. I think 
this will cause a memory leak.
Or we can de-allocate it while driver close, not sure how to.

The best way is if we can keep the current implementation, one extra copy is 
not hurting us
as we do it after the read_data API.


==================================================================================
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
        s8 flags = TTY_NORMAL;
        u16 rx_status, data_len = SUART_FIFO_LEN;
        u32 data_len_read;
-       u8 suart_data[SUART_FIFO_LEN + 1];
+       u8 *suart_data = NULL;
        s32 i = 0;
+       s32 alloc_len = 0;

        if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
                return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
                soft_uart->port[uart_no].sysrq = 0;
 #endif
        } else {
+               alloc_len = tty_prepare_flip_string(tty, &suart_data,
data_len + 1);
                pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
-                                      suart_data, data_len + 1,
-                                      &data_len_read);
+                                               suart_data, alloc_len,
+                                               &data_len_read);

                for (i = 0; i <= data_len_read; i++) {
                        soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
                            (&soft_uart->port[uart_no], suart_data))
                                continue;
                }
-               /* update the tty data structure */
-               tty_insert_flip_string(tty, suart_data, data_len_read);
        }
============================================================================================

--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Tuesday, February 22, 2011 4:41 PM
To: "Subhasish" <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>; "Greg Kroah-Hartman" 
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>; "Stalin 
Srinivasan" <stalin.s@mistralsolutions.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

>> we used separate files and hence we decided to keep the code in a 
>> separate
>> directory so that the related files can be identified easily.
>
> Fair enough but I would have thought you could drop the two files in the
> serial directory if they have obviously related names- trivial item/
>>
>> >
>> >
>> >
>> >> +#ifdef __SUART_DEBUG
>> >> +#define __suart_debug(fmt, args...) \
>> >> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> >> +#else
>> >> +#define __suart_debug(fmt, args...)
>> >> +#endif
>> >> +
>> >> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, 
>> >> ##
>> >> args)
>> >
>> > Use dev_dbg/dev_err/pr_debug/pr_err
>>
>> SG - did you mean replace the printks above with dev_dgb/err or the
>> suart_dbg/err.
>
> Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you
> to configure debug levels and the like nicely as well as producing
> clearer printk info. In some cases with tty code you may not know the
> device so have to use pr_err/pr_debug etc.
>
> Ok
>
>> > Which is never checked. Far better to use WARN_ON and the like for such
>> > cases - or if like this one they don't appear to be possible to simply
>> > delete them
>>
>> SG -- OK, does this look ok ?
>> =================================
>> if (h_uart == NULL) {
>> +WARN_ON(1);
>> - return PRU_SUART_ERR_HANDLE_INVALID;
>> +return -EINVAL;
>> }
>
> Yep - the user will now get a backtrace, and in addition kerneloops.org
> can capture it if that is set up in the distro in use.
>
> Alan 


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-03-01 13:37           ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-03-01 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

I tried using the tty_prepare_flip_string as shown below, but this is 
causing some latency issues.

Problem is, we do not have any flow control, so we must copy the FIFO data 
before the next data
is available. As we are using the tty_prepare_flip_string just before the 
read API, the FIFO is getting
overwritten and we are ending up missing chunks (FIFO sized) of data.

I tried using a tasklet for the TX part, but that did not help.
Another way is to prepare the buffer for the next read and read the data 
immediately.
Something like this:

1. Call tty_prepare_flip_string while startup.
2. When the read interrupt arrives, read the data immediately.
3. Call tty_prepare_flip_string for the next read.

Again, the problem here is that we need to use global variables to store the 
pre-allocated buffers
and at the last read, we allocated the buffer but never used it. I think 
this will cause a memory leak.
Or we can de-allocate it while driver close, not sure how to.

The best way is if we can keep the current implementation, one extra copy is 
not hurting us
as we do it after the read_data API.


==================================================================================
--- a/drivers/tty/serial/da8xx_pruss/pruss_suart.c
+++ b/drivers/tty/serial/da8xx_pruss/pruss_suart.c
@@ -170,8 +170,9 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
        s8 flags = TTY_NORMAL;
        u16 rx_status, data_len = SUART_FIFO_LEN;
        u32 data_len_read;
-       u8 suart_data[SUART_FIFO_LEN + 1];
+       u8 *suart_data = NULL;
        s32 i = 0;
+       s32 alloc_len = 0;

        if (!(suart_get_duplex(soft_uart, uart_no) & ePRU_SUART_HALF_RX))
                return;
@@ -199,9 +200,10 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
                soft_uart->port[uart_no].sysrq = 0;
 #endif
        } else {
+               alloc_len = tty_prepare_flip_string(tty, &suart_data,
data_len + 1);
                pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
-                                      suart_data, data_len + 1,
-                                      &data_len_read);
+                                               suart_data, alloc_len,
+                                               &data_len_read);

                for (i = 0; i <= data_len_read; i++) {
                        soft_uart->port[uart_no].icount.rx++;
@@ -210,8 +212,6 @@ static void omapl_pru_rx_chars(struct omapl_pru_suart
*soft_uart, u32 uart_no)
                            (&soft_uart->port[uart_no], suart_data))
                                continue;
                }
-               /* update the tty data structure */
-               tty_insert_flip_string(tty, suart_data, data_len_read);
        }
============================================================================================

--------------------------------------------------
From: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Sent: Tuesday, February 22, 2011 4:41 PM
To: "Subhasish" <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>; "Greg Kroah-Hartman" 
<gregkh@suse.de>; "open list" <linux-kernel@vger.kernel.org>; "Stalin 
Srinivasan" <stalin.s@mistralsolutions.com>
Subject: Re: [PATCH v2 13/13] tty: pruss SUART driver

>> we used separate files and hence we decided to keep the code in a 
>> separate
>> directory so that the related files can be identified easily.
>
> Fair enough but I would have thought you could drop the two files in the
> serial directory if they have obviously related names- trivial item/
>>
>> >
>> >
>> >
>> >> +#ifdef __SUART_DEBUG
>> >> +#define __suart_debug(fmt, args...) \
>> >> + printk(KERN_DEBUG "suart_debug: " fmt, ## args)
>> >> +#else
>> >> +#define __suart_debug(fmt, args...)
>> >> +#endif
>> >> +
>> >> +#define  __suart_err(fmt, args...) printk(KERN_ERR "suart_err: " fmt, 
>> >> ##
>> >> args)
>> >
>> > Use dev_dbg/dev_err/pr_debug/pr_err
>>
>> SG - did you mean replace the printks above with dev_dgb/err or the
>> suart_dbg/err.
>
> Ideally all the messages shopuld use dev_dbg/dev_err etc. That allows you
> to configure debug levels and the like nicely as well as producing
> clearer printk info. In some cases with tty code you may not know the
> device so have to use pr_err/pr_debug etc.
>
> Ok
>
>> > Which is never checked. Far better to use WARN_ON and the like for such
>> > cases - or if like this one they don't appear to be possible to simply
>> > delete them
>>
>> SG -- OK, does this look ok ?
>> =================================
>> if (h_uart == NULL) {
>> +WARN_ON(1);
>> - return PRU_SUART_ERR_HANDLE_INVALID;
>> +return -EINVAL;
>> }
>
> Yep - the user will now get a backtrace, and in addition kerneloops.org
> can capture it if that is set up in the distro in use.
>
> Alan 

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

* Re: [PATCH v2 13/13] tty: pruss SUART driver
  2011-03-01 13:37           ` Subhasish Ghosh
@ 2011-03-01 14:07             ` Alan Cox
  -1 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-03-01 14:07 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, open list, Stalin Srinivasan

> I tried using a tasklet for the TX part, but that did not help.
> Another way is to prepare the buffer for the next read and read the data 
> immediately.
> Something like this:
> 
> 1. Call tty_prepare_flip_string while startup.
> 2. When the read interrupt arrives, read the data immediately.
> 3. Call tty_prepare_flip_string for the next read.

Only you then don't know the size of space required/

> Again, the problem here is that we need to use global variables to store the 
> pre-allocated buffers

You don't. You can store them per port in the existing objects !

> The best way is if we can keep the current implementation, one extra copy is 
> not hurting us
> as we do it after the read_data API.

No problem with that at all.


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

* [PATCH v2 13/13] tty: pruss SUART driver
@ 2011-03-01 14:07             ` Alan Cox
  0 siblings, 0 replies; 157+ messages in thread
From: Alan Cox @ 2011-03-01 14:07 UTC (permalink / raw)
  To: linux-arm-kernel

> I tried using a tasklet for the TX part, but that did not help.
> Another way is to prepare the buffer for the next read and read the data 
> immediately.
> Something like this:
> 
> 1. Call tty_prepare_flip_string while startup.
> 2. When the read interrupt arrives, read the data immediately.
> 3. Call tty_prepare_flip_string for the next read.

Only you then don't know the size of space required/

> Again, the problem here is that we need to use global variables to store the 
> pre-allocated buffers

You don't. You can store them per port in the existing objects !

> The best way is if we can keep the current implementation, one extra copy is 
> not hurting us
> as we do it after the read_data API.

No problem with that at all.

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

* RE: [PATCH v2 02/13] da850: pruss platform specific additions.
  2011-03-01  6:59       ` Subhasish Ghosh
@ 2011-03-03 11:12         ` TK, Pratheesh Gangadhar
  -1 siblings, 0 replies; 157+ messages in thread
From: TK, Pratheesh Gangadhar @ 2011-03-03 11:12 UTC (permalink / raw)
  To: Subhasish Ghosh, davinci-linux-open-source
  Cc: sachi, Russell King, Kevin Hilman, open list, Watkins, Melissa,
	linux-arm-kernel

Hi,

> -----Original Message-----
> From: Subhasish Ghosh [mailto:subhasish@mistralsolutions.com]
> Sent: Tuesday, March 01, 2011 12:29 PM
> Hello,
> 
> Can we not have the PRU UIO also as a part of the MFD framework.
> I know that the UIO is not really a device, but I feel its incorrect to
> register the same device twice.
> Instead we can have a single entry as the MFD framework and the UIO, as a
> child device, based upon the MFD driver APIs.
> 
> All that we need to do is add an entry into the da8xx_pruss_devices
> structure
> and the MFD driver will do the rest to get the UIO probe called.
> 
Well I see the need for MFD for in-kernel PRUSS based drivers like UART/CAN, 
but UIO use cases are typically mutually exclusive to this. UIO driver 
exports whole PRUSS I/O region and Interrupts to user space application and 
all the tasks including PRUSS INTC setup, loading firmware and
enable/disable PRUs are handled by PRUSS user driver.
I feel it will be a nightmare to make them co-exist unless say we have
2 instances of PRUSS in a SOC. Think about kernel driver setting up PRUSS, PINTC and loading firmware and user land overriding and vice versa. Things are much simpler if we make the usage model mutually exclusive.
Also I don't see any overlap in functionality and reuse UIO can gain from
MFD driver.  
Since we can't register device twice - I would prefer KConfig based check
for the same. 

Also can you point me where you add UART and CAN driver as children to PRUSS
MFD driver - I can't seem to find this in patches.

Thanks,
Pratheesh

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

* [PATCH v2 02/13] da850: pruss platform specific additions.
@ 2011-03-03 11:12         ` TK, Pratheesh Gangadhar
  0 siblings, 0 replies; 157+ messages in thread
From: TK, Pratheesh Gangadhar @ 2011-03-03 11:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

> -----Original Message-----
> From: Subhasish Ghosh [mailto:subhasish at mistralsolutions.com]
> Sent: Tuesday, March 01, 2011 12:29 PM
> Hello,
> 
> Can we not have the PRU UIO also as a part of the MFD framework.
> I know that the UIO is not really a device, but I feel its incorrect to
> register the same device twice.
> Instead we can have a single entry as the MFD framework and the UIO, as a
> child device, based upon the MFD driver APIs.
> 
> All that we need to do is add an entry into the da8xx_pruss_devices
> structure
> and the MFD driver will do the rest to get the UIO probe called.
> 
Well I see the need for MFD for in-kernel PRUSS based drivers like UART/CAN, 
but UIO use cases are typically mutually exclusive to this. UIO driver 
exports whole PRUSS I/O region and Interrupts to user space application and 
all the tasks including PRUSS INTC setup, loading firmware and
enable/disable PRUs are handled by PRUSS user driver.
I feel it will be a nightmare to make them co-exist unless say we have
2 instances of PRUSS in a SOC. Think about kernel driver setting up PRUSS, PINTC and loading firmware and user land overriding and vice versa. Things are much simpler if we make the usage model mutually exclusive.
Also I don't see any overlap in functionality and reuse UIO can gain from
MFD driver.  
Since we can't register device twice - I would prefer KConfig based check
for the same. 

Also can you point me where you add UART and CAN driver as children to PRUSS
MFD driver - I can't seem to find this in patches.

Thanks,
Pratheesh

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

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-03-22  7:30       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-03-22  7:30 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: davinci-linux-open-source, sachi, nsekhar, open list,
	open list:CAN NETWORK DRIVERS, open list:CAN NETWORK DRIVERS,
	m-watkins, 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] 157+ messages in thread

* Re: [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-03-22  7:30       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ 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] 157+ messages in thread

* [PATCH v2 09/13] can: pruss CAN driver.
@ 2011-03-22  7:30       ` Subhasish Ghosh
  0 siblings, 0 replies; 157+ messages in thread
From: Subhasish Ghosh @ 2011-03-22  7:30 UTC (permalink / raw)
  To: linux-arm-kernel

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] 157+ messages in thread

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

Thread overview: 157+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-11 14:51 [PATCH v2 00/13] pruss mfd drivers Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 01/13] mfd: pruss mfd driver Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-21 16:30   ` Samuel Ortiz
2011-02-21 16:30     ` Samuel Ortiz
2011-02-22  5:43     ` Subhasish Ghosh
2011-02-22  5:43       ` Subhasish Ghosh
2011-02-22 10:31       ` Samuel Ortiz
2011-02-22 10:31         ` Samuel Ortiz
2011-02-22 10:48         ` Wolfgang Grandegger
2011-02-22 10:48           ` Wolfgang Grandegger
2011-02-22 11:33           ` Samuel Ortiz
2011-02-22 11:33             ` Samuel Ortiz
2011-02-22 12:49             ` Subhasish Ghosh
2011-02-22 12:49               ` Subhasish Ghosh
2011-02-22 16:27               ` Wolfgang Grandegger
2011-02-22 16:27                 ` Wolfgang Grandegger
2011-02-23 12:25         ` Subhasish Ghosh
2011-02-23 12:25           ` Subhasish Ghosh
2011-02-23 13:09         ` Russell King - ARM Linux
2011-02-23 13:09           ` Russell King - ARM Linux
2011-02-11 14:51 ` [PATCH v2 02/13] da850: pruss platform specific additions Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 18:41   ` Sergei Shtylyov
2011-02-11 18:41     ` Sergei Shtylyov
2011-02-18  7:18     ` Subhasish Ghosh
2011-02-18  7:18       ` Subhasish Ghosh
2011-02-28 13:04   ` TK, Pratheesh Gangadhar
2011-02-28 13:04     ` TK, Pratheesh Gangadhar
2011-03-01  6:59     ` Subhasish Ghosh
2011-03-01  6:59       ` Subhasish Ghosh
2011-03-03 11:12       ` TK, Pratheesh Gangadhar
2011-03-03 11:12         ` TK, Pratheesh Gangadhar
2011-02-11 14:51 ` [PATCH v2 03/13] da850: pruss board " Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 18:43   ` Sergei Shtylyov
2011-02-11 18:43     ` Sergei Shtylyov
2011-02-18  7:18     ` Subhasish Ghosh
2011-02-18  7:18       ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 04/13] mfd: pruss CAN private data Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 05/13] da850: pruss CAN platform specific additions Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 06/13] da850: pruss CAN board " Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 18:45   ` Sergei Shtylyov
2011-02-11 18:45     ` Sergei Shtylyov
2011-02-18  7:19     ` Subhasish Ghosh
2011-02-18  7:19       ` Subhasish Ghosh
2011-02-18  7:19     ` Subhasish Ghosh
2011-02-18  7:19       ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 07/13] da850: pruss CAN platform specific changes for gpios Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 18:47   ` Sergei Shtylyov
2011-02-11 18:47     ` Sergei Shtylyov
2011-02-18  7:20     ` Subhasish Ghosh
2011-02-18  7:20       ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 08/13] da850: pruss CAN board " Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 09/13] can: pruss CAN driver Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 15:06   ` Kurt Van Dijck
2011-02-11 15:06     ` Kurt Van Dijck
2011-02-11 15:06     ` Kurt Van Dijck
2011-02-14  4:54     ` Subhasish Ghosh
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  7:42             ` Kurt Van Dijck
2011-02-14  8:45         ` Subhasish Ghosh
2011-02-14  8:45           ` Subhasish Ghosh
2011-02-14  9:28           ` Wolfgang Grandegger
2011-02-14  9:35           ` Marc Kleine-Budde
2011-02-14 13:15             ` Subhasish Ghosh
2011-02-14 13:15               ` Subhasish Ghosh
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
2011-02-11 15:20     ` Kurt Van Dijck
2011-02-11 15:20     ` Kurt Van Dijck
2011-02-18  7:07     ` Subhasish Ghosh
2011-02-18  7:07       ` Subhasish Ghosh
2011-02-18  7:07       ` Subhasish Ghosh
2011-02-18  7:53       ` Wolfgang Grandegger
2011-02-18  8:15         ` Subhasish Ghosh
2011-02-18  8:15           ` Subhasish Ghosh
2011-02-18  8:15           ` Subhasish Ghosh
2011-02-18  8:36           ` Marc Kleine-Budde
2011-02-18  8:36             ` Marc Kleine-Budde
2011-02-18  8:36             ` Marc Kleine-Budde
2011-02-18  9:09             ` Subhasish Ghosh
2011-02-18  9:09               ` Subhasish Ghosh
2011-02-18  9:09               ` Subhasish Ghosh
     [not found]   ` <1297435892-28278-10-git-send-email-subhasish-EvXpCiN+lbve9wHmmfpqLFaTQe2KTcn/@public.gmane.org>
2011-02-11 20:33     ` Wolfgang Grandegger
2011-02-11 21:33     ` Marc Kleine-Budde
2011-02-18 15:07   ` Arnd Bergmann
2011-02-18 15:07     ` Arnd Bergmann
2011-03-22  7:30     ` Subhasish Ghosh
2011-03-22  7:30       ` Subhasish Ghosh
2011-03-22  7:30       ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 10/13] mfd: pruss SUART private data Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 11/13] da850: pruss SUART board specific additions Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 15:26   ` Michael Williamson
2011-02-11 15:26     ` Michael Williamson
2011-02-18  7:13     ` Subhasish Ghosh
2011-02-18  7:13       ` Subhasish Ghosh
2011-02-11 18:50   ` Sergei Shtylyov
2011-02-11 18:50     ` Sergei Shtylyov
2011-02-22  6:22     ` Subhasish Ghosh
2011-02-22  6:22       ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 12/13] da850: pruss SUART platform " Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 18:55   ` Sergei Shtylyov
2011-02-11 18:55     ` Sergei Shtylyov
2011-02-22  9:18     ` Subhasish Ghosh
2011-02-22  9:18       ` Subhasish Ghosh
2011-02-22 11:20       ` Sergei Shtylyov
2011-02-22 11:20         ` Sergei Shtylyov
2011-02-22 13:24         ` Subhasish Ghosh
2011-02-22 13:24           ` Subhasish Ghosh
2011-02-11 14:51 ` [PATCH v2 13/13] tty: pruss SUART driver Subhasish Ghosh
2011-02-11 14:51   ` Subhasish Ghosh
2011-02-11 16:28   ` Alan Cox
2011-02-11 16:28     ` Alan Cox
2011-02-18 13:47     ` Subhasish Ghosh
2011-02-18 13:47       ` Subhasish Ghosh
2011-02-18 14:35       ` Alan Cox
2011-02-18 14:35         ` Alan Cox
2011-02-18 18:23         ` Thomas Gleixner
2011-02-18 18:23           ` Thomas Gleixner
2011-02-18 18:51           ` Arnd Bergmann
2011-02-18 18:51             ` Arnd Bergmann
2011-02-22  8:42             ` Subhasish Ghosh
2011-02-22  8:42               ` Subhasish Ghosh
2011-02-22 14:37               ` Greg KH
2011-02-22 14:37                 ` Greg KH
2011-02-23  5:30                 ` Subhasish Ghosh
2011-02-23  5:30                   ` Subhasish Ghosh
2011-02-23 18:20                   ` Greg KH
2011-02-23 18:20                     ` Greg KH
2011-02-22  8:43             ` Subhasish Ghosh
2011-02-22  8:43               ` Subhasish Ghosh
2011-02-22 16:34               ` Arnd Bergmann
2011-02-22 16:34                 ` Arnd Bergmann
2011-02-24 10:31                 ` Subhasish Ghosh
2011-02-24 10:31                   ` Subhasish Ghosh
2011-02-22 10:26     ` Subhasish
2011-02-22 10:26       ` Subhasish
2011-02-22 11:11       ` Alan Cox
2011-02-22 11:11         ` Alan Cox
2011-03-01 13:37         ` Subhasish Ghosh
2011-03-01 13:37           ` Subhasish Ghosh
2011-03-01 14:07           ` Alan Cox
2011-03-01 14:07             ` Alan Cox

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