All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 11:50 UTC (permalink / raw)
  To: linux-arm-kernel

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

This patch depends on:
davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
            https://patchwork.kernel.org/patch/615681/
davinci: changed SRAM allocator to shared ram.
            https://patchwork.kernel.org/patch/549351/

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/tty/serial/Kconfig             |   18 +
 drivers/tty/serial/Makefile            |    6 +
 drivers/tty/serial/pruss_suart.c       | 1061 ++++++++++++++++++++
 drivers/tty/serial/pruss_suart.h       | 1038 +++++++++++++++++++
 drivers/tty/serial/pruss_suart_api.c   | 1710 ++++++++++++++++++++++++++++++++
 drivers/tty/serial/pruss_suart_utils.c |  393 ++++++++
 include/linux/serial_core.h            |    2 +
 7 files changed, 4228 insertions(+), 0 deletions(-)
 create mode 100644 drivers/tty/serial/pruss_suart.c
 create mode 100644 drivers/tty/serial/pruss_suart.h
 create mode 100644 drivers/tty/serial/pruss_suart_api.c
 create mode 100644 drivers/tty/serial/pruss_suart_utils.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2b83346..6c26ebf 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1596,4 +1596,22 @@ 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.
+
+config SERIAL_PRUSS_SUART
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	select SERIAL_CORE
+	tristate "PRUSS based SoftUART emulation on DA8XX"
+	---help---
+	This driver emulates up to eight different UARTs on the PRUSS.
+	You may modify the NR_SUARTS macro in the driver to emulate
+	less number of UARTS as per your requirement.
+	If not sure, mark No
+
+config PRUSS_SUART_MCASP
+	depends on ARCH_DAVINCI_DA830 && SERIAL_PRUSS_SUART
+	default "0"
+	int "McASP number"
+	---help---
+	Enter the McASP number to use with SUART (0, 1 or 2).
+	You will need to recompile the kernel if this is changed.
 endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 8ea92e9..e1eaaf3 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,3 +92,9 @@ 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
+
+pruss_uart-objs :=	pruss_suart.o \
+			pruss_suart_api.o \
+			pruss_suart_utils.o
+
+obj-$(CONFIG_SERIAL_PRUSS_SUART) += pruss_uart.o
diff --git a/drivers/tty/serial/pruss_suart.c b/drivers/tty/serial/pruss_suart.c
new file mode 100644
index 0000000..37c3c21
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart.c
@@ -0,0 +1,1061 @@
+/*
+ * 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) 2010, 2011 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 <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <mach/sram.h>
+#include "pruss_suart.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
+
+/* 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;
+	unsigned long tx_empty[NR_SUART];
+	struct clk *clk_mcasp;
+	struct suart_fifo suart_fifo_addr[NR_SUART];
+	struct suart_handle suart_hdl[NR_SUART];
+	struct pruss_suart_iomap suart_iomap;
+	struct tasklet_struct tx_task[NR_SUART];
+	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;
+	unsigned long flags = 0;
+	struct uart_port *port = &soft_uart->port[uart_no];
+	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 */
+	spin_lock_irqsave(&port->lock, flags);
+	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]);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+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 (uart_circ_empty(xmit) ||
+			uart_tx_stopped(&soft_uart->port[uart_no])) {
+		pruss_suart_stop_tx(&soft_uart->port[uart_no]);
+		set_bit(0, &soft_uart->tx_empty[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 (pru_softuart_write(dev,
+		&soft_uart->suart_hdl[uart_no],
+			(u32 *)&soft_uart->suart_fifo_addr
+				[uart_no].fifo_phys_addr_tx, count) != 0) {
+		dev_err(dev, "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 suart_tx_task(unsigned long data)
+{
+	struct uart_port *port = (struct uart_port *)data;
+	struct omapl_pru_suart *soft_uart =
+		container_of(port, struct omapl_pru_suart, port[port->line]);
+
+	omapl_pru_tx_chars(soft_uart, port->line);
+}
+
+static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct tty_struct *tty = NULL;
+	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]);
+
+	pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
+			suart_data, data_len + 1, &data_len_read);
+
+	tty = tty_port_tty_get(&soft_uart->port[uart_no].state->port);
+
+	if (!tty)
+		return;
+
+	/* 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 {
+		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;
+		}
+		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]);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+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(&port->lock, flags);
+
+	do {
+		ret = pru_softuart_get_isrstatus(dev, uart_num, &txrx_flag);
+		if (ret != 0) {
+			dev_err(dev, "suart%d: failed to get interrupt, ret:"
+				" 0x%X txrx_flag 0x%X\n",
+				port->line, ret, txrx_flag);
+				spin_unlock_irqrestore(&port->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]);
+			tasklet_schedule(&soft_uart->tx_task[port->line]);
+		}
+	} while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
+
+	spin_unlock_irqrestore(&port->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;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+	/* 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);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void pruss_suart_enable_ms(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;
+	dev_err(dev, "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;
+	unsigned long flags = 0;
+
+	/* unmask the tx interrupts */
+	spin_lock_irqsave(&port->lock, flags);
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (test_and_clear_bit(0, &soft_uart->tx_empty[port->line]))
+		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)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	dev_dbg(dev, "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 &= ~(CRTSCTS | CMSPAR | CSTOPB
+				      | PARENB | PARODD | CMSPAR);
+	}
+
+	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 (pru_softuart_setdatabits
+		(dev, &soft_uart->suart_hdl[port->line], cval, cval) != 0)
+		dev_err(dev, "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 (pru_softuart_setbaud(dev, &soft_uart->suart_hdl[port->line],
+				 SUART_DEFAULT_BAUD / baud,
+				 SUART_DEFAULT_BAUD / baud) != 0)
+		dev_err(dev, "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);
+	}
+/*
+ * Characters 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);
+	}
+	/*
+	* update the per port timeout
+	*/
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	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;
+	unsigned long flags = 0;
+	s32 retval;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	spin_lock_irqsave(&port->lock, flags);
+	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);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	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
+	 */
+	spin_lock_irqsave(&port->lock, flags);
+	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);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	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;
+	unsigned long flags = 0;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	/* Disable BI and FE intr */
+	spin_lock_irqsave(&port->lock, flags);
+	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);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* 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;
+	struct suart_config pru_suart_config;
+	s16 timeout = 0;
+	u32 err = 0;
+
+	if (soft_uart == NULL) {
+		dev_err(&pdev->dev, "soft_uart ptr failed\n");
+		return -ENODEV;
+	}
+	err = pru_softuart_open(&soft_uart->suart_hdl[port->line]);
+	if (err != 0) {
+		dev_err(&pdev->dev, "failed to open suart: %d\n", err);
+		err = -ENODEV;
+		goto exit;
+	}
+	set_bit(0, &soft_uart->tx_empty[port->line]);
+
+	/* set fifo /timeout */
+	if (SUART_FIFO_TIMEOUT_MIN > suart_timeout) {
+		dev_err(&pdev->dev, "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) {
+		dev_err(&pdev->dev, "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_softuart_setconfig(dev, &soft_uart->suart_hdl[port->line],
+			&pru_suart_config) != 0) {
+		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 struct pruss_suart_initparams init_params = {
+	.tx_baud_value	= SUART_DEFAULT_BAUD,
+	.rx_baud_value	= SUART_DEFAULT_BAUD,
+	.oversampling	= SUART_DEFAULT_OVRSMPL,
+};
+
+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;
+	struct resource *res;
+	struct clk *clk_pruss = NULL;
+	const struct firmware *fw;
+	s32 err, i;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not found\n");
+		return -EINVAL;
+	}
+	(pdata->setup)();
+
+	soft_uart = kzalloc(sizeof(struct omapl_pru_suart), GFP_KERNEL);
+	if (!soft_uart)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get resource");
+		return -ENOMEM;
+	}
+
+	if (!request_mem_region(res->start,
+			resource_size(res),
+			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(res->start,
+					resource_size(res));
+	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;
+
+	clk_pruss = clk_get(NULL, "pruss");
+	if (IS_ERR(clk_pruss)) {
+		dev_err(&pdev->dev, "no clock available: pruss\n");
+		err = -ENODEV;
+		goto probe_exit_iounmap;
+	}
+	soft_uart->clk_freq_pru = clk_get_rate(clk_pruss);
+	clk_put(clk_pruss);
+
+	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(&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", fw->size);
+
+	/* download firmware into pru  & init */
+	err = pru_softuart_init(dev, &init_params, fw->data, fw->size,
+					soft_uart->clk_freq_pru / 1000000,
+					&soft_uart->suart_iomap);
+	if (err) {
+		dev_err(&pdev->dev, "pruss init error\n");
+		err = -ENODEV;
+		goto probe_release_fw;
+	}
+	release_firmware(fw);
+
+	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 =
+			soft_uart->suart_iomap.mcasp_io_addr;
+		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;
+		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;
+		tasklet_init(&soft_uart->tx_task[i], suart_tx_task,
+				(unsigned long)&soft_uart->port[i]);
+		uart_add_one_port(&pruss_suart_reg, &soft_uart->port[i]);
+	}
+
+	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(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(res->start,
+		resource_size(res));
+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;
+	struct resource *res;
+	int i;
+
+	pdata = dev->platform_data;
+	if (!pdata)
+		dev_err(&pdev->dev, "platform data not found\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get resource");
+		return -ENOMEM;
+	}
+
+	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);
+	clk_put(soft_uart->clk_mcasp);
+	pru_mcasp_deinit();
+	clk_disable(soft_uart->clk_mcasp);
+	iounmap(soft_uart->suart_iomap.mcasp_io_addr);
+	if (pdata) {
+		release_mem_region(res->start,
+			resource_size(res));
+	}
+	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;
+
+	pr_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);
+	pr_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/pruss_suart.h b/drivers/tty/serial/pruss_suart.h
new file mode 100644
index 0000000..f3a2a9d
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart.h
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) 2010, 2011 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/io.h>
+#include <linux/mfd/pruss.h>
+
+#define SINGLE_PRU			0
+#define BOTH_PRU			1
+#define PRU_ACTIVE			BOTH_PRU
+#define PRU_CLK_228			228
+#define PRU_CLK_186			186
+
+#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)
+
+#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)
+
+#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 | \
+					PRU_SUART_HALF_RX)
+#define PRU_SUART3_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_13)
+#define PRU_SUART3_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_14)
+
+#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)
+
+#define SUART_NUM_OF_CHANNELS_PER_SUART		2
+#define SUART_NUM_OF_BYTES_PER_CHANNEL		16
+
+#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_TX_OVRSMPL			0
+#define SUART_DEFAULT_OVRSMPL			SUART_8X_OVRSMPL
+
+#define SUART_DEFAULT_OVRSMPL_OFFSET		26
+#define SUART_CHN_OFFSET			31
+#define SERIALIZER_OFFSET			8
+
+#if (SUART_DEFAULT_OVRSMPL == SUART_16X_OVRSMPL)
+#define SUART_DEFAULT_BAUD			57600
+#else
+#define SUART_DEFAULT_BAUD			115200
+#endif
+
+#define PRU_MODE_INVALID			0x0
+#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)
+
+/* MCASP */
+
+#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)
+
+/* SUART REGS */
+
+/* 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 STATUS Register*/
+#define PRU_SUART_CH_STATUS_EN_BIT_MASK		0x8000
+
+/* 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)
+
+/* 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)
+
+/*
+ *  This enum is used to specify the direction of the channel in UART
+ */
+enum SUART_CHN_DIR {
+	SUART_CHN_TX = 1,
+	SUART_CHN_RX = 2
+};
+
+/*
+ *  This enum is used to specify the state of the channel in UART. It
+ *  is either enabled or disabled.
+ */
+enum SUART_CHN_STATE {
+	SUART_CHN_DISABLED = 0,
+	SUART_CHN_ENABLED = 1
+};
+
+enum SUART_EN_BITSPERCHAR {
+	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
+};
+
+enum SUART_EN_UARTNUM {
+	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
+};
+
+enum SUART_EN_UARTTYPE {
+	ePRU_SUART_HALF_TX = 1,
+	ePRU_SUART_HALF_RX,
+	ePRU_SUART_FULL_TX_RX,
+	ePRU_SUART_HALF_TX_DISABLED = 4,
+	ePRU_SUART_HALF_RX_DISABLED = 8
+};
+
+enum SUART_EN_TXCHANNEL {
+	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
+};
+
+enum SUART_EN_RXCHANNEL {
+	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
+};
+
+enum SUART_EN_UART_STATUS {
+	ePRU_SUART_UART_FREE = 0,
+	ePRU_SUART_UART_IN_USE
+};
+
+struct pru_suart_cnh_cntrl_config1 {
+	u32 mode:2;
+	u32 service_req:1;
+	u32 asp_id:2;
+	u32 reserved1:3;
+	u32 serializer_num:4;
+	u32 reserved2:4;
+	u32 presacler:10;
+	u32 over_sampling:2;
+	u32 framing_mask:1;
+	u32 break_mask:1;
+	u32 timeout_mask:1;
+	u32 reserved3:1;
+};
+
+struct pru_suart_chn_config2_status {
+	u32 bits_per_char:4;
+	u32 reserved1:4;
+	u32 data_len:4;
+	u32 reserved2:4;
+	u32 txrx_ready:1;
+	u32 txrx_complete:1;
+	u32 txrx_error:1;
+	u32 txrx_underrun:1;
+	u32 framing_error:1;
+	u32 break_error:1;
+	u32 timeout_error:1;
+	u32 reserved3:8;
+	u32 chn_state:1;
+};
+
+struct pru_suart_regs_ovly {
+	struct pru_suart_cnh_cntrl_config1 ch_ctrl_config1;
+	struct pru_suart_chn_config2_status ch_config2_txrx_status;
+	u32 ch_txrx_data;
+	u32 reserved1;
+};
+
+struct pru_suart_tx_cntx_priv {
+	u32 asp_xsrctl_base;
+	u32 asp_xbuf_base;
+	u16 buff_addr;
+	u8 buff_size;
+	u8 bits_loaded;
+};
+
+struct pru_suart_rx_cntx_priv {
+	u32 asp_rbuf_base;
+	u32 asp_rsrctl_base;
+	u32 reserved1;
+	u32 reserved2;
+	u32 reserved3;
+	u32 reserved4;
+};
+
+struct suart_config {
+	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;
+};
+
+struct suart_handle {
+	u16 uart_num;
+	u16 uart_type;
+	u16 uart_tx_channel;
+	u16 uart_rx_channel;
+	u16 uart_status;
+};
+
+struct pruss_suart_iomap {
+	void __iomem *mcasp_io_addr;
+	void *p_fifo_buff_phys_base;
+	void *p_fifo_buff_virt_base;
+};
+
+struct pruss_suart_initparams {
+	u32 tx_baud_value;
+	u32 rx_baud_value;
+	u32 oversampling;
+};
+
+/* MCASP */
+struct omapl_mcasp_regs_ovly {
+	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 ditcsra[6];
+	u32 ditcsrb[6];
+	u32 ditudra[6];
+	u32 ditudrb[6];
+	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 xbuf[16];
+	u32 rsvd7[16];
+	u32 rbuf[16];
+};
+
+/*
+ *  SUART Config regs
+ */
+struct suart_struct_pru_regs {
+	u16 chn_ctrl;
+	u16 chn_config1;
+	u16 chn_config2;
+	u16 chn_txrx_status;
+	u32 chn_txrx_data;
+};
+
+extern s32 pru_softuart_init(struct device *dev,
+			struct pruss_suart_initparams *,
+			const u8 *pru_suart_emu_code, u32 fw_size,
+			u32 clk_rate_pruss,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern s32 pru_softuart_open(struct suart_handle *h_suart);
+
+extern s32 pru_softuart_close(struct suart_handle *h_uart);
+
+extern s32 pru_softuart_setbaud(struct device *dev,
+			struct suart_handle *h_uart,
+			u16 tx_clk_divisor, u16 rx_clk_divisor);
+
+extern s32 pru_softuart_setdatabits(struct device *dev,
+			struct suart_handle *h_uart,
+			u16 tx_data_bits, u16 rx_data_bits);
+
+extern s32 pru_softuart_setconfig(struct device *dev,
+			struct suart_handle *h_uart,
+			struct suart_config *config_uart);
+
+extern s32 pru_softuart_getconfig(struct device *dev,
+			struct suart_handle *h_uart,
+			struct suart_config *config_uart);
+
+extern s32 pru_softuart_pending_tx_request(struct device *dev);
+
+extern s32 pru_softuart_write(struct device *dev,
+			struct suart_handle *h_uart,
+			u32 *pt_tx_data_buf, u16 data_len);
+
+extern s32 pru_softuart_read(struct device *dev,
+			struct suart_handle *h_uart,
+			u32 *pt_data_buf, u16 data_len);
+
+extern s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
+						u32 txrxmode,
+						u32 intrmask);
+
+extern s32 pru_softuart_clr_tx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_tx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_clr_rx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_rx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num,
+			u16 *txrx_flag);
+
+extern s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num,
+							u32 txrxmode);
+
+extern s32 suart_intr_getmask(struct device *dev, u16 uart_num,
+						u32 txrxmode,
+						u32 intrmask);
+
+extern s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+			u32 txrxmode, u32 intrmask);
+
+extern s32 pru_softuart_get_tx_data_len(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_rx_data_len(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 suart_arm_to_pru_intr(struct device *dev, u16 uart_num);
+
+extern void pru_mcasp_deinit(void);
+
+extern s32 pru_softuart_read_data(struct device *dev,
+			struct suart_handle *h_uart,
+			u8 *p_data_buffer, s32 max_len,
+			u32 *pdata_read);
+
+extern s32 pru_softuart_stop_receive(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 suart_pru_to_host_intr_enable(struct device *dev,
+					u16 uart_num,
+					u32 txrxmode, s32 flag);
+
+extern void pru_set_fifo_timeout(struct device *dev, s16 timeout);
+
+extern void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern void suart_mcasp_reset(struct pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_baud_set(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_serializer_deactivate(u16 sr_num,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+			struct pruss_suart_iomap *pruss_ioaddr);
+#endif
diff --git a/drivers/tty/serial/pruss_suart_api.c b/drivers/tty/serial/pruss_suart_api.c
new file mode 100644
index 0000000..15178f5
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart_api.c
@@ -0,0 +1,1710 @@
+/*
+ * Copyright (C) 2010, 2011 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.h>
+#include "pruss_suart.h"
+
+static u8 uart_statu_table[8];
+static struct 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};
+
+static  s32 pru_softuart_clr_rx_fifo(struct device *dev,
+				struct suart_handle *h_uart);
+static s32 arm_to_pru_intr_init(struct device *dev);
+
+#if (PRU_ACTIVE == BOTH_PRU)
+static void pru_set_ram_data(struct device *dev,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 datatowrite;
+	u32 i;
+	struct pru_suart_regs_ovly *pru_suart_regs = NULL;
+	u32 __iomem *p_sr_ctl_addr = (u32 __iomem *)(pruss_ioaddr->
+						mcasp_io_addr + 0x180);
+	struct pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	struct 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_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						0x3, SUART_CHN_RX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_rx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_config2_txrx_status,
+								0xF, 8);
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+					PRU_SUART_HALF_RX_DISABLED) {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_RX_MODE, p_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_rmwl(dev, (u32) &pru_suart_regs->ch_txrx_data,
+				0xFFFF, RX_DEFAULT_DATA_DUMP_ADDR);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 0);
+		/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (struct pru_suart_rx_cntx_priv *)
+				(PRU0_DATARAM_OFFSET + (0x090 + (i * 0x020)));
+		datatowrite = (MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
+							datatowrite);
+		datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+							datatowrite);
+	}
+
+	/* PRU1 RAM BASE ADDR */
+	pru_suart_regs = (struct 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_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						0x3, SUART_CHN_TX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_tx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev,
+			(u32) &pru_suart_regs->ch_config2_txrx_status, 0xF, 8);
+
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED) {
+			pruss_rmwl(dev, (u32)
+				&pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_TX_MODE,
+				p_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 1);
+
+		/* SUART1 TX context base addr */
+		pru_suart_tx_priv = (struct pru_suart_tx_cntx_priv *)
+			(PRU1_DATARAM_OFFSET + (0x0B0 + (i * 0x02C)));
+		datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
+							datatowrite);
+		datatowrite = (MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+							datatowrite);
+		/* SUART1 TX formatted data base addr */
+		datatowrite = (0x0090 + (i * 0x002C));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+							datatowrite);
+	}
+}
+#else
+static void pru_set_ram_data(struct device *dev,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+
+	struct pru_suart_regs_ovly *pru_suart_regs =
+		(struct pru_suart_regs_ovly *)pruss_ioaddr->pru_io_addr;
+	u32 i;
+	u32 *p_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
+	struct pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	struct pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+
+	/* Channel 0 context information is Tx */
+	for (i = 0; i < 4; i++, pru_suart_regs++) {
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						0x3, SUART_CHN_TX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_tx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_config2_txrx_status,
+								0xF, 8);
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED){
+			pruss_rmwl(dev, (u32)
+				&pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_TX_MODE,
+						p_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 1);
+
+		/* SUART1 TX context base addr */
+		pru_suart_tx_priv = (struct 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)));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+				(MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2)));
+		/* SUART1 TX formatted data base addr */
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+					(0x0090 + (i * 0x050)));
+
+		/* Channel 1 is Rx context information */
+		pru_suart_regs++;
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+							0x3, SUART_CHN_RX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_rx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev,
+			(u32) &pru_suart_regs->ch_config2_txrx_status, 0xF, 8);
+
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+						PRU_SUART_HALF_RX_DISABLED) {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_RX_MODE,
+					p_sr_ctl_addr + uart_rx[i]);
+		}
+		/*
+		 * RX is active by default, write the dummy received data
+		 *@PRU RAM addr 0x1FC to avoid memory corruption
+		 */
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_txrx_data,
+				0xFFFF, RX_DEFAULT_DATA_DUMP_ADDR);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 0);
+		/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (struct 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)));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+				(MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2)));
+	}
+}
+#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);
+}
+
+static void pru_set_delay_count(struct device *dev, u32 pru_freq)
+{
+	u32 delay_cnt;
+
+	if (pru_freq == PRU_CLK_228)
+		delay_cnt = 5;
+	else if (pru_freq == PRU_CLK_186)
+		delay_cnt = 5;
+	else
+		delay_cnt = 3;
+
+	/* PRU 0 */
+	pruss_writeb(dev, PRU_SUART_PRU0_DELAY_OFFSET,
+		(u8) delay_cnt);
+
+	/* PRU 1 */
+	pruss_writeb(dev, PRU_SUART_PRU1_DELAY_OFFSET,
+		(u8) delay_cnt);
+}
+
+static s32 suart_set_pru_id(struct device *dev, u32 pru_no)
+{
+	u32 offset;
+	u8 reg_val = 0;
+
+	if (PRUSS_NUM0 == pru_no)
+		offset = PRU_SUART_PRU0_ID_ADDR;
+	else if (PRUSS_NUM1 == pru_no)
+		offset = PRU_SUART_PRU1_ID_ADDR;
+	else
+		return -EINVAL;
+
+	reg_val = pru_no;
+	pruss_writeb(dev, offset, reg_val);
+
+	return 0;
+}
+
+/*
+ * suart Initialization routine
+ */
+s32 pru_softuart_init(struct device *dev,
+			struct pruss_suart_initparams *init_params,
+			const u8 *pru_suart_emu_code, u32 fw_size,
+			u32 clk_rate_pruss,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 datatowrite[128] = {0};
+	s16 status = 0;
+	s16 idx;
+	s16 retval;
+	u16 i;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) &&
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH))
+		return -EINVAL;
+
+	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;
+	/* Configure McASP0  */
+	suart_mcasp_config(init_params->tx_baud_value,
+				init_params->rx_baud_value,
+				init_params->oversampling, pruss_ioaddr);
+	pruss_enable(dev, PRUSS_NUM0);
+
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pruss_enable(dev, PRUSS_NUM1);
+
+	/* Reset PRU RAM */
+	for (i = 0; i < (PRU0_DATARAM_SIZE / sizeof(int)); i++)
+		pruss_writel(dev, (PRU0_DATARAM_OFFSET + (i * sizeof(int))),
+							datatowrite[i]);
+	if (PRU1_MODE != PRU_MODE_INVALID) {
+		for (i = 0; i < (PRU1_DATARAM_SIZE / sizeof(int)); i++)
+			pruss_writel(dev, (PRU1_DATARAM_OFFSET +
+					(i * sizeof(int))), datatowrite[i]);
+	}
+
+	pruss_load(dev, PRUSS_NUM0, (u32 *)pru_suart_emu_code,
+					(fw_size / sizeof(u32)));
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		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, clk_rate_pruss);
+	suart_set_pru_id(dev, PRUSS_NUM0);
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		suart_set_pru_id(dev, PRUSS_NUM1);
+
+	pru_set_rx_tx_mode(dev, PRU0_MODE, PRUSS_NUM0);
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pru_set_rx_tx_mode(dev, PRU1_MODE, PRUSS_NUM1);
+
+	pru_set_ram_data(dev, pruss_ioaddr);
+	pruss_run(dev, PRUSS_NUM0);
+
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pruss_run(dev, PRUSS_NUM1);
+
+	/* Initialize uart_statu_table */
+	for (idx = 0; idx < 8; idx++)
+		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, (u16) timeout);
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pruss_writew(dev, PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET,
+						(u16) timeout);
+}
+
+void pru_mcasp_deinit(void)
+{
+	suart_mcasp_reset(&suart_iomap);
+}
+
+/* suart Instance open routine  */
+s32 pru_softuart_open(struct suart_handle *h_suart)
+{
+	s16 status = 0;
+	u16 uart_num = h_suart->uart_num - 1;
+
+	if (uart_statu_table[h_suart->uart_num - 1] ==
+			ePRU_SUART_UART_IN_USE) {
+		return -EUSERS;
+	} else {
+		h_suart->uart_type = uart_config[uart_num];
+		h_suart->uart_tx_channel = uart_tx[uart_num];
+		h_suart->uart_rx_channel = uart_rx[uart_num];
+		h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+		uart_statu_table[h_suart->uart_num - 1] =
+						ePRU_SUART_UART_IN_USE;
+	}
+	return status;
+}
+
+/* suart instance close routine */
+s32 pru_softuart_close(struct suart_handle *h_uart)
+{
+	s16 status = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	} else {
+		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;
+}
+
+static s32 search_chnum(u16 uart_num, u16 *ch_num, u32 *pru_offset, u16 mode)
+{
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		*ch_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (uart_num <= 4) {
+			*pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			*pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			*ch_num -= 8;
+		}
+		(mode == 2) ? ++*ch_num : *ch_num;
+	} else if (mode == 1) {
+			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 if (mode == 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;
+	}
+	return 0;
+}
+
+/*
+ * suart routine for setting relative baud rate
+ */
+s32 pru_softuart_setbaud(struct device *dev, struct suart_handle *h_uart,
+		u16 tx_clk_divisor, u16 rx_clk_divisor)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 regval = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Set the clock divisor value s32o the McASP */
+	if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
+		return -EINVAL;
+	if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
+		return -EINVAL;
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	if (tx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writew(dev, offset, regval);
+	}
+	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 0;
+	}
+	regval = 0;
+	if (rx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writew(dev, offset, regval);
+	}
+	return status;
+}
+
+/*
+ * suart routine for setting number of bits per character for a specific uart
+ */
+s32 pru_softuart_setdatabits(struct device *dev, struct suart_handle *h_uart,
+		u16 tx_data_bits, u16 rx_data_bits)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u32 reg_val;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/*
+	 * 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 -EINVAL;
+
+	if ((rx_data_bits < ePRU_SUART_DATA_BITS6)
+			|| (rx_data_bits > ePRU_SUART_DATA_BITS12))
+		return -EINVAL;
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	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);
+		reg_val &= ~(0xF);
+		reg_val |= tx_data_bits;
+		pruss_writeb(dev, offset, (u8) reg_val);
+	}
+	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 0;
+	}
+	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);
+		reg_val &= ~(0xF);
+		reg_val |= rx_data_bits;
+		pruss_writeb(dev, offset, (u8) rx_data_bits);
+	}
+
+	return status;
+}
+
+/*
+ * suart routine to configure specific uart
+ */
+s32 pru_softuart_setconfig(struct device *dev, struct suart_handle *h_uart,
+				struct suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/*
+	 * 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 -EINVAL;
+	}
+	if ((config_uart->tx_bits_per_char < 8)
+			|| (config_uart->tx_bits_per_char > 14)) {
+		return -EINVAL;
+	}
+	if ((config_uart->rx_bits_per_char < 8)
+			|| (config_uart->rx_bits_per_char > 14)) {
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	/*
+	 * 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_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->tx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->tx_clk_divisor <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->tx_bits_per_char <<
+			PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+	}
+
+	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 0;
+	}
+
+	/* 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_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->rx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+
+		/* Configuring RX prescalar value and Oversampling */
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		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_writew(dev, offset, reg_val);
+
+		/* Configuring RX bits per character value */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+						+ PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->rx_bits_per_char <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+	}
+	return status;
+}
+
+/*
+ * suart routine for getting the number of bytes transfered
+ */
+s32 pru_softuart_get_tx_data_len(struct device *dev,
+					struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 read_value = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &read_value);
+	read_value = ((read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	return read_value;
+}
+
+/*
+ * suart routine for getting the number of bytes received
+ */
+s32 pru_softuart_get_rx_data_len(struct device *dev,
+					struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 read_value = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &read_value);
+	read_value = ((read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	return read_value;
+}
+
+/*
+ * suart routine to get the configuration information from a specific uart
+ */
+s32 pru_softuart_getconfig(struct device *dev,
+			 struct suart_handle *h_uart,
+			struct suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+	s16 status = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/*
+	 * NOTE:
+	 * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
+	 * EQUAL TO 64, preScalarValue <= 64
+	 */
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	/* 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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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 0;
+	}
+	/* 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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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 ISR_value = 0;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		return 0;
+	} 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 *)&ISR_value);
+		if ((ISR_value & 0x1) == 0x1)
+			return -EINVAL;
+	} 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 *)&ISR_value);
+		if ((ISR_value & 0x2) == 0x2)
+			return -EINVAL;
+	} else {
+		return 0;
+	}
+
+	return 0;
+}
+
+/*
+ * suart data transmit routine
+ */
+s32 pru_softuart_write(struct device *dev, struct suart_handle *h_uart,
+		u32 *pt_tx_data_buf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH))
+		pru_num = h_uart->uart_num;
+	else if (PRU0_MODE == PRU_MODE_TX_ONLY)
+		pru_num = 0;
+	else if (PRU1_MODE == PRU_MODE_TX_ONLY)
+		pru_num = 1;
+	else
+		return 0;
+
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writew(dev, offset, reg_val);
+
+	/* 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_writel(dev, offset, (u32) *pt_tx_data_buf);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	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_writew(dev, offset, reg_val);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, pru_num);
+
+	return status;
+}
+
+/*
+ * suart data receive routine
+ */
+s32 pru_softuart_read(struct device *dev, struct suart_handle *h_uart,
+		u32 *ptDataBuf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+	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;
+		pru_num = h_uart->uart_num;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_num = 1;
+	} else {
+		return 0;
+	}
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writew(dev, offset, reg_val);
+
+	/* 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_writel(dev, offset, (u32) *ptDataBuf);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+		PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	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_writew(dev, offset, reg_val);
+
+	/* 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
+ */
+s32 pru_softuart_read_data(struct device *dev, struct suart_handle *h_uart,
+				u8 *p_data_buffer, s32 max_len,
+					u32 *pdata_read)
+{
+	s16 ret_val = 0;
+	u8 *psrc_addr = NULL;
+	u32 data_read = 0;
+	u32 data_len = 0;
+	u32 char_len = 0;
+	u32 offset = 0;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 status = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	/* 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_multi(dev, offset, (u8 *) &psrc_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_readw(dev, offset, (u16 *) &data_len);
+
+	/* read the character length */
+	char_len = data_len & PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK;
+	char_len -= 2;	/* remove the START & STOP bit */
+
+	data_len &= PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	data_len = data_len >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT;
+	data_len++;
+
+	/* if the character length is greater than 8, then the size doubles */
+	if (char_len > 8)
+		data_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 *) &status);
+	if (CHN_TXRX_STATUS_TIMEOUT == (status & 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 *) &data_read);
+
+		/* if the character length is greater than 8,
+				then the size doubles */
+		if (char_len > 8)
+			data_read *= 2;
+
+/*
+ * the data corresponding is loaded in second
+ * half during the timeout
+ */
+		if (data_read > data_len) {
+			data_read -= data_len;
+			psrc_addr += data_len;
+		}
+
+		pru_softuart_clr_rx_fifo(dev, h_uart);
+	} else {
+		data_read = data_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 (status & CHN_TXRX_STATUS_CMPLT)
+			psrc_addr += data_len;
+	}
+
+	/* we should be copying only max len given by the application */
+	if (data_read > max_len)
+		data_read = max_len;
+
+/* evaluate the virtual address of the FIFO address
+ * based on the physical addr
+ */
+	psrc_addr = (u8 *)((u32) psrc_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 < data_read; offset++)
+		*p_data_buffer++ = *psrc_addr++;
+	*pdata_read = data_read;
+	ret_val = 0;
+
+	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.
+ */
+s32 pru_softuart_stop_receive(struct device *dev, struct suart_handle *h_uart)
+{
+	u16 ret_status = 0;
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 status;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	/* 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 *) &status);
+
+	/* we need to clear the busy bit corresponding to receive channel */
+	status &= ~(CHN_TXRX_STATUS_RDY);
+	pruss_writeb(dev, offset, (u8) status);
+
+	/* 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_readw(dev, offset, (u16 *) &status);
+	status &= PRU_SUART_CH_CTRL_SR_MASK;
+	status = status >> PRU_SUART_CH_CTRL_SR_SHIFT;
+
+	/* we need to de-activate the serializer corresponding to this rx */
+	ret_status = suart_asp_serializer_deactivate(status, &suart_iomap);
+
+	return ret_status;
+}
+
+/*
+ * suart routine to get the tx status for a specific uart
+ */
+s32 pru_softuart_get_tx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	return status;
+}
+
+s32 pru_softuart_clr_tx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	status &= ~(0x2);
+	pruss_writeb(dev, offset, (u8) status);
+	return status;
+}
+
+/*
+ * suart routine to get the rx status for a specific uart
+ */
+s32 pru_softuart_get_rx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	return status;
+}
+
+static s32 pru_softuart_clr_rx_fifo(struct device *dev,
+				struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val;
+	u16 uart_num;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	uart_num = h_uart->uart_num;
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+	if (PRU0_MODE == PRU_MODE_RX_ONLY)
+		uart_num = 0;
+	else if (PRU1_MODE == PRU_MODE_RX_ONLY)
+		uart_num = 1;
+
+	/* Reset the number of bytes read into the FIFO */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+					+ PRU_SUART_CH_BYTESDONECNTR_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+	reg_val &= 0x00;
+		pruss_writew(dev, offset, reg_val);
+
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	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_writew(dev, offset, reg_val);
+	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;
+}
+
+s32 pru_softuart_clr_rx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	status &= ~(0x3C);
+	pruss_writeb(dev, offset, (u8) status);
+	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 >
+ */
+s32 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num, u16 *txrx_flag)
+{
+	u32 intc_offset;
+	u32 ch_num = 0xFF;
+	u32 reg_val = 0;
+	u32 reg_val2 = 0;
+	u32 ISR_value = 0;
+	u32 ack_reg_val = 0;
+	u32 stat_inx_clr_regoffset = 0;
+
+	/* initialize the status & Flag to known value */
+	*txrx_flag = 0;
+
+	stat_inx_clr_regoffset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+
+	/* Read PRU Interrupt Status Register from PRU */
+	intc_offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+
+	pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* Check if the interrupt occured for Tx */
+		ch_num = uart_num * 2 - 2;
+		reg_val2 = PRU_SUART0_TX_EVT_BIT << ((uart_num - 1) * 2);
+		if (ISR_value & reg_val2) {
+			/* interupt occured for TX */
+			*txrx_flag |= PRU_TX_INTR;
+			/* acknowledge the RX interrupt  */
+			ack_reg_val  = ch_num + PRU_SUART0_TX_EVT;
+			pruss_writel(dev, stat_inx_clr_regoffset,
+					ack_reg_val);
+		}
+
+		/* Check if the interrupt occured for Rx */
+		reg_val2 = PRU_SUART0_RX_EVT_BIT << ((uart_num - 1) * 2);
+		pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
+		if (ISR_value & reg_val2) {
+			/* interupt occured for RX */
+			*txrx_flag |= PRU_RX_INTR;
+			ch_num += 1;
+
+			/* acknowledge the RX interrupt  */
+			ack_reg_val  = ch_num + PRU_SUART0_TX_EVT;
+			pruss_writel(dev, stat_inx_clr_regoffset,
+						ack_reg_val);
+		}
+	} else {
+		ch_num = uart_num - 1;
+		if ((ISR_value & 0x03FC) != 0) {
+			reg_val2 = 1 << (uart_num + 1);
+			if (ISR_value & reg_val2) {
+				/* acknowledge the s32errupt  */
+				ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, stat_inx_clr_regoffset,
+					ack_reg_val);
+				*txrx_flag |= PRU_RX_INTR;
+			}
+		}
+		pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
+		if (ISR_value & 0x3FC00) {
+			reg_val2 = 1 << (uart_num + 9);
+			if (ISR_value & reg_val2) {
+				/* acknowledge the s32errupt  */
+				ack_reg_val = ch_num + PRU_SUART4_TX_EVT;
+				pruss_writel(dev, stat_inx_clr_regoffset,
+					ack_reg_val);
+				*txrx_flag |= PRU_TX_INTR;
+			}
+		}
+	}
+	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 0;
+	}
+
+	pruss_readb(dev, offset, (u8 *) &txrx_flag);
+	txrx_flag &= ~(0x2);
+	pruss_writeb(dev, offset, (u8) txrx_flag);
+
+	return 0;
+}
+
+s32 suart_arm_to_pru_intr(struct device *dev, u16 uart_num)
+{
+	u32 value;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		if ((uart_num > 0) && (uart_num <= 4))
+			value = 0x20; /* PRU0 SYS_EVT32 */
+		else if ((uart_num > 4) && (uart_num <= 8))
+			value = 0x21; /* PRU0 SYS_EVT33 */
+		else
+			return -EINVAL;
+	}
+	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)
+			value = 0x20; /* PRU0 SYS_EVT32 */
+		else if (uart_num == PRUSS_NUM1)
+			value = 0x21; /* PRU0 SYS_EVT33 */
+		else
+			return -EINVAL;
+	}
+	return pruss_writel(dev, PRUSS_INTC_STATIDXSET, value);
+}
+
+static s32 arm_to_pru_intr_init(struct device *dev)
+{
+	u32 value;
+	u32 int_offset;
+
+	/* Clear all the host interrupts */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++)
+		pruss_idx_writel(dev, PRUSS_INTC_HSTINTENIDXCLR, int_offset);
+
+	/* Enable the global s32errupt */
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_GLBLEN & 0xFFFF), 0, 1);
+
+	/* Enable the Host interrupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							 int_offset++)
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF),
+								0, int_offset);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP0 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP0_CHAN);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP1 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP1_CHAN);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP2 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP2_CHAN);
+
+	 /* MAP Channel 0 to SYS_EVT31 */
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP7 & 0xFFFF),
+			PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP7_SYS_EVT31);
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* Sets the channels for the system interrupt */
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP9_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP10_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP11_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP12_FULL);
+	}
+	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 channels for the system interrupt */
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP9_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP10_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP11_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP12_HALF);
+	}
+
+	/* Clear required set of system events
+	* and enable them using indexed register
+	*/
+	for (int_offset = 0; int_offset < 18; int_offset++) {
+		value = 32 + int_offset;
+		pruss_idx_writel(dev, PRUSS_INTC_STATIDXCLR, value);
+	}
+
+	/* enable only the HOST to PRU interrupts and let the PRU to Host events
+	 * enabled by the separate API on demand basis.
+	 */
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 31);
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 32);
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 33);
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 50);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_GLBLEN & 0xFFFF), 0, 1);
+
+	/* Enable the Host interrupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++)
+		pruss_idx_writel(dev, PRUSS_INTC_HSTINTENIDXSET, int_offset);
+
+	return 0;
+}
+
+s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
+		u32 txrxmode, s32 flag)
+{
+	u32 chn_num;
+	u32 value;
+	s16 retval = 0;
+
+	if (uart_num > 8)
+		return -EINVAL;
+
+	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++;
+		value = 34 + chn_num;
+	} else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_RX_ONLY))
+		value = 34 + chn_num;
+	else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_RX_ONLY))
+		value = 42 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_TX_ONLY))
+		value = 34 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_TX_ONLY))
+		value = 42 + chn_num;
+	else
+		return -EINVAL;
+
+	retval = flag ? pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, value) :
+			pruss_idx_writel(dev, PRUSS_INTC_ENIDXCLR, value);
+	return retval;
+}
+
+s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	u32 regval = 0;
+	u32 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 -EINVAL;
+		}
+		if (2 == txrxmode)
+			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) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+	} else
+		return 0;
+
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (rmask & CHN_TXRX_IE_MASK_CMPLT))
+		pruss_rmww(dev, offset, regval, regval);
+
+	if ((rmask & SUART_GBL_INTR_ERR_MASK) ==
+			SUART_GBL_INTR_ERR_MASK) {
+		regval = SUART_GBL_INTR_ERR_MASK;
+		pruss_rmww(dev, offset, regval, regval);
+	}
+
+	offset = pru_offset +
+		(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+				+ PRU_SUART_CH_CONFIG1_OFFSET;
+	/* Framing Error Interrupt Masked */
+	if ((rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		regval |= CHN_TXRX_IE_MASK_FE;
+		pruss_writew(dev, offset, (u16) regval);
+	}
+
+	/* Break Indicator Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		regval |= CHN_TXRX_IE_MASK_BI;
+		pruss_writew(dev, offset, (u16) regval);
+	}
+
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		regval |= CHN_TXRX_IE_MASK_TIMEOUT;
+		pruss_writew(dev, offset, (u16) regval);
+	}
+	return 0;
+}
+
+s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	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 -EINVAL;
+		if (2 == txrxmode)
+			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) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+	} else
+		return 0;
+
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (rmask & CHN_TXRX_IE_MASK_CMPLT))
+		pruss_rmww(dev, offset, regval, 0);
+
+	if ((rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK)
+		pruss_rmww(dev, offset, SUART_GBL_INTR_ERR_MASK, 0);
+
+	offset = pru_offset +
+		(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+				+ PRU_SUART_CH_CONFIG1_OFFSET;
+
+	/* Framing Error Interrupt Masked */
+	if ((rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		pruss_writew(dev, offset, regval);
+	}
+
+	/* Break Indicator Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		pruss_writew(dev, offset, regval);
+	}
+
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		pruss_writew(dev, offset, regval);
+	}
+	return 0;
+}
+
+s32 suart_intr_getmask(struct device *dev, u16 uart_num,
+				u32 txrxmode, u32 rmask)
+{
+	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 -EINVAL;
+
+		if (2 == txrxmode)
+			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 0;
+
+	regval = regval << chn_num;
+	pruss_readw(dev, offset, (u16 *) &txrx_flag);
+	txrx_flag &= regval;
+
+	if ((rmask && (txrx_flag == regval)) || (!rmask && !txrx_flag))
+		return 1;
+
+	return 0;
+}
diff --git a/drivers/tty/serial/pruss_suart_utils.c b/drivers/tty/serial/pruss_suart_utils.c
new file mode 100644
index 0000000..5ee340e
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart_utils.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2010, 2011 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.h>
+#include "pruss_suart.h"
+
+#define SUART_TRX_DIV_CONF_SZ	4
+
+static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+			struct pruss_suart_iomap *pruss_ioaddr);
+static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value, u32 oversampling,
+			struct 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
+ */
+static 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
+ */
+static 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
+ */
+static 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_reset(struct pruss_suart_iomap *pruss_ioaddr)
+{
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+	/* reset mcasp. */
+	iowrite32(MCASP_SUART_GBLCTL, &mcasp0_regs->gblctl);
+	iowrite32(MCASP_SUART_RGBLCTL, &mcasp0_regs->rgblctl);
+	iowrite32(MCASP_SUART_XGBLCTL, &mcasp0_regs->xgblctl);
+	iowrite32(MCASP_SUART_XSTAT, &mcasp0_regs->xstat);
+	iowrite32(MCASP_SUART_RSTAT, &mcasp0_regs->rstat);
+}
+
+void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value,
+			u32 oversampling,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	/* reset mcasp */
+	iowrite32(MCASP_SUART_GBLCTL, &mcasp0_regs->gblctl);
+	iowrite32(MCASP_SUART_RGBLCTL, &mcasp0_regs->rgblctl);
+	iowrite32(MCASP_SUART_XGBLCTL, &mcasp0_regs->xgblctl);
+
+	/* configure receive registers */
+	if ((SUART_8X_OVRSMPL == oversampling) || (0 == oversampling)) {
+		iowrite32(MCASP_SUART_RMASK_8, &mcasp0_regs->rmask);
+		iowrite32(MCASP_SUART_RFMT_8, &mcasp0_regs->rfmt);
+	}
+	if (SUART_16X_OVRSMPL == oversampling) {
+		iowrite32(MCASP_SUART_RMASK_16, &mcasp0_regs->rmask);
+		iowrite32(MCASP_SUART_RFMT_16, &mcasp0_regs->rfmt);
+
+	}
+
+	iowrite32(MCASP_SUART_FSRM, &mcasp0_regs->afsrctl);
+	iowrite32(MCASP_SUART_CLKRM_CLKRP, &mcasp0_regs->aclkrctl);
+	iowrite32(MCASP_SUART_HCLKRP, &mcasp0_regs->ahclkrctl);
+	suart_mcasp_rx_baud_set(rx_baud_value, oversampling, pruss_ioaddr);
+	iowrite32(MCASP_SUART_RTDMS0, &mcasp0_regs->rtdm);
+	iowrite32(MCASP_SUART_RSYNCERR, &mcasp0_regs->rintctl);
+	iowrite32(MCASP_SUART_RMAX_RPS_256, &mcasp0_regs->rclkchk);
+
+	/* configure transmit registers. */
+	iowrite32(MCASP_SUART_XMASK_0_31, &mcasp0_regs->xmask);
+	iowrite32(MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0, &mcasp0_regs->xfmt);
+	iowrite32(MCASP_SUART_FSXM, &mcasp0_regs->afsxctl);
+	iowrite32(MCASP_SUART_CLKXM_ASYNC_CLKXP, &mcasp0_regs->aclkxctl);
+	iowrite32(MCASP_SUART_HCLKXM, &mcasp0_regs->ahclkxctl);
+
+	suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
+	iowrite32(MCASP_SUART_XTDMS0, &mcasp0_regs->xtdm);
+	iowrite32(MCASP_SUART_XSYNCERR, &mcasp0_regs->xintctl);
+	iowrite32(MCASP_SUART_XMAX_XPS_256, &mcasp0_regs->xclkchk);
+
+	/* Serializer as a transmitter */
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl0);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl1);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl2);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl3);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl4);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl5);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl6);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl7);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl8);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl9);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl10);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl11);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl12);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl13);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl14);
+	iowrite32(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);
+	iowrite32(temp_reg, &mcasp0_regs->pfunc);
+
+	iowrite32(0xFFF, &mcasp0_regs->pdout);
+
+	/* config pin function and direction */
+	iowrite32(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);
+	iowrite32(temp_reg, &mcasp0_regs->pdir);
+
+	iowrite32(MCASP_SUART_DIT_DISABLE, &mcasp0_regs->ditctl);
+	iowrite32(MCASP_SUART_LOOPBACK_DISABLE, &mcasp0_regs->dlbctl);
+	iowrite32(MCASP_SUART_AMUTE_DISABLE, &mcasp0_regs->amute);
+
+	iowrite32(MCASP_SUART_XSTAT, &mcasp0_regs->xstat);
+	iowrite32(MCASP_SUART_RSTAT, &mcasp0_regs->rstat);
+}
+
+void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+		struct pruss_suart_iomap *pruss_ioaddr)
+{
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+	temp_reg = ioread32(&mcasp0_regs->pfunc);
+	temp_reg |= (0x1 << serializer_num);
+	iowrite32(temp_reg, &mcasp0_regs->pfunc);
+}
+
+/*
+ * mcasp TX buard rate setting routine
+ */
+static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+		struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val;
+	u32 loop_cnt;
+	s16 status = 0;
+	s16 found_val = false;
+
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					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 = true;
+			break;
+		}
+	}
+	if (found_val == true) {
+		clk_div_val = lt_tx_baud_rate[loop_cnt][2];
+		temp_reg = ioread32(&mcasp0_regs->aclkxctl);
+		temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+		iowrite32(temp_reg, &mcasp0_regs->aclkxctl);
+		clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+		temp_reg = ioread32(&mcasp0_regs->ahclkxctl);
+		temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+		iowrite32(temp_reg, &mcasp0_regs->ahclkxctl);
+	} else {
+		return -EINVAL ;
+	}
+	return status;
+}
+
+/*
+ * mcasp RX buard rate setting routine
+ */
+static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value,
+	u32 oversampling, struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val = 0;
+	u32 loop_cnt = 0;
+	s16 status = 0;
+	u32 temp_reg = 0;
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+
+	switch (oversampling) {
+	case 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 = ioread32(&mcasp0_regs->aclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
+
+				clk_div_val =
+				lt_rx_8x_baud_rate[loop_cnt][3] - 1;
+
+				temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
+				break;
+			}
+		}
+		status = -EINVAL;
+		break;
+	case 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 = ioread32(&mcasp0_regs->aclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
+				clk_div_val = lt_rx_16x_baud_rate[loop_cnt][3];
+				temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
+				break;
+			}
+		}
+		status = -EINVAL;
+		break;
+	case SUART_TX_OVRSMPL:
+		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 = ioread32(&mcasp0_regs->aclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
+				clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+				temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
+				break;
+			}
+		}
+		status = -EINVAL;
+		break;
+	default:
+		status = -EINVAL;
+		break;
+	}
+
+	return status;
+}
+
+/*
+ * mcasp buard rate setting routine
+ */
+s16 suart_asp_baud_set(u32 tx_baud_value, u32 rx_baud_value, u32 oversampling,
+					struct pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = 0;
+
+	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 sr_num,
+		struct pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = 0;
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+		 pruss_ioaddr->mcasp_io_addr;
+	if (sr_num > 15)
+		status = -EINVAL;
+	else
+		iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl0);
+
+	return status;
+}
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] 166+ messages in thread

* [PATCH v4 00/11] pruss mfd drivers.
@ 2011-04-22 12:08 Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                   ` (10 more replies)
  0 siblings, 11 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 4:
=========
MFD:
* added mfd_cells in the board file
* exported seperate multiwrite/read functions
* removed clk_get_pruss api
* improved coding style
* removed code duplications
* renamed files to pruss based
* used make C=1
* added __iomem cookie for io addresses
* used iowrite/read instead of __raw variants

SUART:
* changes for the new mfd_cell implementation
* code cleanup
* used iowrite/read instead of __raw variants
* used make C=1

NOTE:
* as requested by the owner the CAN driver patch is submitted seperately.

version 3:
=========
* added locking to mfd driver.
* removed typedefs.
* resource allocation through mfd.
* renamed da8xx_register_pruss to da8xx_register_pruss_mfd.
* removed da8xx_pruss directory for suart.
* combined all suart headers.
* modified register structure for pruss.
* added function clk_add_alias_mcasp.
* suart api layer cleanup.
* removed semaphore usage.
* updated to latest internal code base.
* removed __suart_err/dbg.

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.

Subhasish Ghosh (11):
  mfd: add pruss mfd driver.
  da850: add pruss clock.
  da850: pruss platform specific additions.
  da850: pruss board specific additions.
  mfd: pruss SUART private data.
  da850: pruss SUART board specific additions.
  da850: pruss SUART platform specific additions.
  tty: add pruss SUART driver
  mfd: pruss CAN private data.
  da850: pruss CAN platform specific additions.
  da850: pruss CAN board specific additions.

 arch/arm/mach-davinci/board-da850-evm.c    |  104 ++
 arch/arm/mach-davinci/da850.c              |   12 +
 arch/arm/mach-davinci/devices-da8xx.c      |   81 ++
 arch/arm/mach-davinci/include/mach/da8xx.h |    4 +
 arch/arm/mach-davinci/include/mach/mux.h   |    5 +
 drivers/mfd/Kconfig                        |   10 +
 drivers/mfd/Makefile                       |    1 +
 drivers/mfd/pruss.c                        |  513 +++++++++
 drivers/tty/serial/Kconfig                 |   18 +
 drivers/tty/serial/Makefile                |    6 +
 drivers/tty/serial/pruss_suart.c           | 1061 +++++++++++++++++
 drivers/tty/serial/pruss_suart.h           | 1038 +++++++++++++++++
 drivers/tty/serial/pruss_suart_api.c       | 1710 ++++++++++++++++++++++++++++
 drivers/tty/serial/pruss_suart_utils.c     |  393 +++++++
 include/linux/mfd/pruss.h                  |  140 +++
 include/linux/mfd/pruss_core.h             |  128 +++
 include/linux/serial_core.h                |    2 +
 17 files changed, 5226 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/pruss.c
 create mode 100644 drivers/tty/serial/pruss_suart.c
 create mode 100644 drivers/tty/serial/pruss_suart.h
 create mode 100644 drivers/tty/serial/pruss_suart_api.c
 create mode 100644 drivers/tty/serial/pruss_suart_utils.c
 create mode 100644 include/linux/mfd/pruss.h
 create mode 100644 include/linux/mfd/pruss_core.h

-- 
1.7.2.3

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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.
For details regarding the PRUSS please refer the folowing link:
http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem

The rational behind the MFD driver being the fact that multiple devices can
be implemented on the cores independently. This is determined by the nature
of the program which is loaded into the PRU's instruction memory.
A device may be de-initialized and another loaded or two different devices
can be run simultaneously on the two cores.
It's also possible, as in our case, to implement a single device on both
the PRU's resulting in improved load sharing.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/mfd/Kconfig            |   10 +
 drivers/mfd/Makefile           |    1 +
 drivers/mfd/pruss.c            |  513 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/pruss.h      |  130 ++++++++++
 include/linux/mfd/pruss_core.h |  128 ++++++++++
 5 files changed, 782 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/pruss.c
 create mode 100644 include/linux/mfd/pruss.h
 create mode 100644 include/linux/mfd/pruss_core.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0284c53..41479e4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -92,6 +92,16 @@ config MFD_TI_SSP
 	  To compile this driver as a module, choose M here: the
 	  module will be called ti-ssp.
 
+config MFD_DA8XX_PRUSS
+	tristate "Texas Instruments DA8XX PRUSS support"
+	depends on ARCH_DAVINCI_DA850
+	select MFD_CORE
+	help
+	  This driver provides support API 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 c56b6c7..8015dea 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)	+= pruss.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
 
diff --git a/drivers/mfd/pruss.c b/drivers/mfd/pruss.c
new file mode 100644
index 0000000..6836d5a
--- /dev/null
+++ b/drivers/mfd/pruss.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2010, 2011 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/spinlock.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mfd/pruss.h>
+#include <linux/mfd/core.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+struct pruss_priv {
+	struct device *dev;
+	spinlock_t lock;
+	struct resource *res;
+	struct clk *clk;
+	void __iomem *ioaddr;
+};
+
+s32 pruss_disable(struct device *dev, u8 pruss_num)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 temp_reg;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	spin_lock(&pruss->lock);
+
+	/* pruss deinit */
+	iowrite32(0xFFFFFFFF, &pruss_mmap->intc.statclrint[pruss_num]);
+
+	/* Disable PRU */
+	h_pruss = &pruss_mmap->core[pruss_num];
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
+			((PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
+			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+			PRUCORE_CONTROL_COUNTENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+		~PRUCORE_CONTROL_ENABLE_MASK) |
+		((PRUCORE_CONTROL_ENABLE_DISABLE <<
+		PRUCORE_CONTROL_ENABLE_SHIFT) &
+		PRUCORE_CONTROL_ENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+
+	/* Reset PRU */
+	iowrite32(PRUCORE_CONTROL_RESETVAL,
+				&h_pruss->control);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_disable);
+
+s32 pruss_enable(struct device *dev, u8 pruss_num)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 i;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	h_pruss = &pruss_mmap->core[pruss_num];
+
+	/* Reset PRU  */
+	spin_lock(&pruss->lock);
+	iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);
+	spin_unlock(&pruss->lock);
+
+	/* Reset any garbage in the ram */
+	if (pruss_num == PRUCORE_0)
+		for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
+			iowrite32(0x0, &pruss_mmap->dram0[i]);
+	else if (pruss_num == PRUCORE_1)
+		for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
+			iowrite32(0x0, &pruss_mmap->dram1[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_enable);
+
+/* Load the specified PRU with code */
+s32 pruss_load(struct device *dev, u8 pruss_num,
+			u32 *pruss_code, u32 code_size_in_words)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 __iomem *pruss_iram;
+	u32 i;
+
+	if (pruss_num == PRUCORE_0)
+		pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
+	else if (pruss_num == PRUCORE_1)
+		pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
+	else
+		return -EINVAL;
+
+	pruss_enable(dev, pruss_num);
+
+	spin_lock(&pruss->lock);
+	/* Copy dMAX code to its instruction RAM  */
+	for (i = 0; i < code_size_in_words; i++)
+		iowrite32(pruss_code[i], (pruss_iram + i));
+
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_load);
+
+s32 pruss_run(struct device *dev, u8 pruss_num)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 temp_reg;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	h_pruss = &pruss_mmap->core[pruss_num];
+
+	/* Enable dMAX, let it execute the code we just copied */
+	spin_lock(&pruss->lock);
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
+			((PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
+			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+			PRUCORE_CONTROL_COUNTENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+			~PRUCORE_CONTROL_ENABLE_MASK) |
+			((PRUCORE_CONTROL_ENABLE_ENABLE <<
+			PRUCORE_CONTROL_ENABLE_SHIFT) &
+			PRUCORE_CONTROL_ENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_run);
+
+s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 temp_reg;
+	u32 cnt = timeout;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	h_pruss = &pruss_mmap->core[pruss_num];
+
+	while (cnt--) {
+		temp_reg = ioread32(&h_pruss->control);
+		if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
+				PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
+				PRUCORE_CONTROL_RUNSTATE_HALT)
+			break;
+	}
+	if (!cnt)
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_wait_for_halt);
+
+s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite8(pdatatowrite, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writeb);
+
+s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddress;
+	u32 preg_data;
+
+	paddress = pruss->ioaddr + offset;
+
+	spin_lock(&pruss->lock);
+	preg_data = ioread8(paddress);
+	preg_data &= ~mask;
+	preg_data |= val;
+	iowrite8(preg_data, paddress);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_rmwb);
+
+s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstoread;
+
+	paddresstoread = pruss->ioaddr + offset ;
+	*pdatatoread = ioread8(paddresstoread);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readb);
+
+s32 pruss_readb_multi(struct device *dev, u32 offset,
+		u8 *pdatatoread, u16 bytestoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	u8 __iomem *paddresstoread;
+	u16 i;
+
+	paddresstoread = pruss->ioaddr + offset;
+
+	for (i = 0; i < bytestoread; i++)
+		*pdatatoread++ = ioread8(paddresstoread++);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readb_multi);
+
+s32 pruss_writel(struct device *dev, u32 offset,
+		u32 pdatatowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite32(pdatatowrite, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writel);
+
+s32 pruss_writel_multi(struct device *dev, u32 offset,
+		u32 *pdatatowrite, u16 wordstowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	u32 __iomem *paddresstowrite;
+	u16 i;
+
+	paddresstowrite = pruss->ioaddr + offset;
+
+	for (i = 0; i < wordstowrite; i++)
+		iowrite32(*pdatatowrite++, paddresstowrite++);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writel_multi);
+
+s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddress;
+	u32 preg_data;
+
+	paddress = pruss->ioaddr + offset;
+
+	spin_lock(&pruss->lock);
+	preg_data = ioread32(paddress);
+	preg_data &= ~mask;
+	preg_data |= val;
+	iowrite32(preg_data, paddress);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_rmwl);
+
+s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstoread;
+
+	paddresstoread = pruss->ioaddr + offset;
+	*pdatatoread = ioread32(paddresstoread);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readl);
+
+s32 pruss_readl_multi(struct device *dev, u32 offset,
+		u32 *pdatatoread, u16 wordstoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	u32 __iomem *paddresstoread;
+	u16 i;
+
+	paddresstoread = pruss->ioaddr + offset;
+	for (i = 0; i < wordstoread; i++)
+		*pdatatoread++ = ioread32(paddresstoread++);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readl_multi);
+
+s32 pruss_writew(struct device *dev, u32 offset, u16 pdatatowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite16(pdatatowrite, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writew);
+
+s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddress;
+	u32 preg_data;
+
+	paddress = pruss->ioaddr + offset;
+
+	spin_lock(&pruss->lock);
+	preg_data = ioread16(paddress);
+	preg_data &= ~mask;
+	preg_data |= val;
+	iowrite16(preg_data, paddress);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_rmww);
+
+s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstoread;
+
+	paddresstoread = pruss->ioaddr + offset;
+	*pdatatoread = ioread16(paddresstoread);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readw);
+
+s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite32(value, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_idx_writel);
+
+static int pruss_mfd_add_devices(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mfd_cell *cell = pdev->dev.platform_data;
+	s32 err, i, num_devices = 0;
+
+	for (i = 0; cell[i].name; i++) {
+		err = mfd_add_devices(dev, 0, &cell[i], 1, NULL, 0);
+		if (err) {
+			dev_err(dev, "cannot add mfd cell: %s\n",
+						cell[i].name);
+			continue;
+		}
+		num_devices++;
+		dev_info(dev, "mfd: added %s device\n", cell[i].name);
+	}
+
+	return num_devices;
+}
+
+static int __devinit pruss_probe(struct platform_device *pdev)
+{
+	struct pruss_priv *pruss_dev = NULL;
+	s32 err;
+
+	pruss_dev = kzalloc(sizeof(struct pruss_priv), 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;
+	}
+	spin_lock_init(&pruss_dev->lock);
+
+	clk_enable(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 pruss_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pruss_priv *pruss = dev_get_drvdata(dev);
+
+	mfd_remove_devices(dev);
+	pruss_disable(dev, PRUCORE_0);
+	pruss_disable(dev, PRUCORE_1);
+	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 pruss_driver = {
+	.probe	= pruss_probe,
+	.remove	= __devexit_p(pruss_remove),
+	.driver	= {
+		.name	= "pruss_mfd",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init pruss_init(void)
+{
+	return platform_driver_register(&pruss_driver);
+}
+module_init(pruss_init);
+
+static void __exit pruss_exit(void)
+{
+	platform_driver_unregister(&pruss_driver);
+}
+module_exit(pruss_exit);
+
+MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
+MODULE_AUTHOR("Subhasish Ghosh");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
new file mode 100644
index 0000000..8ef25b3
--- /dev/null
+++ b/include/linux/mfd/pruss.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010, 2011 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 "pruss_core.h"
+
+#define PRUSS_NUM0			PRUCORE_0
+#define PRUSS_NUM1			PRUCORE_1
+
+#define PRUSS_PRU0_RAM_SZ		512
+#define PRUSS_PRU1_RAM_SZ		512
+#define PRUSS_PRU0_BASE_ADDRESS		0
+#define PRUSS_PRU1_BASE_ADDRESS		0x2000
+#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_HOSTMAP0_CHAN		(0x03020100)
+#define PRU_INTC_HOSTMAP1_CHAN		(0x07060504)
+#define PRU_INTC_HOSTMAP2_CHAN		(0x00000908)
+
+#define PRU_INTC_CHANMAP7_SYS_EVT31	(0x00000000)
+#define PRU_INTC_CHANMAP8_FULL		(0x02020100)
+#define PRU_INTC_CHANMAP9_FULL		(0x04040303)
+#define PRU_INTC_CHANMAP10_FULL		(0x06060505)
+#define PRU_INTC_CHANMAP11_FULL		(0x08080707)
+#define PRU_INTC_CHANMAP12_FULL		(0x00010909)
+#define PRU_INTC_CHANMAP8_HALF		(0x03020100)
+#define PRU_INTC_CHANMAP9_HALF		(0x07060504)
+#define PRU_INTC_CHANMAP10_HALF		(0x03020908)
+#define PRU_INTC_CHANMAP11_HALF		(0x07060504)
+#define PRU_INTC_CHANMAP12_HALF		(0x00010908)
+#define PRU_INTC_REGMAP_MASK		(0xFFFFFFFF)
+
+s32 pruss_enable(struct device *dev, u8 pruss_num);
+
+s32 pruss_load(struct device *dev, u8 pruss_num,
+	u32 *pruss_code, u32 code_size_in_words);
+
+s32 pruss_run(struct device *dev, u8 pruss_num);
+
+s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout);
+
+s32 pruss_disable(struct device *dev, u8 pruss_num);
+
+s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite);
+
+s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val);
+
+s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread);
+
+s32 pruss_readb_multi(struct device *dev, u32 offset,
+		u8 *pdatatoread, u16 bytestoread);
+
+s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread);
+
+s32 pruss_readl_multi(struct device *dev, u32 offset,
+		u32 *pdatatoread, u16 wordstoread);
+
+s32 pruss_writel(struct device *dev, u32 offset, u32 pdatatowrite);
+
+s32 pruss_writel_multi(struct device *dev, u32 offset,
+		u32 *pdatatowrite, u16 wordstowrite);
+
+s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val);
+
+s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value);
+
+s32 pruss_writew(struct device *dev, u32 offset, u16 datatowrite);
+
+s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val);
+
+s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread);
+
+#endif	/* End _PRUSS_H_ */
diff --git a/include/linux/mfd/pruss_core.h b/include/linux/mfd/pruss_core.h
new file mode 100644
index 0000000..48e2b99
--- /dev/null
+++ b/include/linux/mfd/pruss_core.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010, 2011 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_CORE_H_
+#define _PRUSS_CORE_H_
+
+#include <linux/types.h>
+
+#define PRUCORE_0		(0)
+#define PRUCORE_1		(1)
+
+#define PRUCORE_CONTROL_PCRESETVAL_MASK			(0xFFFF0000u)
+#define PRUCORE_CONTROL_PCRESETVAL_SHIFT		(0x00000010u)
+#define PRUCORE_CONTROL_PCRESETVAL_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_RUNSTATE_MASK			(0x00008000u)
+#define PRUCORE_CONTROL_RUNSTATE_SHIFT			(0x0000000Fu)
+#define PRUCORE_CONTROL_RUNSTATE_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_RUNSTATE_HALT			(0x00000000u)
+#define PRUCORE_CONTROL_RUNSTATE_RUN			(0x00000001u)
+#define PRUCORE_CONTROL_SINGLESTEP_MASK			(0x00000100u)
+#define PRUCORE_CONTROL_SINGLESTEP_SHIFT		(0x00000008u)
+#define PRUCORE_CONTROL_SINGLESTEP_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_SINGLESTEP_FREERUN		(0x00000000u)
+#define PRUCORE_CONTROL_SINGLESTEP_SINGLE		(0x00000001u)
+#define PRUCORE_CONTROL_COUNTENABLE_MASK		(0x00000008u)
+#define PRUCORE_CONTROL_COUNTENABLE_SHIFT		(0x00000003u)
+#define PRUCORE_CONTROL_COUNTENABLE_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_COUNTENABLE_DISABLE		(0x00000000u)
+#define PRUCORE_CONTROL_COUNTENABLE_ENABLE		(0x00000001u)
+#define PRUCORE_CONTROL_SLEEPING_MASK			(0x00000004u)
+#define PRUCORE_CONTROL_SLEEPING_SHIFT			(0x00000002u)
+#define PRUCORE_CONTROL_SLEEPING_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_SLEEPING_NOTASLEEP		(0x00000000u)
+#define PRUCORE_CONTROL_SLEEPING_ASLEEP			(0x00000001u)
+#define PRUCORE_CONTROL_ENABLE_MASK			(0x00000002u)
+#define PRUCORE_CONTROL_ENABLE_SHIFT			(0x00000001u)
+#define PRUCORE_CONTROL_ENABLE_RESETVAL			(0x00000000u)
+#define PRUCORE_CONTROL_ENABLE_DISABLE			(0x00000000u)
+#define PRUCORE_CONTROL_ENABLE_ENABLE			(0x00000001u)
+#define PRUCORE_CONTROL_SOFTRESET_MASK			(0x00000001u)
+#define PRUCORE_CONTROL_SOFTRESET_SHIFT			(0x00000000u)
+#define PRUCORE_CONTROL_SOFTRESET_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_SOFTRESET_RESET			(0x00000000u)
+#define PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET		(0x00000001u)
+#define PRUCORE_CONTROL_RESETVAL			(0x00000000u)
+
+struct prusscore_regs {
+	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];
+	u8  rsvd2[768];
+};
+
+struct pruss_intc_regs {
+	u32 revid;
+	u32 control;
+	u8  res1[8];
+	u32 glblen;
+	u8  res2[8];
+	u32 glblnstlvl;
+	u32 statidxset;
+	u32 statidxclr;
+	u32 enidxset;
+	u32 enidxclr;
+	u8  res3[4];
+	u32 hostintenidxset;
+	u32 hostintenidxclr;
+	u8  res4[68];
+	u32 glblpriidx;
+	u8  res5[380];
+	u32 statsetint[2];
+	u8  res6[120];
+	u32 statclrint[2];
+	u8  res7[120];
+	u32 enableset[2];
+	u8  res8[120];
+	u32 enableclr[2];
+	u8  res9[120];
+	u32 chanmap[16];
+	u8  res10[960];
+	u32 hostmap[2];
+	u8  res11[248];
+	u32 hostintpriidx[10];
+	u8  res12[984];
+	u32 polarity[2];
+	u8  res13[120];
+	u32 type[2];
+	u8  res14[888];
+	u32 hostintnstlvl[10];
+	u8  res15[984];
+	u32 hostinten;
+	u8  res16[6907];
+};
+
+struct pruss_map {
+	u8 dram0[512];
+	u8 res1[7680];
+	u8 dram1[512];
+	u8 res2[7680];
+	struct pruss_intc_regs intc;
+	struct prusscore_regs core[2];
+	u8 iram0[4096];
+	u8 res3[12288];
+	u8 iram1[4096];
+	u8 res4[12288];
+};
+#endif
-- 
1.7.2.3


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the pruss MFD driver and associated include files.
For details regarding the PRUSS please refer the folowing link:
http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem

The rational behind the MFD driver being the fact that multiple devices can
be implemented on the cores independently. This is determined by the nature
of the program which is loaded into the PRU's instruction memory.
A device may be de-initialized and another loaded or two different devices
can be run simultaneously on the two cores.
It's also possible, as in our case, to implement a single device on both
the PRU's resulting in improved load sharing.

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/mfd/Kconfig            |   10 +
 drivers/mfd/Makefile           |    1 +
 drivers/mfd/pruss.c            |  513 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/pruss.h      |  130 ++++++++++
 include/linux/mfd/pruss_core.h |  128 ++++++++++
 5 files changed, 782 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/pruss.c
 create mode 100644 include/linux/mfd/pruss.h
 create mode 100644 include/linux/mfd/pruss_core.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0284c53..41479e4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -92,6 +92,16 @@ config MFD_TI_SSP
 	  To compile this driver as a module, choose M here: the
 	  module will be called ti-ssp.
 
+config MFD_DA8XX_PRUSS
+	tristate "Texas Instruments DA8XX PRUSS support"
+	depends on ARCH_DAVINCI_DA850
+	select MFD_CORE
+	help
+	  This driver provides support API 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 c56b6c7..8015dea 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)	+= pruss.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
 
diff --git a/drivers/mfd/pruss.c b/drivers/mfd/pruss.c
new file mode 100644
index 0000000..6836d5a
--- /dev/null
+++ b/drivers/mfd/pruss.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2010, 2011 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/spinlock.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mfd/pruss.h>
+#include <linux/mfd/core.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+struct pruss_priv {
+	struct device *dev;
+	spinlock_t lock;
+	struct resource *res;
+	struct clk *clk;
+	void __iomem *ioaddr;
+};
+
+s32 pruss_disable(struct device *dev, u8 pruss_num)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 temp_reg;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	spin_lock(&pruss->lock);
+
+	/* pruss deinit */
+	iowrite32(0xFFFFFFFF, &pruss_mmap->intc.statclrint[pruss_num]);
+
+	/* Disable PRU */
+	h_pruss = &pruss_mmap->core[pruss_num];
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
+			((PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
+			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+			PRUCORE_CONTROL_COUNTENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+		~PRUCORE_CONTROL_ENABLE_MASK) |
+		((PRUCORE_CONTROL_ENABLE_DISABLE <<
+		PRUCORE_CONTROL_ENABLE_SHIFT) &
+		PRUCORE_CONTROL_ENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+
+	/* Reset PRU */
+	iowrite32(PRUCORE_CONTROL_RESETVAL,
+				&h_pruss->control);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_disable);
+
+s32 pruss_enable(struct device *dev, u8 pruss_num)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 i;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	h_pruss = &pruss_mmap->core[pruss_num];
+
+	/* Reset PRU  */
+	spin_lock(&pruss->lock);
+	iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);
+	spin_unlock(&pruss->lock);
+
+	/* Reset any garbage in the ram */
+	if (pruss_num == PRUCORE_0)
+		for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
+			iowrite32(0x0, &pruss_mmap->dram0[i]);
+	else if (pruss_num == PRUCORE_1)
+		for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
+			iowrite32(0x0, &pruss_mmap->dram1[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_enable);
+
+/* Load the specified PRU with code */
+s32 pruss_load(struct device *dev, u8 pruss_num,
+			u32 *pruss_code, u32 code_size_in_words)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 __iomem *pruss_iram;
+	u32 i;
+
+	if (pruss_num == PRUCORE_0)
+		pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
+	else if (pruss_num == PRUCORE_1)
+		pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
+	else
+		return -EINVAL;
+
+	pruss_enable(dev, pruss_num);
+
+	spin_lock(&pruss->lock);
+	/* Copy dMAX code to its instruction RAM  */
+	for (i = 0; i < code_size_in_words; i++)
+		iowrite32(pruss_code[i], (pruss_iram + i));
+
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_load);
+
+s32 pruss_run(struct device *dev, u8 pruss_num)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 temp_reg;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	h_pruss = &pruss_mmap->core[pruss_num];
+
+	/* Enable dMAX, let it execute the code we just copied */
+	spin_lock(&pruss->lock);
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
+			((PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
+			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
+			PRUCORE_CONTROL_COUNTENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+
+	temp_reg = ioread32(&h_pruss->control);
+	temp_reg = (temp_reg &
+			~PRUCORE_CONTROL_ENABLE_MASK) |
+			((PRUCORE_CONTROL_ENABLE_ENABLE <<
+			PRUCORE_CONTROL_ENABLE_SHIFT) &
+			PRUCORE_CONTROL_ENABLE_MASK);
+	iowrite32(temp_reg, &h_pruss->control);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_run);
+
+s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	struct prusscore_regs __iomem *h_pruss;
+	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
+	u32 temp_reg;
+	u32 cnt = timeout;
+
+	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
+		return -EINVAL;
+
+	h_pruss = &pruss_mmap->core[pruss_num];
+
+	while (cnt--) {
+		temp_reg = ioread32(&h_pruss->control);
+		if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
+				PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
+				PRUCORE_CONTROL_RUNSTATE_HALT)
+			break;
+	}
+	if (!cnt)
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_wait_for_halt);
+
+s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite8(pdatatowrite, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writeb);
+
+s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddress;
+	u32 preg_data;
+
+	paddress = pruss->ioaddr + offset;
+
+	spin_lock(&pruss->lock);
+	preg_data = ioread8(paddress);
+	preg_data &= ~mask;
+	preg_data |= val;
+	iowrite8(preg_data, paddress);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_rmwb);
+
+s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstoread;
+
+	paddresstoread = pruss->ioaddr + offset ;
+	*pdatatoread = ioread8(paddresstoread);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readb);
+
+s32 pruss_readb_multi(struct device *dev, u32 offset,
+		u8 *pdatatoread, u16 bytestoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	u8 __iomem *paddresstoread;
+	u16 i;
+
+	paddresstoread = pruss->ioaddr + offset;
+
+	for (i = 0; i < bytestoread; i++)
+		*pdatatoread++ = ioread8(paddresstoread++);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readb_multi);
+
+s32 pruss_writel(struct device *dev, u32 offset,
+		u32 pdatatowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite32(pdatatowrite, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writel);
+
+s32 pruss_writel_multi(struct device *dev, u32 offset,
+		u32 *pdatatowrite, u16 wordstowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	u32 __iomem *paddresstowrite;
+	u16 i;
+
+	paddresstowrite = pruss->ioaddr + offset;
+
+	for (i = 0; i < wordstowrite; i++)
+		iowrite32(*pdatatowrite++, paddresstowrite++);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writel_multi);
+
+s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddress;
+	u32 preg_data;
+
+	paddress = pruss->ioaddr + offset;
+
+	spin_lock(&pruss->lock);
+	preg_data = ioread32(paddress);
+	preg_data &= ~mask;
+	preg_data |= val;
+	iowrite32(preg_data, paddress);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_rmwl);
+
+s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstoread;
+
+	paddresstoread = pruss->ioaddr + offset;
+	*pdatatoread = ioread32(paddresstoread);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readl);
+
+s32 pruss_readl_multi(struct device *dev, u32 offset,
+		u32 *pdatatoread, u16 wordstoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	u32 __iomem *paddresstoread;
+	u16 i;
+
+	paddresstoread = pruss->ioaddr + offset;
+	for (i = 0; i < wordstoread; i++)
+		*pdatatoread++ = ioread32(paddresstoread++);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readl_multi);
+
+s32 pruss_writew(struct device *dev, u32 offset, u16 pdatatowrite)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite16(pdatatowrite, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_writew);
+
+s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddress;
+	u32 preg_data;
+
+	paddress = pruss->ioaddr + offset;
+
+	spin_lock(&pruss->lock);
+	preg_data = ioread16(paddress);
+	preg_data &= ~mask;
+	preg_data |= val;
+	iowrite16(preg_data, paddress);
+	spin_unlock(&pruss->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_rmww);
+
+s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstoread;
+
+	paddresstoread = pruss->ioaddr + offset;
+	*pdatatoread = ioread16(paddresstoread);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_readw);
+
+s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value)
+{
+	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
+	void __iomem *paddresstowrite;
+
+	paddresstowrite = pruss->ioaddr + offset;
+	iowrite32(value, paddresstowrite);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pruss_idx_writel);
+
+static int pruss_mfd_add_devices(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mfd_cell *cell = pdev->dev.platform_data;
+	s32 err, i, num_devices = 0;
+
+	for (i = 0; cell[i].name; i++) {
+		err = mfd_add_devices(dev, 0, &cell[i], 1, NULL, 0);
+		if (err) {
+			dev_err(dev, "cannot add mfd cell: %s\n",
+						cell[i].name);
+			continue;
+		}
+		num_devices++;
+		dev_info(dev, "mfd: added %s device\n", cell[i].name);
+	}
+
+	return num_devices;
+}
+
+static int __devinit pruss_probe(struct platform_device *pdev)
+{
+	struct pruss_priv *pruss_dev = NULL;
+	s32 err;
+
+	pruss_dev = kzalloc(sizeof(struct pruss_priv), 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;
+	}
+	spin_lock_init(&pruss_dev->lock);
+
+	clk_enable(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 pruss_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pruss_priv *pruss = dev_get_drvdata(dev);
+
+	mfd_remove_devices(dev);
+	pruss_disable(dev, PRUCORE_0);
+	pruss_disable(dev, PRUCORE_1);
+	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 pruss_driver = {
+	.probe	= pruss_probe,
+	.remove	= __devexit_p(pruss_remove),
+	.driver	= {
+		.name	= "pruss_mfd",
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init pruss_init(void)
+{
+	return platform_driver_register(&pruss_driver);
+}
+module_init(pruss_init);
+
+static void __exit pruss_exit(void)
+{
+	platform_driver_unregister(&pruss_driver);
+}
+module_exit(pruss_exit);
+
+MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
+MODULE_AUTHOR("Subhasish Ghosh");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
new file mode 100644
index 0000000..8ef25b3
--- /dev/null
+++ b/include/linux/mfd/pruss.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010, 2011 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 "pruss_core.h"
+
+#define PRUSS_NUM0			PRUCORE_0
+#define PRUSS_NUM1			PRUCORE_1
+
+#define PRUSS_PRU0_RAM_SZ		512
+#define PRUSS_PRU1_RAM_SZ		512
+#define PRUSS_PRU0_BASE_ADDRESS		0
+#define PRUSS_PRU1_BASE_ADDRESS		0x2000
+#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_HOSTMAP0_CHAN		(0x03020100)
+#define PRU_INTC_HOSTMAP1_CHAN		(0x07060504)
+#define PRU_INTC_HOSTMAP2_CHAN		(0x00000908)
+
+#define PRU_INTC_CHANMAP7_SYS_EVT31	(0x00000000)
+#define PRU_INTC_CHANMAP8_FULL		(0x02020100)
+#define PRU_INTC_CHANMAP9_FULL		(0x04040303)
+#define PRU_INTC_CHANMAP10_FULL		(0x06060505)
+#define PRU_INTC_CHANMAP11_FULL		(0x08080707)
+#define PRU_INTC_CHANMAP12_FULL		(0x00010909)
+#define PRU_INTC_CHANMAP8_HALF		(0x03020100)
+#define PRU_INTC_CHANMAP9_HALF		(0x07060504)
+#define PRU_INTC_CHANMAP10_HALF		(0x03020908)
+#define PRU_INTC_CHANMAP11_HALF		(0x07060504)
+#define PRU_INTC_CHANMAP12_HALF		(0x00010908)
+#define PRU_INTC_REGMAP_MASK		(0xFFFFFFFF)
+
+s32 pruss_enable(struct device *dev, u8 pruss_num);
+
+s32 pruss_load(struct device *dev, u8 pruss_num,
+	u32 *pruss_code, u32 code_size_in_words);
+
+s32 pruss_run(struct device *dev, u8 pruss_num);
+
+s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout);
+
+s32 pruss_disable(struct device *dev, u8 pruss_num);
+
+s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite);
+
+s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val);
+
+s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread);
+
+s32 pruss_readb_multi(struct device *dev, u32 offset,
+		u8 *pdatatoread, u16 bytestoread);
+
+s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread);
+
+s32 pruss_readl_multi(struct device *dev, u32 offset,
+		u32 *pdatatoread, u16 wordstoread);
+
+s32 pruss_writel(struct device *dev, u32 offset, u32 pdatatowrite);
+
+s32 pruss_writel_multi(struct device *dev, u32 offset,
+		u32 *pdatatowrite, u16 wordstowrite);
+
+s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val);
+
+s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value);
+
+s32 pruss_writew(struct device *dev, u32 offset, u16 datatowrite);
+
+s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val);
+
+s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread);
+
+#endif	/* End _PRUSS_H_ */
diff --git a/include/linux/mfd/pruss_core.h b/include/linux/mfd/pruss_core.h
new file mode 100644
index 0000000..48e2b99
--- /dev/null
+++ b/include/linux/mfd/pruss_core.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010, 2011 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_CORE_H_
+#define _PRUSS_CORE_H_
+
+#include <linux/types.h>
+
+#define PRUCORE_0		(0)
+#define PRUCORE_1		(1)
+
+#define PRUCORE_CONTROL_PCRESETVAL_MASK			(0xFFFF0000u)
+#define PRUCORE_CONTROL_PCRESETVAL_SHIFT		(0x00000010u)
+#define PRUCORE_CONTROL_PCRESETVAL_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_RUNSTATE_MASK			(0x00008000u)
+#define PRUCORE_CONTROL_RUNSTATE_SHIFT			(0x0000000Fu)
+#define PRUCORE_CONTROL_RUNSTATE_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_RUNSTATE_HALT			(0x00000000u)
+#define PRUCORE_CONTROL_RUNSTATE_RUN			(0x00000001u)
+#define PRUCORE_CONTROL_SINGLESTEP_MASK			(0x00000100u)
+#define PRUCORE_CONTROL_SINGLESTEP_SHIFT		(0x00000008u)
+#define PRUCORE_CONTROL_SINGLESTEP_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_SINGLESTEP_FREERUN		(0x00000000u)
+#define PRUCORE_CONTROL_SINGLESTEP_SINGLE		(0x00000001u)
+#define PRUCORE_CONTROL_COUNTENABLE_MASK		(0x00000008u)
+#define PRUCORE_CONTROL_COUNTENABLE_SHIFT		(0x00000003u)
+#define PRUCORE_CONTROL_COUNTENABLE_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_COUNTENABLE_DISABLE		(0x00000000u)
+#define PRUCORE_CONTROL_COUNTENABLE_ENABLE		(0x00000001u)
+#define PRUCORE_CONTROL_SLEEPING_MASK			(0x00000004u)
+#define PRUCORE_CONTROL_SLEEPING_SHIFT			(0x00000002u)
+#define PRUCORE_CONTROL_SLEEPING_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_SLEEPING_NOTASLEEP		(0x00000000u)
+#define PRUCORE_CONTROL_SLEEPING_ASLEEP			(0x00000001u)
+#define PRUCORE_CONTROL_ENABLE_MASK			(0x00000002u)
+#define PRUCORE_CONTROL_ENABLE_SHIFT			(0x00000001u)
+#define PRUCORE_CONTROL_ENABLE_RESETVAL			(0x00000000u)
+#define PRUCORE_CONTROL_ENABLE_DISABLE			(0x00000000u)
+#define PRUCORE_CONTROL_ENABLE_ENABLE			(0x00000001u)
+#define PRUCORE_CONTROL_SOFTRESET_MASK			(0x00000001u)
+#define PRUCORE_CONTROL_SOFTRESET_SHIFT			(0x00000000u)
+#define PRUCORE_CONTROL_SOFTRESET_RESETVAL		(0x00000000u)
+#define PRUCORE_CONTROL_SOFTRESET_RESET			(0x00000000u)
+#define PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET		(0x00000001u)
+#define PRUCORE_CONTROL_RESETVAL			(0x00000000u)
+
+struct prusscore_regs {
+	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];
+	u8  rsvd2[768];
+};
+
+struct pruss_intc_regs {
+	u32 revid;
+	u32 control;
+	u8  res1[8];
+	u32 glblen;
+	u8  res2[8];
+	u32 glblnstlvl;
+	u32 statidxset;
+	u32 statidxclr;
+	u32 enidxset;
+	u32 enidxclr;
+	u8  res3[4];
+	u32 hostintenidxset;
+	u32 hostintenidxclr;
+	u8  res4[68];
+	u32 glblpriidx;
+	u8  res5[380];
+	u32 statsetint[2];
+	u8  res6[120];
+	u32 statclrint[2];
+	u8  res7[120];
+	u32 enableset[2];
+	u8  res8[120];
+	u32 enableclr[2];
+	u8  res9[120];
+	u32 chanmap[16];
+	u8  res10[960];
+	u32 hostmap[2];
+	u8  res11[248];
+	u32 hostintpriidx[10];
+	u8  res12[984];
+	u32 polarity[2];
+	u8  res13[120];
+	u32 type[2];
+	u8  res14[888];
+	u32 hostintnstlvl[10];
+	u8  res15[984];
+	u32 hostinten;
+	u8  res16[6907];
+};
+
+struct pruss_map {
+	u8 dram0[512];
+	u8 res1[7680];
+	u8 dram1[512];
+	u8 res2[7680];
+	struct pruss_intc_regs intc;
+	struct prusscore_regs core[2];
+	u8 iram0[4096];
+	u8 res3[12288];
+	u8 iram1[4096];
+	u8 res4[12288];
+};
+#endif
-- 
1.7.2.3

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

* [PATCH v4 02/11] da850: add pruss clock.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 clock.

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

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 2d50885..a7cf2d0 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,
@@ -401,6 +407,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),
-- 
1.7.2.3


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

* [PATCH v4 02/11] da850: add pruss clock.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the PRUSS clock.

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

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 2d50885..a7cf2d0 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,
@@ -401,6 +407,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),
-- 
1.7.2.3

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

* [PATCH v4 03/11] da850: pruss platform specific additions.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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/devices-da8xx.c      |   63 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    4 ++
 2 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 625d4b6..f51c9ad 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.h>
 
 #include "clock.h"
 
@@ -510,6 +511,68 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 	}
 }
 
+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,
+	},
+};
+
+static struct platform_device da8xx_pruss_mfddev = {
+	.name		= "pruss_mfd",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(da8xx_pruss_resources),
+	.resource	= da8xx_pruss_resources,
+};
+
+int __init da8xx_register_pruss_mfd(struct mfd_cell *cell)
+{
+	da8xx_pruss_mfddev.dev.platform_data = cell;
+	return platform_device_register(&da8xx_pruss_mfddev);
+}
+
 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 09b8ddb..0c23035 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -16,6 +16,8 @@
 #include <linux/platform_device.h>
 #include <linux/davinci_emac.h>
 #include <linux/spi/spi.h>
+#include <linux/mfd/pruss.h>
+#include <linux/mfd/core.h>
 
 #include <mach/serial.h>
 #include <mach/edma.h>
@@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
 #define DA8XX_DDR2_CTL_BASE	0xb0000000
 #define DA8XX_ARM_RAM_BASE	0xffff0000
 #define DA8XX_SHARED_RAM_BASE	0x80000000
+#define DA8XX_PRUSS_MEM_BASE	0x01C30000
 
 void __init da830_init(void);
 void __init da850_init(void);
@@ -85,6 +88,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_mfd(struct mfd_cell *);
 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] 166+ messages in thread

* [PATCH v4 03/11] da850: pruss platform specific additions.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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/devices-da8xx.c      |   63 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    4 ++
 2 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 625d4b6..f51c9ad 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.h>
 
 #include "clock.h"
 
@@ -510,6 +511,68 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 	}
 }
 
+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,
+	},
+};
+
+static struct platform_device da8xx_pruss_mfddev = {
+	.name		= "pruss_mfd",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(da8xx_pruss_resources),
+	.resource	= da8xx_pruss_resources,
+};
+
+int __init da8xx_register_pruss_mfd(struct mfd_cell *cell)
+{
+	da8xx_pruss_mfddev.dev.platform_data = cell;
+	return platform_device_register(&da8xx_pruss_mfddev);
+}
+
 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 09b8ddb..0c23035 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -16,6 +16,8 @@
 #include <linux/platform_device.h>
 #include <linux/davinci_emac.h>
 #include <linux/spi/spi.h>
+#include <linux/mfd/pruss.h>
+#include <linux/mfd/core.h>
 
 #include <mach/serial.h>
 #include <mach/edma.h>
@@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
 #define DA8XX_DDR2_CTL_BASE	0xb0000000
 #define DA8XX_ARM_RAM_BASE	0xffff0000
 #define DA8XX_SHARED_RAM_BASE	0x80000000
+#define DA8XX_PRUSS_MEM_BASE	0x01C30000
 
 void __init da830_init(void);
 void __init da850_init(void);
@@ -85,6 +88,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_mfd(struct mfd_cell *);
 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] 166+ messages in thread

* [PATCH v4 04/11] da850: pruss board specific additions.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index a7b41bf..0b6b948 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1117,6 +1117,15 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static struct mfd_cell cell[] = {
+	{.name = NULL,},
+};
+
+static int __init da8xx_evm_setup_pruss(void)
+{
+	return da8xx_register_pruss_mfd(cell);
+}
+
 static __init void da850_evm_init(void)
 {
 	int ret;
@@ -1191,6 +1200,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] 166+ messages in thread

* [PATCH v4 04/11] da850: pruss board specific additions.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index a7b41bf..0b6b948 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1117,6 +1117,15 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static struct mfd_cell cell[] = {
+	{.name = NULL,},
+};
+
+static int __init da8xx_evm_setup_pruss(void)
+{
+	return da8xx_register_pruss_mfd(cell);
+}
+
 static __init void da850_evm_init(void)
 {
 	int ret;
@@ -1191,6 +1200,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] 166+ messages in thread

* [PATCH v4 05/11] mfd: pruss SUART private data.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
index 8ef25b3..c5e2af2 100644
--- a/include/linux/mfd/pruss.h
+++ b/include/linux/mfd/pruss.h
@@ -87,6 +87,11 @@
 #define PRU_INTC_CHANMAP12_HALF		(0x00010908)
 #define PRU_INTC_REGMAP_MASK		(0xFFFFFFFF)
 
+struct da850_evm_pruss_suart_data {
+	u32 version;
+	int (*setup)(void);
+};
+
 s32 pruss_enable(struct device *dev, u8 pruss_num);
 
 s32 pruss_load(struct device *dev, u8 pruss_num,
-- 
1.7.2.3


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

* [PATCH v4 05/11] mfd: pruss SUART private data.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
index 8ef25b3..c5e2af2 100644
--- a/include/linux/mfd/pruss.h
+++ b/include/linux/mfd/pruss.h
@@ -87,6 +87,11 @@
 #define PRU_INTC_CHANMAP12_HALF		(0x00010908)
 #define PRU_INTC_REGMAP_MASK		(0xFFFFFFFF)
 
+struct da850_evm_pruss_suart_data {
+	u32 version;
+	int (*setup)(void);
+};
+
 s32 pruss_enable(struct device *dev, u8 pruss_num);
 
 s32 pruss_load(struct device *dev, u8 pruss_num,
-- 
1.7.2.3

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

* [PATCH v4 06/11] da850: pruss SUART board specific additions.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 |   46 ++++++++++++++++++++++++++++++-
 1 files changed, 45 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 0b6b948..e7fdf31 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1117,8 +1117,52 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static 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_pruss_suart_setup(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 struct da850_evm_pruss_suart_data suart_data = {
+	.version	= 1,
+	.setup		= da850_evm_pruss_suart_setup,
+};
+
+static struct resource da850_evm_pruss_suart_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 mfd_cell cell[] = {
-	{.name = NULL,},
+	{
+		.id		= 0,
+		.name		= "da8xx_pruss_uart",
+		.platform_data	= &suart_data,
+		.data_size	= sizeof(suart_data),
+		.num_resources  = ARRAY_SIZE(da850_evm_pruss_suart_resource),
+		.resources	= da850_evm_pruss_suart_resource,
+	},
+	{
+		.name		= NULL,
+	},
 };
 
 static int __init da8xx_evm_setup_pruss(void)
-- 
1.7.2.3


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

* [PATCH v4 06/11] da850: pruss SUART board specific additions.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 |   46 ++++++++++++++++++++++++++++++-
 1 files changed, 45 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 0b6b948..e7fdf31 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1117,8 +1117,52 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static 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_pruss_suart_setup(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 struct da850_evm_pruss_suart_data suart_data = {
+	.version	= 1,
+	.setup		= da850_evm_pruss_suart_setup,
+};
+
+static struct resource da850_evm_pruss_suart_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 mfd_cell cell[] = {
-	{.name = NULL,},
+	{
+		.id		= 0,
+		.name		= "da8xx_pruss_uart",
+		.platform_data	= &suart_data,
+		.data_size	= sizeof(suart_data),
+		.num_resources  = ARRAY_SIZE(da850_evm_pruss_suart_resource),
+		.resources	= da850_evm_pruss_suart_resource,
+	},
+	{
+		.name		= NULL,
+	},
 };
 
 static int __init da8xx_evm_setup_pruss(void)
-- 
1.7.2.3

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

* [PATCH v4 07/11] da850: pruss SUART platform specific additions.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index f51c9ad..8f41ae4 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -567,9 +567,27 @@ static struct platform_device da8xx_pruss_mfddev = {
 	.resource	= da8xx_pruss_resources,
 };
 
+#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
+static int da8xx_mcasp_clk_add_alias(void)
+{
+	return clk_add_alias(NULL, "da8xx_pruss_uart.0",
+			NULL, &da850_mcasp_device.dev);
+}
+#else
+static int da8xx_mcasp_clk_add_alias(void)
+{
+	return 0;
+}
+#endif
 int __init da8xx_register_pruss_mfd(struct mfd_cell *cell)
 {
+	int ret;
+
 	da8xx_pruss_mfddev.dev.platform_data = cell;
+
+	ret = da8xx_mcasp_clk_add_alias();
+	if (ret < 0)
+		return ret;
 	return platform_device_register(&da8xx_pruss_mfddev);
 }
 
-- 
1.7.2.3


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

* [PATCH v4 07/11] da850: pruss SUART platform specific additions.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index f51c9ad..8f41ae4 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -567,9 +567,27 @@ static struct platform_device da8xx_pruss_mfddev = {
 	.resource	= da8xx_pruss_resources,
 };
 
+#ifdef CONFIG_SERIAL_PRUSS_SUART_MODULE
+static int da8xx_mcasp_clk_add_alias(void)
+{
+	return clk_add_alias(NULL, "da8xx_pruss_uart.0",
+			NULL, &da850_mcasp_device.dev);
+}
+#else
+static int da8xx_mcasp_clk_add_alias(void)
+{
+	return 0;
+}
+#endif
 int __init da8xx_register_pruss_mfd(struct mfd_cell *cell)
 {
+	int ret;
+
 	da8xx_pruss_mfddev.dev.platform_data = cell;
+
+	ret = da8xx_mcasp_clk_add_alias();
+	if (ret < 0)
+		return ret;
 	return platform_device_register(&da8xx_pruss_mfddev);
 }
 
-- 
1.7.2.3

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 UTC (permalink / raw)
  To: davinci-linux-open-source
  Cc: linux-arm-kernel, m-watkins, nsekhar, sachi, Subhasish Ghosh,
	Greg Kroah-Hartman, Andrew Morton, Randy Dunlap, open list

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

This patch depends on:
davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
            https://patchwork.kernel.org/patch/615681/
davinci: changed SRAM allocator to shared ram.
            https://patchwork.kernel.org/patch/549351/

Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
---
 drivers/tty/serial/Kconfig             |   18 +
 drivers/tty/serial/Makefile            |    6 +
 drivers/tty/serial/pruss_suart.c       | 1061 ++++++++++++++++++++
 drivers/tty/serial/pruss_suart.h       | 1038 +++++++++++++++++++
 drivers/tty/serial/pruss_suart_api.c   | 1710 ++++++++++++++++++++++++++++++++
 drivers/tty/serial/pruss_suart_utils.c |  393 ++++++++
 include/linux/serial_core.h            |    2 +
 7 files changed, 4228 insertions(+), 0 deletions(-)
 create mode 100644 drivers/tty/serial/pruss_suart.c
 create mode 100644 drivers/tty/serial/pruss_suart.h
 create mode 100644 drivers/tty/serial/pruss_suart_api.c
 create mode 100644 drivers/tty/serial/pruss_suart_utils.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2b83346..6c26ebf 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1596,4 +1596,22 @@ 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.
+
+config SERIAL_PRUSS_SUART
+	depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
+	select SERIAL_CORE
+	tristate "PRUSS based SoftUART emulation on DA8XX"
+	---help---
+	This driver emulates up to eight different UARTs on the PRUSS.
+	You may modify the NR_SUARTS macro in the driver to emulate
+	less number of UARTS as per your requirement.
+	If not sure, mark No
+
+config PRUSS_SUART_MCASP
+	depends on ARCH_DAVINCI_DA830 && SERIAL_PRUSS_SUART
+	default "0"
+	int "McASP number"
+	---help---
+	Enter the McASP number to use with SUART (0, 1 or 2).
+	You will need to recompile the kernel if this is changed.
 endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 8ea92e9..e1eaaf3 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,3 +92,9 @@ 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
+
+pruss_uart-objs :=	pruss_suart.o \
+			pruss_suart_api.o \
+			pruss_suart_utils.o
+
+obj-$(CONFIG_SERIAL_PRUSS_SUART) += pruss_uart.o
diff --git a/drivers/tty/serial/pruss_suart.c b/drivers/tty/serial/pruss_suart.c
new file mode 100644
index 0000000..37c3c21
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart.c
@@ -0,0 +1,1061 @@
+/*
+ * 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) 2010, 2011 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 <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <mach/sram.h>
+#include "pruss_suart.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
+
+/* 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;
+	unsigned long tx_empty[NR_SUART];
+	struct clk *clk_mcasp;
+	struct suart_fifo suart_fifo_addr[NR_SUART];
+	struct suart_handle suart_hdl[NR_SUART];
+	struct pruss_suart_iomap suart_iomap;
+	struct tasklet_struct tx_task[NR_SUART];
+	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;
+	unsigned long flags = 0;
+	struct uart_port *port = &soft_uart->port[uart_no];
+	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 */
+	spin_lock_irqsave(&port->lock, flags);
+	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]);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+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 (uart_circ_empty(xmit) ||
+			uart_tx_stopped(&soft_uart->port[uart_no])) {
+		pruss_suart_stop_tx(&soft_uart->port[uart_no]);
+		set_bit(0, &soft_uart->tx_empty[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 (pru_softuart_write(dev,
+		&soft_uart->suart_hdl[uart_no],
+			(u32 *)&soft_uart->suart_fifo_addr
+				[uart_no].fifo_phys_addr_tx, count) != 0) {
+		dev_err(dev, "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 suart_tx_task(unsigned long data)
+{
+	struct uart_port *port = (struct uart_port *)data;
+	struct omapl_pru_suart *soft_uart =
+		container_of(port, struct omapl_pru_suart, port[port->line]);
+
+	omapl_pru_tx_chars(soft_uart, port->line);
+}
+
+static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 uart_no)
+{
+	struct tty_struct *tty = NULL;
+	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]);
+
+	pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
+			suart_data, data_len + 1, &data_len_read);
+
+	tty = tty_port_tty_get(&soft_uart->port[uart_no].state->port);
+
+	if (!tty)
+		return;
+
+	/* 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 {
+		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;
+		}
+		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]);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+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(&port->lock, flags);
+
+	do {
+		ret = pru_softuart_get_isrstatus(dev, uart_num, &txrx_flag);
+		if (ret != 0) {
+			dev_err(dev, "suart%d: failed to get interrupt, ret:"
+				" 0x%X txrx_flag 0x%X\n",
+				port->line, ret, txrx_flag);
+				spin_unlock_irqrestore(&port->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]);
+			tasklet_schedule(&soft_uart->tx_task[port->line]);
+		}
+	} while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
+
+	spin_unlock_irqrestore(&port->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;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+	/* 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);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void pruss_suart_enable_ms(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;
+	dev_err(dev, "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;
+	unsigned long flags = 0;
+
+	/* unmask the tx interrupts */
+	spin_lock_irqsave(&port->lock, flags);
+	suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
+			   PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (test_and_clear_bit(0, &soft_uart->tx_empty[port->line]))
+		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)
+{
+	struct omapl_pru_suart *soft_uart =
+	    container_of(port, struct omapl_pru_suart, port[port->line]);
+	struct device *dev = soft_uart->dev;
+	dev_dbg(dev, "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 &= ~(CRTSCTS | CMSPAR | CSTOPB
+				      | PARENB | PARODD | CMSPAR);
+	}
+
+	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 (pru_softuart_setdatabits
+		(dev, &soft_uart->suart_hdl[port->line], cval, cval) != 0)
+		dev_err(dev, "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 (pru_softuart_setbaud(dev, &soft_uart->suart_hdl[port->line],
+				 SUART_DEFAULT_BAUD / baud,
+				 SUART_DEFAULT_BAUD / baud) != 0)
+		dev_err(dev, "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);
+	}
+/*
+ * Characters 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);
+	}
+	/*
+	* update the per port timeout
+	*/
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	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;
+	unsigned long flags = 0;
+	s32 retval;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	spin_lock_irqsave(&port->lock, flags);
+	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);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	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
+	 */
+	spin_lock_irqsave(&port->lock, flags);
+	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);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	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;
+	unsigned long flags = 0;
+
+	/*
+	 * Disable interrupts from this port
+	 */
+	/* Disable BI and FE intr */
+	spin_lock_irqsave(&port->lock, flags);
+	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);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* 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;
+	struct suart_config pru_suart_config;
+	s16 timeout = 0;
+	u32 err = 0;
+
+	if (soft_uart == NULL) {
+		dev_err(&pdev->dev, "soft_uart ptr failed\n");
+		return -ENODEV;
+	}
+	err = pru_softuart_open(&soft_uart->suart_hdl[port->line]);
+	if (err != 0) {
+		dev_err(&pdev->dev, "failed to open suart: %d\n", err);
+		err = -ENODEV;
+		goto exit;
+	}
+	set_bit(0, &soft_uart->tx_empty[port->line]);
+
+	/* set fifo /timeout */
+	if (SUART_FIFO_TIMEOUT_MIN > suart_timeout) {
+		dev_err(&pdev->dev, "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) {
+		dev_err(&pdev->dev, "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_softuart_setconfig(dev, &soft_uart->suart_hdl[port->line],
+			&pru_suart_config) != 0) {
+		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 struct pruss_suart_initparams init_params = {
+	.tx_baud_value	= SUART_DEFAULT_BAUD,
+	.rx_baud_value	= SUART_DEFAULT_BAUD,
+	.oversampling	= SUART_DEFAULT_OVRSMPL,
+};
+
+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;
+	struct resource *res;
+	struct clk *clk_pruss = NULL;
+	const struct firmware *fw;
+	s32 err, i;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not found\n");
+		return -EINVAL;
+	}
+	(pdata->setup)();
+
+	soft_uart = kzalloc(sizeof(struct omapl_pru_suart), GFP_KERNEL);
+	if (!soft_uart)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get resource");
+		return -ENOMEM;
+	}
+
+	if (!request_mem_region(res->start,
+			resource_size(res),
+			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(res->start,
+					resource_size(res));
+	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;
+
+	clk_pruss = clk_get(NULL, "pruss");
+	if (IS_ERR(clk_pruss)) {
+		dev_err(&pdev->dev, "no clock available: pruss\n");
+		err = -ENODEV;
+		goto probe_exit_iounmap;
+	}
+	soft_uart->clk_freq_pru = clk_get_rate(clk_pruss);
+	clk_put(clk_pruss);
+
+	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(&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", fw->size);
+
+	/* download firmware into pru  & init */
+	err = pru_softuart_init(dev, &init_params, fw->data, fw->size,
+					soft_uart->clk_freq_pru / 1000000,
+					&soft_uart->suart_iomap);
+	if (err) {
+		dev_err(&pdev->dev, "pruss init error\n");
+		err = -ENODEV;
+		goto probe_release_fw;
+	}
+	release_firmware(fw);
+
+	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 =
+			soft_uart->suart_iomap.mcasp_io_addr;
+		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;
+		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;
+		tasklet_init(&soft_uart->tx_task[i], suart_tx_task,
+				(unsigned long)&soft_uart->port[i]);
+		uart_add_one_port(&pruss_suart_reg, &soft_uart->port[i]);
+	}
+
+	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(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(res->start,
+		resource_size(res));
+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;
+	struct resource *res;
+	int i;
+
+	pdata = dev->platform_data;
+	if (!pdata)
+		dev_err(&pdev->dev, "platform data not found\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get resource");
+		return -ENOMEM;
+	}
+
+	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);
+	clk_put(soft_uart->clk_mcasp);
+	pru_mcasp_deinit();
+	clk_disable(soft_uart->clk_mcasp);
+	iounmap(soft_uart->suart_iomap.mcasp_io_addr);
+	if (pdata) {
+		release_mem_region(res->start,
+			resource_size(res));
+	}
+	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;
+
+	pr_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);
+	pr_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/pruss_suart.h b/drivers/tty/serial/pruss_suart.h
new file mode 100644
index 0000000..f3a2a9d
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart.h
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (C) 2010, 2011 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/io.h>
+#include <linux/mfd/pruss.h>
+
+#define SINGLE_PRU			0
+#define BOTH_PRU			1
+#define PRU_ACTIVE			BOTH_PRU
+#define PRU_CLK_228			228
+#define PRU_CLK_186			186
+
+#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)
+
+#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)
+
+#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 | \
+					PRU_SUART_HALF_RX)
+#define PRU_SUART3_CONFIG_RX_SER	(PRU_SUART_SERIALIZER_13)
+#define PRU_SUART3_CONFIG_TX_SER	(PRU_SUART_SERIALIZER_14)
+
+#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)
+
+#define SUART_NUM_OF_CHANNELS_PER_SUART		2
+#define SUART_NUM_OF_BYTES_PER_CHANNEL		16
+
+#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_TX_OVRSMPL			0
+#define SUART_DEFAULT_OVRSMPL			SUART_8X_OVRSMPL
+
+#define SUART_DEFAULT_OVRSMPL_OFFSET		26
+#define SUART_CHN_OFFSET			31
+#define SERIALIZER_OFFSET			8
+
+#if (SUART_DEFAULT_OVRSMPL == SUART_16X_OVRSMPL)
+#define SUART_DEFAULT_BAUD			57600
+#else
+#define SUART_DEFAULT_BAUD			115200
+#endif
+
+#define PRU_MODE_INVALID			0x0
+#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)
+
+/* MCASP */
+
+#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)
+
+/* SUART REGS */
+
+/* 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 STATUS Register*/
+#define PRU_SUART_CH_STATUS_EN_BIT_MASK		0x8000
+
+/* 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)
+
+/* 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)
+
+/*
+ *  This enum is used to specify the direction of the channel in UART
+ */
+enum SUART_CHN_DIR {
+	SUART_CHN_TX = 1,
+	SUART_CHN_RX = 2
+};
+
+/*
+ *  This enum is used to specify the state of the channel in UART. It
+ *  is either enabled or disabled.
+ */
+enum SUART_CHN_STATE {
+	SUART_CHN_DISABLED = 0,
+	SUART_CHN_ENABLED = 1
+};
+
+enum SUART_EN_BITSPERCHAR {
+	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
+};
+
+enum SUART_EN_UARTNUM {
+	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
+};
+
+enum SUART_EN_UARTTYPE {
+	ePRU_SUART_HALF_TX = 1,
+	ePRU_SUART_HALF_RX,
+	ePRU_SUART_FULL_TX_RX,
+	ePRU_SUART_HALF_TX_DISABLED = 4,
+	ePRU_SUART_HALF_RX_DISABLED = 8
+};
+
+enum SUART_EN_TXCHANNEL {
+	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
+};
+
+enum SUART_EN_RXCHANNEL {
+	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
+};
+
+enum SUART_EN_UART_STATUS {
+	ePRU_SUART_UART_FREE = 0,
+	ePRU_SUART_UART_IN_USE
+};
+
+struct pru_suart_cnh_cntrl_config1 {
+	u32 mode:2;
+	u32 service_req:1;
+	u32 asp_id:2;
+	u32 reserved1:3;
+	u32 serializer_num:4;
+	u32 reserved2:4;
+	u32 presacler:10;
+	u32 over_sampling:2;
+	u32 framing_mask:1;
+	u32 break_mask:1;
+	u32 timeout_mask:1;
+	u32 reserved3:1;
+};
+
+struct pru_suart_chn_config2_status {
+	u32 bits_per_char:4;
+	u32 reserved1:4;
+	u32 data_len:4;
+	u32 reserved2:4;
+	u32 txrx_ready:1;
+	u32 txrx_complete:1;
+	u32 txrx_error:1;
+	u32 txrx_underrun:1;
+	u32 framing_error:1;
+	u32 break_error:1;
+	u32 timeout_error:1;
+	u32 reserved3:8;
+	u32 chn_state:1;
+};
+
+struct pru_suart_regs_ovly {
+	struct pru_suart_cnh_cntrl_config1 ch_ctrl_config1;
+	struct pru_suart_chn_config2_status ch_config2_txrx_status;
+	u32 ch_txrx_data;
+	u32 reserved1;
+};
+
+struct pru_suart_tx_cntx_priv {
+	u32 asp_xsrctl_base;
+	u32 asp_xbuf_base;
+	u16 buff_addr;
+	u8 buff_size;
+	u8 bits_loaded;
+};
+
+struct pru_suart_rx_cntx_priv {
+	u32 asp_rbuf_base;
+	u32 asp_rsrctl_base;
+	u32 reserved1;
+	u32 reserved2;
+	u32 reserved3;
+	u32 reserved4;
+};
+
+struct suart_config {
+	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;
+};
+
+struct suart_handle {
+	u16 uart_num;
+	u16 uart_type;
+	u16 uart_tx_channel;
+	u16 uart_rx_channel;
+	u16 uart_status;
+};
+
+struct pruss_suart_iomap {
+	void __iomem *mcasp_io_addr;
+	void *p_fifo_buff_phys_base;
+	void *p_fifo_buff_virt_base;
+};
+
+struct pruss_suart_initparams {
+	u32 tx_baud_value;
+	u32 rx_baud_value;
+	u32 oversampling;
+};
+
+/* MCASP */
+struct omapl_mcasp_regs_ovly {
+	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 ditcsra[6];
+	u32 ditcsrb[6];
+	u32 ditudra[6];
+	u32 ditudrb[6];
+	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 xbuf[16];
+	u32 rsvd7[16];
+	u32 rbuf[16];
+};
+
+/*
+ *  SUART Config regs
+ */
+struct suart_struct_pru_regs {
+	u16 chn_ctrl;
+	u16 chn_config1;
+	u16 chn_config2;
+	u16 chn_txrx_status;
+	u32 chn_txrx_data;
+};
+
+extern s32 pru_softuart_init(struct device *dev,
+			struct pruss_suart_initparams *,
+			const u8 *pru_suart_emu_code, u32 fw_size,
+			u32 clk_rate_pruss,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern s32 pru_softuart_open(struct suart_handle *h_suart);
+
+extern s32 pru_softuart_close(struct suart_handle *h_uart);
+
+extern s32 pru_softuart_setbaud(struct device *dev,
+			struct suart_handle *h_uart,
+			u16 tx_clk_divisor, u16 rx_clk_divisor);
+
+extern s32 pru_softuart_setdatabits(struct device *dev,
+			struct suart_handle *h_uart,
+			u16 tx_data_bits, u16 rx_data_bits);
+
+extern s32 pru_softuart_setconfig(struct device *dev,
+			struct suart_handle *h_uart,
+			struct suart_config *config_uart);
+
+extern s32 pru_softuart_getconfig(struct device *dev,
+			struct suart_handle *h_uart,
+			struct suart_config *config_uart);
+
+extern s32 pru_softuart_pending_tx_request(struct device *dev);
+
+extern s32 pru_softuart_write(struct device *dev,
+			struct suart_handle *h_uart,
+			u32 *pt_tx_data_buf, u16 data_len);
+
+extern s32 pru_softuart_read(struct device *dev,
+			struct suart_handle *h_uart,
+			u32 *pt_data_buf, u16 data_len);
+
+extern s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
+						u32 txrxmode,
+						u32 intrmask);
+
+extern s32 pru_softuart_clr_tx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_tx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_clr_rx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_rx_status(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num,
+			u16 *txrx_flag);
+
+extern s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num,
+							u32 txrxmode);
+
+extern s32 suart_intr_getmask(struct device *dev, u16 uart_num,
+						u32 txrxmode,
+						u32 intrmask);
+
+extern s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+			u32 txrxmode, u32 intrmask);
+
+extern s32 pru_softuart_get_tx_data_len(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 pru_softuart_get_rx_data_len(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 suart_arm_to_pru_intr(struct device *dev, u16 uart_num);
+
+extern void pru_mcasp_deinit(void);
+
+extern s32 pru_softuart_read_data(struct device *dev,
+			struct suart_handle *h_uart,
+			u8 *p_data_buffer, s32 max_len,
+			u32 *pdata_read);
+
+extern s32 pru_softuart_stop_receive(struct device *dev,
+				struct suart_handle *h_uart);
+
+extern s32 suart_pru_to_host_intr_enable(struct device *dev,
+					u16 uart_num,
+					u32 txrxmode, s32 flag);
+
+extern void pru_set_fifo_timeout(struct device *dev, s16 timeout);
+
+extern void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern void suart_mcasp_reset(struct pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_baud_set(u32 tx_baud_value,
+			u32 rx_baud_value, u32 oversampling,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern short suart_asp_serializer_deactivate(u16 sr_num,
+			struct pruss_suart_iomap *pruss_ioaddr);
+
+extern void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+			struct pruss_suart_iomap *pruss_ioaddr);
+#endif
diff --git a/drivers/tty/serial/pruss_suart_api.c b/drivers/tty/serial/pruss_suart_api.c
new file mode 100644
index 0000000..15178f5
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart_api.c
@@ -0,0 +1,1710 @@
+/*
+ * Copyright (C) 2010, 2011 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.h>
+#include "pruss_suart.h"
+
+static u8 uart_statu_table[8];
+static struct 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};
+
+static  s32 pru_softuart_clr_rx_fifo(struct device *dev,
+				struct suart_handle *h_uart);
+static s32 arm_to_pru_intr_init(struct device *dev);
+
+#if (PRU_ACTIVE == BOTH_PRU)
+static void pru_set_ram_data(struct device *dev,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 datatowrite;
+	u32 i;
+	struct pru_suart_regs_ovly *pru_suart_regs = NULL;
+	u32 __iomem *p_sr_ctl_addr = (u32 __iomem *)(pruss_ioaddr->
+						mcasp_io_addr + 0x180);
+	struct pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	struct 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_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						0x3, SUART_CHN_RX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_rx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_config2_txrx_status,
+								0xF, 8);
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+					PRU_SUART_HALF_RX_DISABLED) {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_RX_MODE, p_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_rmwl(dev, (u32) &pru_suart_regs->ch_txrx_data,
+				0xFFFF, RX_DEFAULT_DATA_DUMP_ADDR);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 0);
+		/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (struct pru_suart_rx_cntx_priv *)
+				(PRU0_DATARAM_OFFSET + (0x090 + (i * 0x020)));
+		datatowrite = (MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
+							datatowrite);
+		datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+							datatowrite);
+	}
+
+	/* PRU1 RAM BASE ADDR */
+	pru_suart_regs = (struct 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_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						0x3, SUART_CHN_TX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_tx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev,
+			(u32) &pru_suart_regs->ch_config2_txrx_status, 0xF, 8);
+
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED) {
+			pruss_rmwl(dev, (u32)
+				&pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_TX_MODE,
+				p_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 1);
+
+		/* SUART1 TX context base addr */
+		pru_suart_tx_priv = (struct pru_suart_tx_cntx_priv *)
+			(PRU1_DATARAM_OFFSET + (0x0B0 + (i * 0x02C)));
+		datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
+							datatowrite);
+		datatowrite = (MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+							datatowrite);
+		/* SUART1 TX formatted data base addr */
+		datatowrite = (0x0090 + (i * 0x002C));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+							datatowrite);
+	}
+}
+#else
+static void pru_set_ram_data(struct device *dev,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+
+	struct pru_suart_regs_ovly *pru_suart_regs =
+		(struct pru_suart_regs_ovly *)pruss_ioaddr->pru_io_addr;
+	u32 i;
+	u32 *p_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
+	struct pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
+	struct pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
+
+	/* Channel 0 context information is Tx */
+	for (i = 0; i < 4; i++, pru_suart_regs++) {
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						0x3, SUART_CHN_TX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_tx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_config2_txrx_status,
+								0xF, 8);
+		if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
+						PRU_SUART_HALF_TX_DISABLED){
+			pruss_rmwl(dev, (u32)
+				&pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_TX_MODE,
+						p_sr_ctl_addr + uart_tx[i]);
+		}
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 1);
+
+		/* SUART1 TX context base addr */
+		pru_suart_tx_priv = (struct 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)));
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
+				(MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2)));
+		/* SUART1 TX formatted data base addr */
+		pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
+					(0x0090 + (i * 0x050)));
+
+		/* Channel 1 is Rx context information */
+		pru_suart_regs++;
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+							0x3, SUART_CHN_RX);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+						(0xF << SERIALIZER_OFFSET),
+				((0xF & uart_rx[i]) << SERIALIZER_OFFSET));
+		pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
+				(0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
+				(SUART_DEFAULT_OVRSMPL <<
+				SUART_DEFAULT_OVRSMPL_OFFSET));
+		pruss_rmwl(dev,
+			(u32) &pru_suart_regs->ch_config2_txrx_status, 0xF, 8);
+
+		if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
+						PRU_SUART_HALF_RX_DISABLED) {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_DISABLED << SUART_CHN_OFFSET));
+		} else {
+			pruss_rmwl(dev,
+				(u32) &pru_suart_regs->ch_config2_txrx_status,
+				(0x1 << SUART_CHN_OFFSET),
+				(SUART_CHN_ENABLED << SUART_CHN_OFFSET));
+			iowrite32(MCASP_SRCTL_RX_MODE,
+					p_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_rmwl(dev, (u32) &pru_suart_regs->ch_txrx_data,
+				0xFFFF, RX_DEFAULT_DATA_DUMP_ADDR);
+		pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 0);
+		/* SUART1 RX context base addr */
+		pru_suart_rx_priv = (struct 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)));
+		pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
+				(MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2)));
+	}
+}
+#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);
+}
+
+static void pru_set_delay_count(struct device *dev, u32 pru_freq)
+{
+	u32 delay_cnt;
+
+	if (pru_freq == PRU_CLK_228)
+		delay_cnt = 5;
+	else if (pru_freq == PRU_CLK_186)
+		delay_cnt = 5;
+	else
+		delay_cnt = 3;
+
+	/* PRU 0 */
+	pruss_writeb(dev, PRU_SUART_PRU0_DELAY_OFFSET,
+		(u8) delay_cnt);
+
+	/* PRU 1 */
+	pruss_writeb(dev, PRU_SUART_PRU1_DELAY_OFFSET,
+		(u8) delay_cnt);
+}
+
+static s32 suart_set_pru_id(struct device *dev, u32 pru_no)
+{
+	u32 offset;
+	u8 reg_val = 0;
+
+	if (PRUSS_NUM0 == pru_no)
+		offset = PRU_SUART_PRU0_ID_ADDR;
+	else if (PRUSS_NUM1 == pru_no)
+		offset = PRU_SUART_PRU1_ID_ADDR;
+	else
+		return -EINVAL;
+
+	reg_val = pru_no;
+	pruss_writeb(dev, offset, reg_val);
+
+	return 0;
+}
+
+/*
+ * suart Initialization routine
+ */
+s32 pru_softuart_init(struct device *dev,
+			struct pruss_suart_initparams *init_params,
+			const u8 *pru_suart_emu_code, u32 fw_size,
+			u32 clk_rate_pruss,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 datatowrite[128] = {0};
+	s16 status = 0;
+	s16 idx;
+	s16 retval;
+	u16 i;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) &&
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH))
+		return -EINVAL;
+
+	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;
+	/* Configure McASP0  */
+	suart_mcasp_config(init_params->tx_baud_value,
+				init_params->rx_baud_value,
+				init_params->oversampling, pruss_ioaddr);
+	pruss_enable(dev, PRUSS_NUM0);
+
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pruss_enable(dev, PRUSS_NUM1);
+
+	/* Reset PRU RAM */
+	for (i = 0; i < (PRU0_DATARAM_SIZE / sizeof(int)); i++)
+		pruss_writel(dev, (PRU0_DATARAM_OFFSET + (i * sizeof(int))),
+							datatowrite[i]);
+	if (PRU1_MODE != PRU_MODE_INVALID) {
+		for (i = 0; i < (PRU1_DATARAM_SIZE / sizeof(int)); i++)
+			pruss_writel(dev, (PRU1_DATARAM_OFFSET +
+					(i * sizeof(int))), datatowrite[i]);
+	}
+
+	pruss_load(dev, PRUSS_NUM0, (u32 *)pru_suart_emu_code,
+					(fw_size / sizeof(u32)));
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		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, clk_rate_pruss);
+	suart_set_pru_id(dev, PRUSS_NUM0);
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		suart_set_pru_id(dev, PRUSS_NUM1);
+
+	pru_set_rx_tx_mode(dev, PRU0_MODE, PRUSS_NUM0);
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pru_set_rx_tx_mode(dev, PRU1_MODE, PRUSS_NUM1);
+
+	pru_set_ram_data(dev, pruss_ioaddr);
+	pruss_run(dev, PRUSS_NUM0);
+
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pruss_run(dev, PRUSS_NUM1);
+
+	/* Initialize uart_statu_table */
+	for (idx = 0; idx < 8; idx++)
+		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, (u16) timeout);
+	if (PRU1_MODE != PRU_MODE_INVALID)
+		pruss_writew(dev, PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET,
+						(u16) timeout);
+}
+
+void pru_mcasp_deinit(void)
+{
+	suart_mcasp_reset(&suart_iomap);
+}
+
+/* suart Instance open routine  */
+s32 pru_softuart_open(struct suart_handle *h_suart)
+{
+	s16 status = 0;
+	u16 uart_num = h_suart->uart_num - 1;
+
+	if (uart_statu_table[h_suart->uart_num - 1] ==
+			ePRU_SUART_UART_IN_USE) {
+		return -EUSERS;
+	} else {
+		h_suart->uart_type = uart_config[uart_num];
+		h_suart->uart_tx_channel = uart_tx[uart_num];
+		h_suart->uart_rx_channel = uart_rx[uart_num];
+		h_suart->uart_status = ePRU_SUART_UART_IN_USE;
+		uart_statu_table[h_suart->uart_num - 1] =
+						ePRU_SUART_UART_IN_USE;
+	}
+	return status;
+}
+
+/* suart instance close routine */
+s32 pru_softuart_close(struct suart_handle *h_uart)
+{
+	s16 status = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	} else {
+		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;
+}
+
+static s32 search_chnum(u16 uart_num, u16 *ch_num, u32 *pru_offset, u16 mode)
+{
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		*ch_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
+		if (uart_num <= 4) {
+			*pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
+		} else {
+			*pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+			*ch_num -= 8;
+		}
+		(mode == 2) ? ++*ch_num : *ch_num;
+	} else if (mode == 1) {
+			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 if (mode == 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;
+	}
+	return 0;
+}
+
+/*
+ * suart routine for setting relative baud rate
+ */
+s32 pru_softuart_setbaud(struct device *dev, struct suart_handle *h_uart,
+		u16 tx_clk_divisor, u16 rx_clk_divisor)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 regval = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Set the clock divisor value s32o the McASP */
+	if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
+		return -EINVAL;
+	if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
+		return -EINVAL;
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	if (tx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writew(dev, offset, regval);
+	}
+	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 0;
+	}
+	regval = 0;
+	if (rx_clk_divisor != 0) {
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= (~0x3FF);
+		regval |= tx_clk_divisor;
+		pruss_writew(dev, offset, regval);
+	}
+	return status;
+}
+
+/*
+ * suart routine for setting number of bits per character for a specific uart
+ */
+s32 pru_softuart_setdatabits(struct device *dev, struct suart_handle *h_uart,
+		u16 tx_data_bits, u16 rx_data_bits)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u32 reg_val;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/*
+	 * 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 -EINVAL;
+
+	if ((rx_data_bits < ePRU_SUART_DATA_BITS6)
+			|| (rx_data_bits > ePRU_SUART_DATA_BITS12))
+		return -EINVAL;
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	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);
+		reg_val &= ~(0xF);
+		reg_val |= tx_data_bits;
+		pruss_writeb(dev, offset, (u8) reg_val);
+	}
+	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 0;
+	}
+	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);
+		reg_val &= ~(0xF);
+		reg_val |= rx_data_bits;
+		pruss_writeb(dev, offset, (u8) rx_data_bits);
+	}
+
+	return status;
+}
+
+/*
+ * suart routine to configure specific uart
+ */
+s32 pru_softuart_setconfig(struct device *dev, struct suart_handle *h_uart,
+				struct suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/*
+	 * 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 -EINVAL;
+	}
+	if ((config_uart->tx_bits_per_char < 8)
+			|| (config_uart->tx_bits_per_char > 14)) {
+		return -EINVAL;
+	}
+	if ((config_uart->rx_bits_per_char < 8)
+			|| (config_uart->rx_bits_per_char > 14)) {
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	/*
+	 * 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_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->tx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->tx_clk_divisor <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->tx_bits_per_char <<
+			PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+	}
+
+	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 0;
+	}
+
+	/* 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_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->rx_serializer <<
+			PRU_SUART_CH_CTRL_SR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+
+		/* Configuring RX prescalar value and Oversampling */
+		offset = pru_offset +
+			(ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_CONFIG1_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		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_writew(dev, offset, reg_val);
+
+		/* Configuring RX bits per character value */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+						+ PRU_SUART_CH_CONFIG2_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+		reg_val = reg_val | (config_uart->rx_bits_per_char <<
+			PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
+		pruss_writew(dev, offset, reg_val);
+	}
+	return status;
+}
+
+/*
+ * suart routine for getting the number of bytes transfered
+ */
+s32 pru_softuart_get_tx_data_len(struct device *dev,
+					struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 read_value = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &read_value);
+	read_value = ((read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	return read_value;
+}
+
+/*
+ * suart routine for getting the number of bytes received
+ */
+s32 pru_softuart_get_rx_data_len(struct device *dev,
+					struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 read_value = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &read_value);
+	read_value = ((read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
+					>> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	return read_value;
+}
+
+/*
+ * suart routine to get the configuration information from a specific uart
+ */
+s32 pru_softuart_getconfig(struct device *dev,
+			 struct suart_handle *h_uart,
+			struct suart_config *config_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+	s16 status = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/*
+	 * NOTE:
+	 * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
+	 * EQUAL TO 64, preScalarValue <= 64
+	 */
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	/* 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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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 0;
+	}
+	/* 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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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_readw(dev, offset, (u16 *) &reg_val);
+	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 ISR_value = 0;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		return 0;
+	} 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 *)&ISR_value);
+		if ((ISR_value & 0x1) == 0x1)
+			return -EINVAL;
+	} 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 *)&ISR_value);
+		if ((ISR_value & 0x2) == 0x2)
+			return -EINVAL;
+	} else {
+		return 0;
+	}
+
+	return 0;
+}
+
+/*
+ * suart data transmit routine
+ */
+s32 pru_softuart_write(struct device *dev, struct suart_handle *h_uart,
+		u32 *pt_tx_data_buf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
+				(PRU1_MODE == PRU_MODE_RX_TX_BOTH))
+		pru_num = h_uart->uart_num;
+	else if (PRU0_MODE == PRU_MODE_TX_ONLY)
+		pru_num = 0;
+	else if (PRU1_MODE == PRU_MODE_TX_ONLY)
+		pru_num = 1;
+	else
+		return 0;
+
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writew(dev, offset, reg_val);
+
+	/* 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_writel(dev, offset, (u32) *pt_tx_data_buf);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	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_writew(dev, offset, reg_val);
+
+	/* generate ARM->PRU event */
+	suart_arm_to_pru_intr(dev, pru_num);
+
+	return status;
+}
+
+/*
+ * suart data receive routine
+ */
+s32 pru_softuart_read(struct device *dev, struct suart_handle *h_uart,
+		u32 *ptDataBuf, u16 data_len)
+{
+	u32 offset = 0;
+	u32 pru_offset;
+	s16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val = 0;
+	u16 pru_num;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+	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;
+		pru_num = h_uart->uart_num;
+	} else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
+		pru_num = 0;
+	} else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
+		pru_num = 1;
+	} else {
+		return 0;
+	}
+	/* Writing data length to SUART channel register */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_CONFIG2_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
+	pruss_writew(dev, offset, reg_val);
+
+	/* 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_writel(dev, offset, (u32) *ptDataBuf);
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+		PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	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_writew(dev, offset, reg_val);
+
+	/* 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
+ */
+s32 pru_softuart_read_data(struct device *dev, struct suart_handle *h_uart,
+				u8 *p_data_buffer, s32 max_len,
+					u32 *pdata_read)
+{
+	s16 ret_val = 0;
+	u8 *psrc_addr = NULL;
+	u32 data_read = 0;
+	u32 data_len = 0;
+	u32 char_len = 0;
+	u32 offset = 0;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 status = 0;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	/* 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_multi(dev, offset, (u8 *) &psrc_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_readw(dev, offset, (u16 *) &data_len);
+
+	/* read the character length */
+	char_len = data_len & PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK;
+	char_len -= 2;	/* remove the START & STOP bit */
+
+	data_len &= PRU_SUART_CH_CONFIG2_DATALEN_MASK;
+	data_len = data_len >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT;
+	data_len++;
+
+	/* if the character length is greater than 8, then the size doubles */
+	if (char_len > 8)
+		data_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 *) &status);
+	if (CHN_TXRX_STATUS_TIMEOUT == (status & 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 *) &data_read);
+
+		/* if the character length is greater than 8,
+				then the size doubles */
+		if (char_len > 8)
+			data_read *= 2;
+
+/*
+ * the data corresponding is loaded in second
+ * half during the timeout
+ */
+		if (data_read > data_len) {
+			data_read -= data_len;
+			psrc_addr += data_len;
+		}
+
+		pru_softuart_clr_rx_fifo(dev, h_uart);
+	} else {
+		data_read = data_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 (status & CHN_TXRX_STATUS_CMPLT)
+			psrc_addr += data_len;
+	}
+
+	/* we should be copying only max len given by the application */
+	if (data_read > max_len)
+		data_read = max_len;
+
+/* evaluate the virtual address of the FIFO address
+ * based on the physical addr
+ */
+	psrc_addr = (u8 *)((u32) psrc_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 < data_read; offset++)
+		*p_data_buffer++ = *psrc_addr++;
+	*pdata_read = data_read;
+	ret_val = 0;
+
+	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.
+ */
+s32 pru_softuart_stop_receive(struct device *dev, struct suart_handle *h_uart)
+{
+	u16 ret_status = 0;
+	u32 offset;
+	u32 pru_offset;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 status;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	/* 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 *) &status);
+
+	/* we need to clear the busy bit corresponding to receive channel */
+	status &= ~(CHN_TXRX_STATUS_RDY);
+	pruss_writeb(dev, offset, (u8) status);
+
+	/* 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_readw(dev, offset, (u16 *) &status);
+	status &= PRU_SUART_CH_CTRL_SR_MASK;
+	status = status >> PRU_SUART_CH_CTRL_SR_SHIFT;
+
+	/* we need to de-activate the serializer corresponding to this rx */
+	ret_status = suart_asp_serializer_deactivate(status, &suart_iomap);
+
+	return ret_status;
+}
+
+/*
+ * suart routine to get the tx status for a specific uart
+ */
+s32 pru_softuart_get_tx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	return status;
+}
+
+s32 pru_softuart_clr_tx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+					PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	status &= ~(0x2);
+	pruss_writeb(dev, offset, (u8) status);
+	return status;
+}
+
+/*
+ * suart routine to get the rx status for a specific uart
+ */
+s32 pru_softuart_get_rx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+				PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	return status;
+}
+
+static s32 pru_softuart_clr_rx_fifo(struct device *dev,
+				struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+	u16 reg_val;
+	u16 uart_num;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	uart_num = h_uart->uart_num;
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+	if (PRU0_MODE == PRU_MODE_RX_ONLY)
+		uart_num = 0;
+	else if (PRU1_MODE == PRU_MODE_RX_ONLY)
+		uart_num = 1;
+
+	/* Reset the number of bytes read into the FIFO */
+		offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+					+ PRU_SUART_CH_BYTESDONECNTR_OFFSET;
+		pruss_readw(dev, offset, (u16 *) &reg_val);
+	reg_val &= 0x00;
+		pruss_writew(dev, offset, reg_val);
+
+
+	/* Service Request to PRU */
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+						PRU_SUART_CH_CTRL_OFFSET;
+	pruss_readw(dev, offset, (u16 *) &reg_val);
+	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_writew(dev, offset, reg_val);
+	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;
+}
+
+s32 pru_softuart_clr_rx_status(struct device *dev, struct suart_handle *h_uart)
+{
+	u32 offset;
+	u32 pru_offset;
+	u16 status = 0;
+	u16 ch_num = h_uart->uart_num - 1;
+
+	if (h_uart == NULL) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
+
+	offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
+			PRU_SUART_CH_TXRXSTATUS_OFFSET;
+	pruss_readb(dev, offset, (u8 *) &status);
+	status &= ~(0x3C);
+	pruss_writeb(dev, offset, (u8) status);
+	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 >
+ */
+s32 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num, u16 *txrx_flag)
+{
+	u32 intc_offset;
+	u32 ch_num = 0xFF;
+	u32 reg_val = 0;
+	u32 reg_val2 = 0;
+	u32 ISR_value = 0;
+	u32 ack_reg_val = 0;
+	u32 stat_inx_clr_regoffset = 0;
+
+	/* initialize the status & Flag to known value */
+	*txrx_flag = 0;
+
+	stat_inx_clr_regoffset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
+
+	/* Read PRU Interrupt Status Register from PRU */
+	intc_offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
+
+	pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+		|| (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* Check if the interrupt occured for Tx */
+		ch_num = uart_num * 2 - 2;
+		reg_val2 = PRU_SUART0_TX_EVT_BIT << ((uart_num - 1) * 2);
+		if (ISR_value & reg_val2) {
+			/* interupt occured for TX */
+			*txrx_flag |= PRU_TX_INTR;
+			/* acknowledge the RX interrupt  */
+			ack_reg_val  = ch_num + PRU_SUART0_TX_EVT;
+			pruss_writel(dev, stat_inx_clr_regoffset,
+					ack_reg_val);
+		}
+
+		/* Check if the interrupt occured for Rx */
+		reg_val2 = PRU_SUART0_RX_EVT_BIT << ((uart_num - 1) * 2);
+		pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
+		if (ISR_value & reg_val2) {
+			/* interupt occured for RX */
+			*txrx_flag |= PRU_RX_INTR;
+			ch_num += 1;
+
+			/* acknowledge the RX interrupt  */
+			ack_reg_val  = ch_num + PRU_SUART0_TX_EVT;
+			pruss_writel(dev, stat_inx_clr_regoffset,
+						ack_reg_val);
+		}
+	} else {
+		ch_num = uart_num - 1;
+		if ((ISR_value & 0x03FC) != 0) {
+			reg_val2 = 1 << (uart_num + 1);
+			if (ISR_value & reg_val2) {
+				/* acknowledge the s32errupt  */
+				ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
+				pruss_writel(dev, stat_inx_clr_regoffset,
+					ack_reg_val);
+				*txrx_flag |= PRU_RX_INTR;
+			}
+		}
+		pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
+		if (ISR_value & 0x3FC00) {
+			reg_val2 = 1 << (uart_num + 9);
+			if (ISR_value & reg_val2) {
+				/* acknowledge the s32errupt  */
+				ack_reg_val = ch_num + PRU_SUART4_TX_EVT;
+				pruss_writel(dev, stat_inx_clr_regoffset,
+					ack_reg_val);
+				*txrx_flag |= PRU_TX_INTR;
+			}
+		}
+	}
+	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 0;
+	}
+
+	pruss_readb(dev, offset, (u8 *) &txrx_flag);
+	txrx_flag &= ~(0x2);
+	pruss_writeb(dev, offset, (u8) txrx_flag);
+
+	return 0;
+}
+
+s32 suart_arm_to_pru_intr(struct device *dev, u16 uart_num)
+{
+	u32 value;
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		if ((uart_num > 0) && (uart_num <= 4))
+			value = 0x20; /* PRU0 SYS_EVT32 */
+		else if ((uart_num > 4) && (uart_num <= 8))
+			value = 0x21; /* PRU0 SYS_EVT33 */
+		else
+			return -EINVAL;
+	}
+	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)
+			value = 0x20; /* PRU0 SYS_EVT32 */
+		else if (uart_num == PRUSS_NUM1)
+			value = 0x21; /* PRU0 SYS_EVT33 */
+		else
+			return -EINVAL;
+	}
+	return pruss_writel(dev, PRUSS_INTC_STATIDXSET, value);
+}
+
+static s32 arm_to_pru_intr_init(struct device *dev)
+{
+	u32 value;
+	u32 int_offset;
+
+	/* Clear all the host interrupts */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++)
+		pruss_idx_writel(dev, PRUSS_INTC_HSTINTENIDXCLR, int_offset);
+
+	/* Enable the global s32errupt */
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_GLBLEN & 0xFFFF), 0, 1);
+
+	/* Enable the Host interrupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							 int_offset++)
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF),
+								0, int_offset);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP0 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP0_CHAN);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP1 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP1_CHAN);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP2 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP2_CHAN);
+
+	 /* MAP Channel 0 to SYS_EVT31 */
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP7 & 0xFFFF),
+			PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP7_SYS_EVT31);
+
+	if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
+	    || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
+		/* Sets the channels for the system interrupt */
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP9_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP10_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP11_FULL);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP12_FULL);
+	}
+	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 channels for the system interrupt */
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP9_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP10_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP11_HALF);
+		pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF),
+				PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP12_HALF);
+	}
+
+	/* Clear required set of system events
+	* and enable them using indexed register
+	*/
+	for (int_offset = 0; int_offset < 18; int_offset++) {
+		value = 32 + int_offset;
+		pruss_idx_writel(dev, PRUSS_INTC_STATIDXCLR, value);
+	}
+
+	/* enable only the HOST to PRU interrupts and let the PRU to Host events
+	 * enabled by the separate API on demand basis.
+	 */
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 31);
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 32);
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 33);
+	pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 50);
+	pruss_rmwl(dev, (u32) (PRUSS_INTC_GLBLEN & 0xFFFF), 0, 1);
+
+	/* Enable the Host interrupts for all host channels */
+	for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
+							int_offset++)
+		pruss_idx_writel(dev, PRUSS_INTC_HSTINTENIDXSET, int_offset);
+
+	return 0;
+}
+
+s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
+		u32 txrxmode, s32 flag)
+{
+	u32 chn_num;
+	u32 value;
+	s16 retval = 0;
+
+	if (uart_num > 8)
+		return -EINVAL;
+
+	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++;
+		value = 34 + chn_num;
+	} else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_RX_ONLY))
+		value = 34 + chn_num;
+	else if ((PRU_MODE_RX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_RX_ONLY))
+		value = 42 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU0_MODE == PRU_MODE_TX_ONLY))
+		value = 34 + chn_num;
+	else if ((PRU_MODE_TX_ONLY == txrxmode)
+		&& (PRU1_MODE == PRU_MODE_TX_ONLY))
+		value = 42 + chn_num;
+	else
+		return -EINVAL;
+
+	retval = flag ? pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, value) :
+			pruss_idx_writel(dev, PRUSS_INTC_ENIDXCLR, value);
+	return retval;
+}
+
+s32 suart_intr_setmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	u32 regval = 0;
+	u32 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 -EINVAL;
+		}
+		if (2 == txrxmode)
+			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) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+	} else
+		return 0;
+
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (rmask & CHN_TXRX_IE_MASK_CMPLT))
+		pruss_rmww(dev, offset, regval, regval);
+
+	if ((rmask & SUART_GBL_INTR_ERR_MASK) ==
+			SUART_GBL_INTR_ERR_MASK) {
+		regval = SUART_GBL_INTR_ERR_MASK;
+		pruss_rmww(dev, offset, regval, regval);
+	}
+
+	offset = pru_offset +
+		(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+				+ PRU_SUART_CH_CONFIG1_OFFSET;
+	/* Framing Error Interrupt Masked */
+	if ((rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		regval |= CHN_TXRX_IE_MASK_FE;
+		pruss_writew(dev, offset, (u16) regval);
+	}
+
+	/* Break Indicator Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		regval |= CHN_TXRX_IE_MASK_BI;
+		pruss_writew(dev, offset, (u16) regval);
+	}
+
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		regval |= CHN_TXRX_IE_MASK_TIMEOUT;
+		pruss_writew(dev, offset, (u16) regval);
+	}
+	return 0;
+}
+
+s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
+		u32 txrxmode, u32 rmask)
+{
+	u32 offset;
+	u32 pru_offset;
+	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 -EINVAL;
+		if (2 == txrxmode)
+			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) {
+		pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
+		offset = PRU_SUART_PRU1_IMR_OFFSET;
+	} else
+		return 0;
+
+	regval = 1 << chn_num;
+	if (CHN_TXRX_IE_MASK_CMPLT == (rmask & CHN_TXRX_IE_MASK_CMPLT))
+		pruss_rmww(dev, offset, regval, 0);
+
+	if ((rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK)
+		pruss_rmww(dev, offset, SUART_GBL_INTR_ERR_MASK, 0);
+
+	offset = pru_offset +
+		(chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
+				+ PRU_SUART_CH_CONFIG1_OFFSET;
+
+	/* Framing Error Interrupt Masked */
+	if ((rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_FE);
+		pruss_writew(dev, offset, regval);
+	}
+
+	/* Break Indicator Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_BI == (rmask & CHN_TXRX_IE_MASK_BI)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_BI);
+		pruss_writew(dev, offset, regval);
+	}
+
+	/* Timeout error Interrupt Masked */
+	if (CHN_TXRX_IE_MASK_TIMEOUT ==
+			(rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
+		regval = 0;
+		pruss_readw(dev, offset, (u16 *) &regval);
+		regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
+		pruss_writew(dev, offset, regval);
+	}
+	return 0;
+}
+
+s32 suart_intr_getmask(struct device *dev, u16 uart_num,
+				u32 txrxmode, u32 rmask)
+{
+	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 -EINVAL;
+
+		if (2 == txrxmode)
+			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 0;
+
+	regval = regval << chn_num;
+	pruss_readw(dev, offset, (u16 *) &txrx_flag);
+	txrx_flag &= regval;
+
+	if ((rmask && (txrx_flag == regval)) || (!rmask && !txrx_flag))
+		return 1;
+
+	return 0;
+}
diff --git a/drivers/tty/serial/pruss_suart_utils.c b/drivers/tty/serial/pruss_suart_utils.c
new file mode 100644
index 0000000..5ee340e
--- /dev/null
+++ b/drivers/tty/serial/pruss_suart_utils.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2010, 2011 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.h>
+#include "pruss_suart.h"
+
+#define SUART_TRX_DIV_CONF_SZ	4
+
+static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+			struct pruss_suart_iomap *pruss_ioaddr);
+static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value, u32 oversampling,
+			struct 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
+ */
+static 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
+ */
+static 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
+ */
+static 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_reset(struct pruss_suart_iomap *pruss_ioaddr)
+{
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+	/* reset mcasp. */
+	iowrite32(MCASP_SUART_GBLCTL, &mcasp0_regs->gblctl);
+	iowrite32(MCASP_SUART_RGBLCTL, &mcasp0_regs->rgblctl);
+	iowrite32(MCASP_SUART_XGBLCTL, &mcasp0_regs->xgblctl);
+	iowrite32(MCASP_SUART_XSTAT, &mcasp0_regs->xstat);
+	iowrite32(MCASP_SUART_RSTAT, &mcasp0_regs->rstat);
+}
+
+void suart_mcasp_config(u32 tx_baud_value,
+			u32 rx_baud_value,
+			u32 oversampling,
+			struct pruss_suart_iomap *pruss_ioaddr)
+{
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+
+	/* reset mcasp */
+	iowrite32(MCASP_SUART_GBLCTL, &mcasp0_regs->gblctl);
+	iowrite32(MCASP_SUART_RGBLCTL, &mcasp0_regs->rgblctl);
+	iowrite32(MCASP_SUART_XGBLCTL, &mcasp0_regs->xgblctl);
+
+	/* configure receive registers */
+	if ((SUART_8X_OVRSMPL == oversampling) || (0 == oversampling)) {
+		iowrite32(MCASP_SUART_RMASK_8, &mcasp0_regs->rmask);
+		iowrite32(MCASP_SUART_RFMT_8, &mcasp0_regs->rfmt);
+	}
+	if (SUART_16X_OVRSMPL == oversampling) {
+		iowrite32(MCASP_SUART_RMASK_16, &mcasp0_regs->rmask);
+		iowrite32(MCASP_SUART_RFMT_16, &mcasp0_regs->rfmt);
+
+	}
+
+	iowrite32(MCASP_SUART_FSRM, &mcasp0_regs->afsrctl);
+	iowrite32(MCASP_SUART_CLKRM_CLKRP, &mcasp0_regs->aclkrctl);
+	iowrite32(MCASP_SUART_HCLKRP, &mcasp0_regs->ahclkrctl);
+	suart_mcasp_rx_baud_set(rx_baud_value, oversampling, pruss_ioaddr);
+	iowrite32(MCASP_SUART_RTDMS0, &mcasp0_regs->rtdm);
+	iowrite32(MCASP_SUART_RSYNCERR, &mcasp0_regs->rintctl);
+	iowrite32(MCASP_SUART_RMAX_RPS_256, &mcasp0_regs->rclkchk);
+
+	/* configure transmit registers. */
+	iowrite32(MCASP_SUART_XMASK_0_31, &mcasp0_regs->xmask);
+	iowrite32(MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0, &mcasp0_regs->xfmt);
+	iowrite32(MCASP_SUART_FSXM, &mcasp0_regs->afsxctl);
+	iowrite32(MCASP_SUART_CLKXM_ASYNC_CLKXP, &mcasp0_regs->aclkxctl);
+	iowrite32(MCASP_SUART_HCLKXM, &mcasp0_regs->ahclkxctl);
+
+	suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
+	iowrite32(MCASP_SUART_XTDMS0, &mcasp0_regs->xtdm);
+	iowrite32(MCASP_SUART_XSYNCERR, &mcasp0_regs->xintctl);
+	iowrite32(MCASP_SUART_XMAX_XPS_256, &mcasp0_regs->xclkchk);
+
+	/* Serializer as a transmitter */
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl0);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl1);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl2);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl3);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl4);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl5);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl6);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl7);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl8);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl9);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl10);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl11);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl12);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl13);
+	iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl14);
+	iowrite32(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);
+	iowrite32(temp_reg, &mcasp0_regs->pfunc);
+
+	iowrite32(0xFFF, &mcasp0_regs->pdout);
+
+	/* config pin function and direction */
+	iowrite32(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);
+	iowrite32(temp_reg, &mcasp0_regs->pdir);
+
+	iowrite32(MCASP_SUART_DIT_DISABLE, &mcasp0_regs->ditctl);
+	iowrite32(MCASP_SUART_LOOPBACK_DISABLE, &mcasp0_regs->dlbctl);
+	iowrite32(MCASP_SUART_AMUTE_DISABLE, &mcasp0_regs->amute);
+
+	iowrite32(MCASP_SUART_XSTAT, &mcasp0_regs->xstat);
+	iowrite32(MCASP_SUART_RSTAT, &mcasp0_regs->rstat);
+}
+
+void suart_mcasp_tx_serialzier_set(u32 serializer_num,
+		struct pruss_suart_iomap *pruss_ioaddr)
+{
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+	u32 temp_reg;
+	temp_reg = ioread32(&mcasp0_regs->pfunc);
+	temp_reg |= (0x1 << serializer_num);
+	iowrite32(temp_reg, &mcasp0_regs->pfunc);
+}
+
+/*
+ * mcasp TX buard rate setting routine
+ */
+static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
+		struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val;
+	u32 loop_cnt;
+	s16 status = 0;
+	s16 found_val = false;
+
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					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 = true;
+			break;
+		}
+	}
+	if (found_val == true) {
+		clk_div_val = lt_tx_baud_rate[loop_cnt][2];
+		temp_reg = ioread32(&mcasp0_regs->aclkxctl);
+		temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+		iowrite32(temp_reg, &mcasp0_regs->aclkxctl);
+		clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+		temp_reg = ioread32(&mcasp0_regs->ahclkxctl);
+		temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+		iowrite32(temp_reg, &mcasp0_regs->ahclkxctl);
+	} else {
+		return -EINVAL ;
+	}
+	return status;
+}
+
+/*
+ * mcasp RX buard rate setting routine
+ */
+static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value,
+	u32 oversampling, struct pruss_suart_iomap *pruss_ioaddr)
+{
+	u32 clk_div_val = 0;
+	u32 loop_cnt = 0;
+	s16 status = 0;
+	u32 temp_reg = 0;
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+					pruss_ioaddr->mcasp_io_addr;
+
+	switch (oversampling) {
+	case 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 = ioread32(&mcasp0_regs->aclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
+
+				clk_div_val =
+				lt_rx_8x_baud_rate[loop_cnt][3] - 1;
+
+				temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
+				break;
+			}
+		}
+		status = -EINVAL;
+		break;
+	case 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 = ioread32(&mcasp0_regs->aclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
+				clk_div_val = lt_rx_16x_baud_rate[loop_cnt][3];
+				temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
+				break;
+			}
+		}
+		status = -EINVAL;
+		break;
+	case SUART_TX_OVRSMPL:
+		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 = ioread32(&mcasp0_regs->aclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
+				clk_div_val = lt_tx_baud_rate[loop_cnt][3];
+				temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
+				temp_reg |= (clk_div_val <<
+					OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
+				iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
+				break;
+			}
+		}
+		status = -EINVAL;
+		break;
+	default:
+		status = -EINVAL;
+		break;
+	}
+
+	return status;
+}
+
+/*
+ * mcasp buard rate setting routine
+ */
+s16 suart_asp_baud_set(u32 tx_baud_value, u32 rx_baud_value, u32 oversampling,
+					struct pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = 0;
+
+	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 sr_num,
+		struct pruss_suart_iomap *pruss_ioaddr)
+{
+	s16 status = 0;
+	struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
+		 pruss_ioaddr->mcasp_io_addr;
+	if (sr_num > 15)
+		status = -EINVAL;
+	else
+		iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl0);
+
+	return status;
+}
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] 166+ messages in thread

* [PATCH v4 09/11] mfd: pruss CAN private data.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
index c5e2af2..3b46156 100644
--- a/include/linux/mfd/pruss.h
+++ b/include/linux/mfd/pruss.h
@@ -92,6 +92,11 @@ struct da850_evm_pruss_suart_data {
 	int (*setup)(void);
 };
 
+struct da850_evm_pruss_can_data {
+	u32 version;
+	int (*setup)(void);
+};
+
 s32 pruss_enable(struct device *dev, u8 pruss_num);
 
 s32 pruss_load(struct device *dev, u8 pruss_num,
-- 
1.7.2.3


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

* [PATCH v4 09/11] mfd: pruss CAN private data.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
index c5e2af2..3b46156 100644
--- a/include/linux/mfd/pruss.h
+++ b/include/linux/mfd/pruss.h
@@ -92,6 +92,11 @@ struct da850_evm_pruss_suart_data {
 	int (*setup)(void);
 };
 
+struct da850_evm_pruss_can_data {
+	u32 version;
+	int (*setup)(void);
+};
+
 s32 pruss_enable(struct device *dev, u8 pruss_num);
 
 s32 pruss_load(struct device *dev, u8 pruss_num,
-- 
1.7.2.3

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

* [PATCH v4 10/11] da850: pruss CAN platform specific additions.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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            |    5 +++++
 arch/arm/mach-davinci/include/mach/mux.h |    5 +++++
 2 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a7cf2d0..84a5e64 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -581,7 +581,12 @@ 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_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 5d4e0fe..85b3a0d 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -906,8 +906,13 @@ 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_0,
 	DA850_GPIO2_4,
 	DA850_GPIO2_6,
 	DA850_GPIO2_8,
-- 
1.7.2.3


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

* [PATCH v4 10/11] da850: pruss CAN platform specific additions.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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            |    5 +++++
 arch/arm/mach-davinci/include/mach/mux.h |    5 +++++
 2 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a7cf2d0..84a5e64 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -581,7 +581,12 @@ 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_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 5d4e0fe..85b3a0d 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -906,8 +906,13 @@ 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_0,
 	DA850_GPIO2_4,
 	DA850_GPIO2_6,
 	DA850_GPIO2_8,
-- 
1.7.2.3

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

* [PATCH v4 11/11] da850: pruss CAN board specific additions.
  2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
@ 2011-04-22 12:08   ` Subhasish Ghosh
  2011-04-22 12:08   ` Subhasish Ghosh
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 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 pinmux 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 |   46 +++++++++++++++++++++++++++++++
 1 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index e7fdf31..e1ff18c 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -48,6 +48,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)
 
@@ -1117,6 +1118,43 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static const short da850_evm_pruss_can_pins[] = {
+	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
+	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
+	-1
+};
+
+static int __init da850_evm_pruss_can_setup(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);
+
+	/* 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;
+}
+
+static struct da850_evm_pruss_can_data can_data = {
+	.version	= 1,
+	.setup		= da850_evm_pruss_can_setup,
+};
+
+
 static const short da850_evm_pruss_suart_pins[] = {
 	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
 	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
@@ -1161,6 +1199,14 @@ static struct mfd_cell cell[] = {
 		.resources	= da850_evm_pruss_suart_resource,
 	},
 	{
+		.id		= 1,
+		.name		= "da8xx_pruss_can",
+		.platform_data	= &can_data,
+		.data_size	= sizeof(can_data),
+		.num_resources  = 0,
+		.resources	= NULL,
+	},
+	{
 		.name		= NULL,
 	},
 };
-- 
1.7.2.3


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

* [PATCH v4 11/11] da850: pruss CAN board specific additions.
@ 2011-04-22 12:08   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-22 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the pruss CAN pinmux 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 |   46 +++++++++++++++++++++++++++++++
 1 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index e7fdf31..e1ff18c 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -48,6 +48,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)
 
@@ -1117,6 +1118,43 @@ static __init int da850_evm_init_cpufreq(void)
 static __init int da850_evm_init_cpufreq(void) { return 0; }
 #endif
 
+static const short da850_evm_pruss_can_pins[] = {
+	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
+	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
+	-1
+};
+
+static int __init da850_evm_pruss_can_setup(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);
+
+	/* 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;
+}
+
+static struct da850_evm_pruss_can_data can_data = {
+	.version	= 1,
+	.setup		= da850_evm_pruss_can_setup,
+};
+
+
 static const short da850_evm_pruss_suart_pins[] = {
 	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
 	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
@@ -1161,6 +1199,14 @@ static struct mfd_cell cell[] = {
 		.resources	= da850_evm_pruss_suart_resource,
 	},
 	{
+		.id		= 1,
+		.name		= "da8xx_pruss_can",
+		.platform_data	= &can_data,
+		.data_size	= sizeof(can_data),
+		.num_resources  = 0,
+		.resources	= NULL,
+	},
+	{
 		.name		= NULL,
 	},
 };
-- 
1.7.2.3

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-04-22 16:00     ` Marc Kleine-Budde
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-22 16:00 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Samuel Ortiz, nsekhar,
	open list, m-watkins, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 29131 bytes --]

On 04/22/2011 02:08 PM, Subhasish Ghosh wrote:
> This patch adds the pruss MFD driver and associated include files.
> For details regarding the PRUSS please refer the folowing link:
> http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem
> 
> The rational behind the MFD driver being the fact that multiple devices can
> be implemented on the cores independently. This is determined by the nature
> of the program which is loaded into the PRU's instruction memory.
> A device may be de-initialized and another loaded or two different devices
> can be run simultaneously on the two cores.
> It's also possible, as in our case, to implement a single device on both
> the PRU's resulting in improved load sharing.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
>  drivers/mfd/Kconfig            |   10 +
>  drivers/mfd/Makefile           |    1 +
>  drivers/mfd/pruss.c            |  513 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/pruss.h      |  130 ++++++++++
>  include/linux/mfd/pruss_core.h |  128 ++++++++++
>  5 files changed, 782 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mfd/pruss.c
>  create mode 100644 include/linux/mfd/pruss.h
>  create mode 100644 include/linux/mfd/pruss_core.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 0284c53..41479e4 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -92,6 +92,16 @@ config MFD_TI_SSP
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ti-ssp.
>  
> +config MFD_DA8XX_PRUSS
> +	tristate "Texas Instruments DA8XX PRUSS support"
> +	depends on ARCH_DAVINCI_DA850
> +	select MFD_CORE
> +	help
> +	  This driver provides support API 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 c56b6c7..8015dea 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)	+= pruss.o
>  obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
>  obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
>  
> diff --git a/drivers/mfd/pruss.c b/drivers/mfd/pruss.c
> new file mode 100644
> index 0000000..6836d5a
> --- /dev/null
> +++ b/drivers/mfd/pruss.c
> @@ -0,0 +1,513 @@
> +/*
> + * Copyright (C) 2010, 2011 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/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/mfd/pruss.h>
> +#include <linux/mfd/core.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +
> +struct pruss_priv {
> +	struct device *dev;
> +	spinlock_t lock;
> +	struct resource *res;
> +	struct clk *clk;
> +	void __iomem *ioaddr;
> +};
> +
> +s32 pruss_disable(struct device *dev, u8 pruss_num)
make it a int function
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 temp_reg;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	spin_lock(&pruss->lock);
> +
> +	/* pruss deinit */
> +	iowrite32(0xFFFFFFFF, &pruss_mmap->intc.statclrint[pruss_num]);
> +
> +	/* Disable PRU */
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
> +			((PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
> +			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
> +			PRUCORE_CONTROL_COUNTENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +		~PRUCORE_CONTROL_ENABLE_MASK) |
> +		((PRUCORE_CONTROL_ENABLE_DISABLE <<
> +		PRUCORE_CONTROL_ENABLE_SHIFT) &
> +		PRUCORE_CONTROL_ENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +
> +	/* Reset PRU */
> +	iowrite32(PRUCORE_CONTROL_RESETVAL,
> +				&h_pruss->control);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;

make it a void function?
> +}
> +EXPORT_SYMBOL_GPL(pruss_disable);
> +
> +s32 pruss_enable(struct device *dev, u8 pruss_num)
int?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 i;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	/* Reset PRU  */
> +	spin_lock(&pruss->lock);
> +	iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);

no need to lock the ram reset below?


> +	spin_unlock(&pruss->lock);
> +
> +	/* Reset any garbage in the ram */
> +	if (pruss_num == PRUCORE_0)
> +		for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram0[i]);
> +	else if (pruss_num == PRUCORE_1)
> +		for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram1[i]);

if you make a array for these

+struct pruss_map {
+	u8 dram0[512];
+	u8 res1[7680];

+	u8 dram1[512];
+	u8 res2[7680];
..}

you don't need the if..else..

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_enable);
> +
> +/* Load the specified PRU with code */
> +s32 pruss_load(struct device *dev, u8 pruss_num,
> +			u32 *pruss_code, u32 code_size_in_words)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 __iomem *pruss_iram;
> +	u32 i;
> +
> +	if (pruss_num == PRUCORE_0)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
> +	else if (pruss_num == PRUCORE_1)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
> +	else

same here
> +		return -EINVAL;
> +
> +	pruss_enable(dev, pruss_num);
> +
> +	spin_lock(&pruss->lock);
> +	/* Copy dMAX code to its instruction RAM  */
> +	for (i = 0; i < code_size_in_words; i++)
> +		iowrite32(pruss_code[i], (pruss_iram + i));
> +
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_load);
> +
> +s32 pruss_run(struct device *dev, u8 pruss_num)
int?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 temp_reg;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	/* Enable dMAX, let it execute the code we just copied */
> +	spin_lock(&pruss->lock);
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
> +			((PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
> +			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
> +			PRUCORE_CONTROL_COUNTENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +			~PRUCORE_CONTROL_ENABLE_MASK) |
> +			((PRUCORE_CONTROL_ENABLE_ENABLE <<
> +			PRUCORE_CONTROL_ENABLE_SHIFT) &
> +			PRUCORE_CONTROL_ENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_run);
> +
> +s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 temp_reg;
> +	u32 cnt = timeout;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	while (cnt--) {
> +		temp_reg = ioread32(&h_pruss->control);
> +		if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
> +				PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
> +				PRUCORE_CONTROL_RUNSTATE_HALT)
> +			break;

how long might this take? what about some delay, sleep, or reschedule?

> +	}
> +	if (!cnt)
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_wait_for_halt);
> +
> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;

we usually don't use "p" variable names for pointers

> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite8(pdatatowrite, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writeb);
> +
> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
void function?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddress;
> +	u32 preg_data;
> +
> +	paddress = pruss->ioaddr + offset;
> +
> +	spin_lock(&pruss->lock);
> +	preg_data = ioread8(paddress);
> +	preg_data &= ~mask;
> +	preg_data |= val;
> +	iowrite8(preg_data, paddress);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_rmwb);
> +
> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset ;
> +	*pdatatoread = ioread8(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb);
> +
> +s32 pruss_readb_multi(struct device *dev, u32 offset,
> +		u8 *pdatatoread, u16 bytestoread)
viod?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u8 __iomem *paddresstoread;
> +	u16 i;
int?
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +
> +	for (i = 0; i < bytestoread; i++)
> +		*pdatatoread++ = ioread8(paddresstoread++);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb_multi);
> +
> +s32 pruss_writel(struct device *dev, u32 offset,
> +		u32 pdatatowrite)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite32(pdatatowrite, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writel);
> +
> +s32 pruss_writel_multi(struct device *dev, u32 offset,
> +		u32 *pdatatowrite, u16 wordstowrite)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u32 __iomem *paddresstowrite;
> +	u16 i;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +
> +	for (i = 0; i < wordstowrite; i++)
> +		iowrite32(*pdatatowrite++, paddresstowrite++);
memcopy_to_iomem?
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writel_multi);
> +
> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddress;
> +	u32 preg_data;
> +
> +	paddress = pruss->ioaddr + offset;
> +
> +	spin_lock(&pruss->lock);
> +	preg_data = ioread32(paddress);
> +	preg_data &= ~mask;
> +	preg_data |= val;
> +	iowrite32(preg_data, paddress);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_rmwl);
> +
> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
void? or return the read value
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +	*pdatatoread = ioread32(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readl);
> +
> +s32 pruss_readl_multi(struct device *dev, u32 offset,
> +		u32 *pdatatoread, u16 wordstoread)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u32 __iomem *paddresstoread;
> +	u16 i;
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +	for (i = 0; i < wordstoread; i++)
> +		*pdatatoread++ = ioread32(paddresstoread++);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readl_multi);
> +
> +s32 pruss_writew(struct device *dev, u32 offset, u16 pdatatowrite)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite16(pdatatowrite, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writew);
> +
> +s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddress;
> +	u32 preg_data;
> +
> +	paddress = pruss->ioaddr + offset;
> +
> +	spin_lock(&pruss->lock);
> +	preg_data = ioread16(paddress);
> +	preg_data &= ~mask;
> +	preg_data |= val;
> +	iowrite16(preg_data, paddress);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_rmww);
> +
> +s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +	*pdatatoread = ioread16(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readw);
> +
> +s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite32(value, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_idx_writel);
> +
> +static int pruss_mfd_add_devices(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mfd_cell *cell = pdev->dev.platform_data;
> +	s32 err, i, num_devices = 0;
> +
> +	for (i = 0; cell[i].name; i++) {
> +		err = mfd_add_devices(dev, 0, &cell[i], 1, NULL, 0);
> +		if (err) {
> +			dev_err(dev, "cannot add mfd cell: %s\n",
> +						cell[i].name);
> +			continue;
> +		}
> +		num_devices++;
> +		dev_info(dev, "mfd: added %s device\n", cell[i].name);
> +	}
> +
> +	return num_devices;
> +}
> +
> +static int __devinit pruss_probe(struct platform_device *pdev)
> +{
> +	struct pruss_priv *pruss_dev = NULL;
> +	s32 err;
> +
> +	pruss_dev = kzalloc(sizeof(struct pruss_priv), 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;
> +	}
> +	spin_lock_init(&pruss_dev->lock);
> +
> +	clk_enable(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 pruss_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct pruss_priv *pruss = dev_get_drvdata(dev);
> +
> +	mfd_remove_devices(dev);
> +	pruss_disable(dev, PRUCORE_0);
> +	pruss_disable(dev, PRUCORE_1);
> +	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 pruss_driver = {
> +	.probe	= pruss_probe,
> +	.remove	= __devexit_p(pruss_remove),
> +	.driver	= {
> +		.name	= "pruss_mfd",
> +		.owner	= THIS_MODULE,
> +	}
> +};
> +
> +static int __init pruss_init(void)
> +{
> +	return platform_driver_register(&pruss_driver);
> +}
> +module_init(pruss_init);
> +
> +static void __exit pruss_exit(void)
> +{
> +	platform_driver_unregister(&pruss_driver);
> +}
> +module_exit(pruss_exit);
> +
> +MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
> +MODULE_AUTHOR("Subhasish Ghosh");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
> new file mode 100644
> index 0000000..8ef25b3
> --- /dev/null
> +++ b/include/linux/mfd/pruss.h
> @@ -0,0 +1,130 @@
> +/*
> + * Copyright (C) 2010, 2011 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 "pruss_core.h"
> +
> +#define PRUSS_NUM0			PRUCORE_0
> +#define PRUSS_NUM1			PRUCORE_1
> +
> +#define PRUSS_PRU0_RAM_SZ		512
> +#define PRUSS_PRU1_RAM_SZ		512
> +#define PRUSS_PRU0_BASE_ADDRESS		0
> +#define PRUSS_PRU1_BASE_ADDRESS		0x2000
> +#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_HOSTMAP0_CHAN		(0x03020100)
> +#define PRU_INTC_HOSTMAP1_CHAN		(0x07060504)
> +#define PRU_INTC_HOSTMAP2_CHAN		(0x00000908)
> +
> +#define PRU_INTC_CHANMAP7_SYS_EVT31	(0x00000000)
> +#define PRU_INTC_CHANMAP8_FULL		(0x02020100)
> +#define PRU_INTC_CHANMAP9_FULL		(0x04040303)
> +#define PRU_INTC_CHANMAP10_FULL		(0x06060505)
> +#define PRU_INTC_CHANMAP11_FULL		(0x08080707)
> +#define PRU_INTC_CHANMAP12_FULL		(0x00010909)
> +#define PRU_INTC_CHANMAP8_HALF		(0x03020100)
> +#define PRU_INTC_CHANMAP9_HALF		(0x07060504)
> +#define PRU_INTC_CHANMAP10_HALF		(0x03020908)
> +#define PRU_INTC_CHANMAP11_HALF		(0x07060504)
> +#define PRU_INTC_CHANMAP12_HALF		(0x00010908)
> +#define PRU_INTC_REGMAP_MASK		(0xFFFFFFFF)
> +
> +s32 pruss_enable(struct device *dev, u8 pruss_num);
> +
> +s32 pruss_load(struct device *dev, u8 pruss_num,
> +	u32 *pruss_code, u32 code_size_in_words);
> +
> +s32 pruss_run(struct device *dev, u8 pruss_num);
> +
> +s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout);
> +
> +s32 pruss_disable(struct device *dev, u8 pruss_num);
> +
> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite);
> +
> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val);
> +
> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread);
> +
> +s32 pruss_readb_multi(struct device *dev, u32 offset,
> +		u8 *pdatatoread, u16 bytestoread);
> +
> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread);
> +
> +s32 pruss_readl_multi(struct device *dev, u32 offset,
> +		u32 *pdatatoread, u16 wordstoread);
> +
> +s32 pruss_writel(struct device *dev, u32 offset, u32 pdatatowrite);
> +
> +s32 pruss_writel_multi(struct device *dev, u32 offset,
> +		u32 *pdatatowrite, u16 wordstowrite);
> +
> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val);
> +
> +s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value);
> +
> +s32 pruss_writew(struct device *dev, u32 offset, u16 datatowrite);
> +
> +s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val);
> +
> +s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread);
> +
> +#endif	/* End _PRUSS_H_ */
> diff --git a/include/linux/mfd/pruss_core.h b/include/linux/mfd/pruss_core.h
> new file mode 100644
> index 0000000..48e2b99
> --- /dev/null
> +++ b/include/linux/mfd/pruss_core.h
> @@ -0,0 +1,128 @@
> +/*
> + * Copyright (C) 2010, 2011 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_CORE_H_
> +#define _PRUSS_CORE_H_
> +
> +#include <linux/types.h>
> +
> +#define PRUCORE_0		(0)
> +#define PRUCORE_1		(1)
> +
> +#define PRUCORE_CONTROL_PCRESETVAL_MASK			(0xFFFF0000u)
> +#define PRUCORE_CONTROL_PCRESETVAL_SHIFT		(0x00000010u)
> +#define PRUCORE_CONTROL_PCRESETVAL_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_RUNSTATE_MASK			(0x00008000u)
> +#define PRUCORE_CONTROL_RUNSTATE_SHIFT			(0x0000000Fu)
> +#define PRUCORE_CONTROL_RUNSTATE_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_RUNSTATE_HALT			(0x00000000u)
> +#define PRUCORE_CONTROL_RUNSTATE_RUN			(0x00000001u)
> +#define PRUCORE_CONTROL_SINGLESTEP_MASK			(0x00000100u)
> +#define PRUCORE_CONTROL_SINGLESTEP_SHIFT		(0x00000008u)
> +#define PRUCORE_CONTROL_SINGLESTEP_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_SINGLESTEP_FREERUN		(0x00000000u)
> +#define PRUCORE_CONTROL_SINGLESTEP_SINGLE		(0x00000001u)
> +#define PRUCORE_CONTROL_COUNTENABLE_MASK		(0x00000008u)
> +#define PRUCORE_CONTROL_COUNTENABLE_SHIFT		(0x00000003u)
> +#define PRUCORE_CONTROL_COUNTENABLE_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_COUNTENABLE_DISABLE		(0x00000000u)
> +#define PRUCORE_CONTROL_COUNTENABLE_ENABLE		(0x00000001u)
> +#define PRUCORE_CONTROL_SLEEPING_MASK			(0x00000004u)
> +#define PRUCORE_CONTROL_SLEEPING_SHIFT			(0x00000002u)
> +#define PRUCORE_CONTROL_SLEEPING_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_SLEEPING_NOTASLEEP		(0x00000000u)
> +#define PRUCORE_CONTROL_SLEEPING_ASLEEP			(0x00000001u)
> +#define PRUCORE_CONTROL_ENABLE_MASK			(0x00000002u)
> +#define PRUCORE_CONTROL_ENABLE_SHIFT			(0x00000001u)
> +#define PRUCORE_CONTROL_ENABLE_RESETVAL			(0x00000000u)
> +#define PRUCORE_CONTROL_ENABLE_DISABLE			(0x00000000u)
> +#define PRUCORE_CONTROL_ENABLE_ENABLE			(0x00000001u)
> +#define PRUCORE_CONTROL_SOFTRESET_MASK			(0x00000001u)
> +#define PRUCORE_CONTROL_SOFTRESET_SHIFT			(0x00000000u)
> +#define PRUCORE_CONTROL_SOFTRESET_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_SOFTRESET_RESET			(0x00000000u)
> +#define PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET		(0x00000001u)
> +#define PRUCORE_CONTROL_RESETVAL			(0x00000000u)
> +
> +struct prusscore_regs {
> +	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];
> +	u8  rsvd2[768];
> +};
> +
> +struct pruss_intc_regs {
> +	u32 revid;
> +	u32 control;
> +	u8  res1[8];
> +	u32 glblen;
> +	u8  res2[8];
> +	u32 glblnstlvl;
> +	u32 statidxset;
> +	u32 statidxclr;
> +	u32 enidxset;
> +	u32 enidxclr;
> +	u8  res3[4];
> +	u32 hostintenidxset;
> +	u32 hostintenidxclr;
> +	u8  res4[68];
> +	u32 glblpriidx;
> +	u8  res5[380];
> +	u32 statsetint[2];
> +	u8  res6[120];
> +	u32 statclrint[2];
> +	u8  res7[120];
> +	u32 enableset[2];
> +	u8  res8[120];
> +	u32 enableclr[2];
> +	u8  res9[120];
> +	u32 chanmap[16];
> +	u8  res10[960];
> +	u32 hostmap[2];
> +	u8  res11[248];
> +	u32 hostintpriidx[10];
> +	u8  res12[984];
> +	u32 polarity[2];
> +	u8  res13[120];
> +	u32 type[2];
> +	u8  res14[888];
> +	u32 hostintnstlvl[10];
> +	u8  res15[984];
> +	u32 hostinten;
> +	u8  res16[6907];
> +};
> +
> +struct pruss_map {
> +	u8 dram0[512];
> +	u8 res1[7680];
> +	u8 dram1[512];
> +	u8 res2[7680];
> +	struct pruss_intc_regs intc;
> +	struct prusscore_regs core[2];
> +	u8 iram0[4096];
> +	u8 res3[12288];
> +	u8 iram1[4096];
> +	u8 res4[12288];
> +};
> +#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 #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-22 16:00     ` Marc Kleine-Budde
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-22 16:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/22/2011 02:08 PM, Subhasish Ghosh wrote:
> This patch adds the pruss MFD driver and associated include files.
> For details regarding the PRUSS please refer the folowing link:
> http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem
> 
> The rational behind the MFD driver being the fact that multiple devices can
> be implemented on the cores independently. This is determined by the nature
> of the program which is loaded into the PRU's instruction memory.
> A device may be de-initialized and another loaded or two different devices
> can be run simultaneously on the two cores.
> It's also possible, as in our case, to implement a single device on both
> the PRU's resulting in improved load sharing.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
>  drivers/mfd/Kconfig            |   10 +
>  drivers/mfd/Makefile           |    1 +
>  drivers/mfd/pruss.c            |  513 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/pruss.h      |  130 ++++++++++
>  include/linux/mfd/pruss_core.h |  128 ++++++++++
>  5 files changed, 782 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mfd/pruss.c
>  create mode 100644 include/linux/mfd/pruss.h
>  create mode 100644 include/linux/mfd/pruss_core.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 0284c53..41479e4 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -92,6 +92,16 @@ config MFD_TI_SSP
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ti-ssp.
>  
> +config MFD_DA8XX_PRUSS
> +	tristate "Texas Instruments DA8XX PRUSS support"
> +	depends on ARCH_DAVINCI_DA850
> +	select MFD_CORE
> +	help
> +	  This driver provides support API 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 c56b6c7..8015dea 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)	+= pruss.o
>  obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
>  obj-$(CONFIG_MFD_TI_SSP)	+= ti-ssp.o
>  
> diff --git a/drivers/mfd/pruss.c b/drivers/mfd/pruss.c
> new file mode 100644
> index 0000000..6836d5a
> --- /dev/null
> +++ b/drivers/mfd/pruss.c
> @@ -0,0 +1,513 @@
> +/*
> + * Copyright (C) 2010, 2011 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/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/mfd/pruss.h>
> +#include <linux/mfd/core.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +
> +struct pruss_priv {
> +	struct device *dev;
> +	spinlock_t lock;
> +	struct resource *res;
> +	struct clk *clk;
> +	void __iomem *ioaddr;
> +};
> +
> +s32 pruss_disable(struct device *dev, u8 pruss_num)
make it a int function
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 temp_reg;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	spin_lock(&pruss->lock);
> +
> +	/* pruss deinit */
> +	iowrite32(0xFFFFFFFF, &pruss_mmap->intc.statclrint[pruss_num]);
> +
> +	/* Disable PRU */
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
> +			((PRUCORE_CONTROL_COUNTENABLE_DISABLE <<
> +			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
> +			PRUCORE_CONTROL_COUNTENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +		~PRUCORE_CONTROL_ENABLE_MASK) |
> +		((PRUCORE_CONTROL_ENABLE_DISABLE <<
> +		PRUCORE_CONTROL_ENABLE_SHIFT) &
> +		PRUCORE_CONTROL_ENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +
> +	/* Reset PRU */
> +	iowrite32(PRUCORE_CONTROL_RESETVAL,
> +				&h_pruss->control);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;

make it a void function?
> +}
> +EXPORT_SYMBOL_GPL(pruss_disable);
> +
> +s32 pruss_enable(struct device *dev, u8 pruss_num)
int?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 i;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	/* Reset PRU  */
> +	spin_lock(&pruss->lock);
> +	iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);

no need to lock the ram reset below?


> +	spin_unlock(&pruss->lock);
> +
> +	/* Reset any garbage in the ram */
> +	if (pruss_num == PRUCORE_0)
> +		for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram0[i]);
> +	else if (pruss_num == PRUCORE_1)
> +		for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram1[i]);

if you make a array for these

+struct pruss_map {
+	u8 dram0[512];
+	u8 res1[7680];

+	u8 dram1[512];
+	u8 res2[7680];
..}

you don't need the if..else..

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_enable);
> +
> +/* Load the specified PRU with code */
> +s32 pruss_load(struct device *dev, u8 pruss_num,
> +			u32 *pruss_code, u32 code_size_in_words)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 __iomem *pruss_iram;
> +	u32 i;
> +
> +	if (pruss_num == PRUCORE_0)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
> +	else if (pruss_num == PRUCORE_1)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
> +	else

same here
> +		return -EINVAL;
> +
> +	pruss_enable(dev, pruss_num);
> +
> +	spin_lock(&pruss->lock);
> +	/* Copy dMAX code to its instruction RAM  */
> +	for (i = 0; i < code_size_in_words; i++)
> +		iowrite32(pruss_code[i], (pruss_iram + i));
> +
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_load);
> +
> +s32 pruss_run(struct device *dev, u8 pruss_num)
int?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 temp_reg;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	/* Enable dMAX, let it execute the code we just copied */
> +	spin_lock(&pruss->lock);
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +			~PRUCORE_CONTROL_COUNTENABLE_MASK) |
> +			((PRUCORE_CONTROL_COUNTENABLE_ENABLE <<
> +			PRUCORE_CONTROL_COUNTENABLE_SHIFT) &
> +			PRUCORE_CONTROL_COUNTENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +
> +	temp_reg = ioread32(&h_pruss->control);
> +	temp_reg = (temp_reg &
> +			~PRUCORE_CONTROL_ENABLE_MASK) |
> +			((PRUCORE_CONTROL_ENABLE_ENABLE <<
> +			PRUCORE_CONTROL_ENABLE_SHIFT) &
> +			PRUCORE_CONTROL_ENABLE_MASK);
> +	iowrite32(temp_reg, &h_pruss->control);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_run);
> +
> +s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct prusscore_regs __iomem *h_pruss;
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 temp_reg;
> +	u32 cnt = timeout;
> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	while (cnt--) {
> +		temp_reg = ioread32(&h_pruss->control);
> +		if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
> +				PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
> +				PRUCORE_CONTROL_RUNSTATE_HALT)
> +			break;

how long might this take? what about some delay, sleep, or reschedule?

> +	}
> +	if (!cnt)
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_wait_for_halt);
> +
> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;

we usually don't use "p" variable names for pointers

> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite8(pdatatowrite, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writeb);
> +
> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
void function?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddress;
> +	u32 preg_data;
> +
> +	paddress = pruss->ioaddr + offset;
> +
> +	spin_lock(&pruss->lock);
> +	preg_data = ioread8(paddress);
> +	preg_data &= ~mask;
> +	preg_data |= val;
> +	iowrite8(preg_data, paddress);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_rmwb);
> +
> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset ;
> +	*pdatatoread = ioread8(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb);
> +
> +s32 pruss_readb_multi(struct device *dev, u32 offset,
> +		u8 *pdatatoread, u16 bytestoread)
viod?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u8 __iomem *paddresstoread;
> +	u16 i;
int?
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +
> +	for (i = 0; i < bytestoread; i++)
> +		*pdatatoread++ = ioread8(paddresstoread++);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb_multi);
> +
> +s32 pruss_writel(struct device *dev, u32 offset,
> +		u32 pdatatowrite)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite32(pdatatowrite, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writel);
> +
> +s32 pruss_writel_multi(struct device *dev, u32 offset,
> +		u32 *pdatatowrite, u16 wordstowrite)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u32 __iomem *paddresstowrite;
> +	u16 i;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +
> +	for (i = 0; i < wordstowrite; i++)
> +		iowrite32(*pdatatowrite++, paddresstowrite++);
memcopy_to_iomem?
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writel_multi);
> +
> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
void?
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddress;
> +	u32 preg_data;
> +
> +	paddress = pruss->ioaddr + offset;
> +
> +	spin_lock(&pruss->lock);
> +	preg_data = ioread32(paddress);
> +	preg_data &= ~mask;
> +	preg_data |= val;
> +	iowrite32(preg_data, paddress);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_rmwl);
> +
> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
void? or return the read value
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +	*pdatatoread = ioread32(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readl);
> +
> +s32 pruss_readl_multi(struct device *dev, u32 offset,
> +		u32 *pdatatoread, u16 wordstoread)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u32 __iomem *paddresstoread;
> +	u16 i;
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +	for (i = 0; i < wordstoread; i++)
> +		*pdatatoread++ = ioread32(paddresstoread++);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readl_multi);
> +
> +s32 pruss_writew(struct device *dev, u32 offset, u16 pdatatowrite)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite16(pdatatowrite, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writew);
> +
> +s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddress;
> +	u32 preg_data;
> +
> +	paddress = pruss->ioaddr + offset;
> +
> +	spin_lock(&pruss->lock);
> +	preg_data = ioread16(paddress);
> +	preg_data &= ~mask;
> +	preg_data |= val;
> +	iowrite16(preg_data, paddress);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_rmww);
> +
> +s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset;
> +	*pdatatoread = ioread16(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readw);
> +
> +s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +	iowrite32(value, paddresstowrite);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_idx_writel);
> +
> +static int pruss_mfd_add_devices(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mfd_cell *cell = pdev->dev.platform_data;
> +	s32 err, i, num_devices = 0;
> +
> +	for (i = 0; cell[i].name; i++) {
> +		err = mfd_add_devices(dev, 0, &cell[i], 1, NULL, 0);
> +		if (err) {
> +			dev_err(dev, "cannot add mfd cell: %s\n",
> +						cell[i].name);
> +			continue;
> +		}
> +		num_devices++;
> +		dev_info(dev, "mfd: added %s device\n", cell[i].name);
> +	}
> +
> +	return num_devices;
> +}
> +
> +static int __devinit pruss_probe(struct platform_device *pdev)
> +{
> +	struct pruss_priv *pruss_dev = NULL;
> +	s32 err;
> +
> +	pruss_dev = kzalloc(sizeof(struct pruss_priv), 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;
> +	}
> +	spin_lock_init(&pruss_dev->lock);
> +
> +	clk_enable(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 pruss_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct pruss_priv *pruss = dev_get_drvdata(dev);
> +
> +	mfd_remove_devices(dev);
> +	pruss_disable(dev, PRUCORE_0);
> +	pruss_disable(dev, PRUCORE_1);
> +	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 pruss_driver = {
> +	.probe	= pruss_probe,
> +	.remove	= __devexit_p(pruss_remove),
> +	.driver	= {
> +		.name	= "pruss_mfd",
> +		.owner	= THIS_MODULE,
> +	}
> +};
> +
> +static int __init pruss_init(void)
> +{
> +	return platform_driver_register(&pruss_driver);
> +}
> +module_init(pruss_init);
> +
> +static void __exit pruss_exit(void)
> +{
> +	platform_driver_unregister(&pruss_driver);
> +}
> +module_exit(pruss_exit);
> +
> +MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver");
> +MODULE_AUTHOR("Subhasish Ghosh");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/pruss.h b/include/linux/mfd/pruss.h
> new file mode 100644
> index 0000000..8ef25b3
> --- /dev/null
> +++ b/include/linux/mfd/pruss.h
> @@ -0,0 +1,130 @@
> +/*
> + * Copyright (C) 2010, 2011 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 "pruss_core.h"
> +
> +#define PRUSS_NUM0			PRUCORE_0
> +#define PRUSS_NUM1			PRUCORE_1
> +
> +#define PRUSS_PRU0_RAM_SZ		512
> +#define PRUSS_PRU1_RAM_SZ		512
> +#define PRUSS_PRU0_BASE_ADDRESS		0
> +#define PRUSS_PRU1_BASE_ADDRESS		0x2000
> +#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_HOSTMAP0_CHAN		(0x03020100)
> +#define PRU_INTC_HOSTMAP1_CHAN		(0x07060504)
> +#define PRU_INTC_HOSTMAP2_CHAN		(0x00000908)
> +
> +#define PRU_INTC_CHANMAP7_SYS_EVT31	(0x00000000)
> +#define PRU_INTC_CHANMAP8_FULL		(0x02020100)
> +#define PRU_INTC_CHANMAP9_FULL		(0x04040303)
> +#define PRU_INTC_CHANMAP10_FULL		(0x06060505)
> +#define PRU_INTC_CHANMAP11_FULL		(0x08080707)
> +#define PRU_INTC_CHANMAP12_FULL		(0x00010909)
> +#define PRU_INTC_CHANMAP8_HALF		(0x03020100)
> +#define PRU_INTC_CHANMAP9_HALF		(0x07060504)
> +#define PRU_INTC_CHANMAP10_HALF		(0x03020908)
> +#define PRU_INTC_CHANMAP11_HALF		(0x07060504)
> +#define PRU_INTC_CHANMAP12_HALF		(0x00010908)
> +#define PRU_INTC_REGMAP_MASK		(0xFFFFFFFF)
> +
> +s32 pruss_enable(struct device *dev, u8 pruss_num);
> +
> +s32 pruss_load(struct device *dev, u8 pruss_num,
> +	u32 *pruss_code, u32 code_size_in_words);
> +
> +s32 pruss_run(struct device *dev, u8 pruss_num);
> +
> +s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout);
> +
> +s32 pruss_disable(struct device *dev, u8 pruss_num);
> +
> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite);
> +
> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val);
> +
> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread);
> +
> +s32 pruss_readb_multi(struct device *dev, u32 offset,
> +		u8 *pdatatoread, u16 bytestoread);
> +
> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread);
> +
> +s32 pruss_readl_multi(struct device *dev, u32 offset,
> +		u32 *pdatatoread, u16 wordstoread);
> +
> +s32 pruss_writel(struct device *dev, u32 offset, u32 pdatatowrite);
> +
> +s32 pruss_writel_multi(struct device *dev, u32 offset,
> +		u32 *pdatatowrite, u16 wordstowrite);
> +
> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val);
> +
> +s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value);
> +
> +s32 pruss_writew(struct device *dev, u32 offset, u16 datatowrite);
> +
> +s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val);
> +
> +s32 pruss_readw(struct device *dev, u32 offset, u16 *pdatatoread);
> +
> +#endif	/* End _PRUSS_H_ */
> diff --git a/include/linux/mfd/pruss_core.h b/include/linux/mfd/pruss_core.h
> new file mode 100644
> index 0000000..48e2b99
> --- /dev/null
> +++ b/include/linux/mfd/pruss_core.h
> @@ -0,0 +1,128 @@
> +/*
> + * Copyright (C) 2010, 2011 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_CORE_H_
> +#define _PRUSS_CORE_H_
> +
> +#include <linux/types.h>
> +
> +#define PRUCORE_0		(0)
> +#define PRUCORE_1		(1)
> +
> +#define PRUCORE_CONTROL_PCRESETVAL_MASK			(0xFFFF0000u)
> +#define PRUCORE_CONTROL_PCRESETVAL_SHIFT		(0x00000010u)
> +#define PRUCORE_CONTROL_PCRESETVAL_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_RUNSTATE_MASK			(0x00008000u)
> +#define PRUCORE_CONTROL_RUNSTATE_SHIFT			(0x0000000Fu)
> +#define PRUCORE_CONTROL_RUNSTATE_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_RUNSTATE_HALT			(0x00000000u)
> +#define PRUCORE_CONTROL_RUNSTATE_RUN			(0x00000001u)
> +#define PRUCORE_CONTROL_SINGLESTEP_MASK			(0x00000100u)
> +#define PRUCORE_CONTROL_SINGLESTEP_SHIFT		(0x00000008u)
> +#define PRUCORE_CONTROL_SINGLESTEP_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_SINGLESTEP_FREERUN		(0x00000000u)
> +#define PRUCORE_CONTROL_SINGLESTEP_SINGLE		(0x00000001u)
> +#define PRUCORE_CONTROL_COUNTENABLE_MASK		(0x00000008u)
> +#define PRUCORE_CONTROL_COUNTENABLE_SHIFT		(0x00000003u)
> +#define PRUCORE_CONTROL_COUNTENABLE_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_COUNTENABLE_DISABLE		(0x00000000u)
> +#define PRUCORE_CONTROL_COUNTENABLE_ENABLE		(0x00000001u)
> +#define PRUCORE_CONTROL_SLEEPING_MASK			(0x00000004u)
> +#define PRUCORE_CONTROL_SLEEPING_SHIFT			(0x00000002u)
> +#define PRUCORE_CONTROL_SLEEPING_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_SLEEPING_NOTASLEEP		(0x00000000u)
> +#define PRUCORE_CONTROL_SLEEPING_ASLEEP			(0x00000001u)
> +#define PRUCORE_CONTROL_ENABLE_MASK			(0x00000002u)
> +#define PRUCORE_CONTROL_ENABLE_SHIFT			(0x00000001u)
> +#define PRUCORE_CONTROL_ENABLE_RESETVAL			(0x00000000u)
> +#define PRUCORE_CONTROL_ENABLE_DISABLE			(0x00000000u)
> +#define PRUCORE_CONTROL_ENABLE_ENABLE			(0x00000001u)
> +#define PRUCORE_CONTROL_SOFTRESET_MASK			(0x00000001u)
> +#define PRUCORE_CONTROL_SOFTRESET_SHIFT			(0x00000000u)
> +#define PRUCORE_CONTROL_SOFTRESET_RESETVAL		(0x00000000u)
> +#define PRUCORE_CONTROL_SOFTRESET_RESET			(0x00000000u)
> +#define PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET		(0x00000001u)
> +#define PRUCORE_CONTROL_RESETVAL			(0x00000000u)
> +
> +struct prusscore_regs {
> +	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];
> +	u8  rsvd2[768];
> +};
> +
> +struct pruss_intc_regs {
> +	u32 revid;
> +	u32 control;
> +	u8  res1[8];
> +	u32 glblen;
> +	u8  res2[8];
> +	u32 glblnstlvl;
> +	u32 statidxset;
> +	u32 statidxclr;
> +	u32 enidxset;
> +	u32 enidxclr;
> +	u8  res3[4];
> +	u32 hostintenidxset;
> +	u32 hostintenidxclr;
> +	u8  res4[68];
> +	u32 glblpriidx;
> +	u8  res5[380];
> +	u32 statsetint[2];
> +	u8  res6[120];
> +	u32 statclrint[2];
> +	u8  res7[120];
> +	u32 enableset[2];
> +	u8  res8[120];
> +	u32 enableclr[2];
> +	u8  res9[120];
> +	u32 chanmap[16];
> +	u8  res10[960];
> +	u32 hostmap[2];
> +	u8  res11[248];
> +	u32 hostintpriidx[10];
> +	u8  res12[984];
> +	u32 polarity[2];
> +	u8  res13[120];
> +	u32 type[2];
> +	u8  res14[888];
> +	u32 hostintnstlvl[10];
> +	u8  res15[984];
> +	u32 hostinten;
> +	u8  res16[6907];
> +};
> +
> +struct pruss_map {
> +	u8 dram0[512];
> +	u8 res1[7680];
> +	u8 dram1[512];
> +	u8 res2[7680];
> +	struct pruss_intc_regs intc;
> +	struct prusscore_regs core[2];
> +	u8 iram0[4096];
> +	u8 res3[12288];
> +	u8 iram1[4096];
> +	u8 res4[12288];
> +};
> +#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   |

-------------- 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/20110422/15a6ff63/attachment-0001.sig>

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

* Re: [PATCH v4 11/11] da850: pruss CAN board specific additions.
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-04-22 16:03     ` Marc Kleine-Budde
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-22 16:03 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, Kevin Hilman, sachi, Russell King,
	nsekhar, open list, m-watkins, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 3105 bytes --]

On 04/22/2011 02:08 PM, Subhasish Ghosh wrote:
> This patch adds the pruss CAN pinmux 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 |   46 +++++++++++++++++++++++++++++++
>  1 files changed, 46 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index e7fdf31..e1ff18c 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -48,6 +48,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)
>  
> @@ -1117,6 +1118,43 @@ static __init int da850_evm_init_cpufreq(void)
>  static __init int da850_evm_init_cpufreq(void) { return 0; }
>  #endif
>  
> +static const short da850_evm_pruss_can_pins[] = {
> +	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
> +	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
> +	-1
> +};
> +
> +static int __init da850_evm_pruss_can_setup(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);
> +
> +	/* 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;
> +}
> +
> +static struct da850_evm_pruss_can_data can_data = {
> +	.version	= 1,
> +	.setup		= da850_evm_pruss_can_setup,

I suggest to do the pinmux setup unconditionally before registering the
can driver. Rename setup into transceiver_switch and extend the driver
to switch on and off the transceiver. Call the transceiver switch from
open and close in the can drver.

> +};
> +
> +
>  static const short da850_evm_pruss_suart_pins[] = {
>  	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
>  	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
> @@ -1161,6 +1199,14 @@ static struct mfd_cell cell[] = {
>  		.resources	= da850_evm_pruss_suart_resource,
>  	},
>  	{
> +		.id		= 1,
> +		.name		= "da8xx_pruss_can",
> +		.platform_data	= &can_data,
> +		.data_size	= sizeof(can_data),
> +		.num_resources  = 0,
> +		.resources	= NULL,
> +	},
> +	{
>  		.name		= NULL,
>  	},
>  };

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

* [PATCH v4 11/11] da850: pruss CAN board specific additions.
@ 2011-04-22 16:03     ` Marc Kleine-Budde
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-22 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/22/2011 02:08 PM, Subhasish Ghosh wrote:
> This patch adds the pruss CAN pinmux 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 |   46 +++++++++++++++++++++++++++++++
>  1 files changed, 46 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index e7fdf31..e1ff18c 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
> @@ -48,6 +48,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)
>  
> @@ -1117,6 +1118,43 @@ static __init int da850_evm_init_cpufreq(void)
>  static __init int da850_evm_init_cpufreq(void) { return 0; }
>  #endif
>  
> +static const short da850_evm_pruss_can_pins[] = {
> +	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
> +	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
> +	-1
> +};
> +
> +static int __init da850_evm_pruss_can_setup(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);
> +
> +	/* 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;
> +}
> +
> +static struct da850_evm_pruss_can_data can_data = {
> +	.version	= 1,
> +	.setup		= da850_evm_pruss_can_setup,

I suggest to do the pinmux setup unconditionally before registering the
can driver. Rename setup into transceiver_switch and extend the driver
to switch on and off the transceiver. Call the transceiver switch from
open and close in the can drver.

> +};
> +
> +
>  static const short da850_evm_pruss_suart_pins[] = {
>  	DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
>  	DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
> @@ -1161,6 +1199,14 @@ static struct mfd_cell cell[] = {
>  		.resources	= da850_evm_pruss_suart_resource,
>  	},
>  	{
> +		.id		= 1,
> +		.name		= "da8xx_pruss_can",
> +		.platform_data	= &can_data,
> +		.data_size	= sizeof(can_data),
> +		.num_resources  = 0,
> +		.resources	= NULL,
> +	},
> +	{
>  		.name		= NULL,
>  	},
>  };

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/20110422/3613b9b9/attachment.sig>

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-04-25 21:20     ` Greg KH
  -1 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-04-25 21:20 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, m-watkins, nsekhar,
	sachi, Greg Kroah-Hartman, Andrew Morton, Randy Dunlap,
	open list

On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
> This patch adds support for the TTY compliant
> Soft-UART device emulated on PRUSS.
> 
> This patch depends on:
> davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
>             https://patchwork.kernel.org/patch/615681/
> davinci: changed SRAM allocator to shared ram.
>             https://patchwork.kernel.org/patch/549351/

Who is going to be applying these patches to the tree?

Should this driver go through a davinci subtree because of these
dependancies?

thanks,

greg k-h

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-25 21:20     ` Greg KH
  0 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-04-25 21:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
> This patch adds support for the TTY compliant
> Soft-UART device emulated on PRUSS.
> 
> This patch depends on:
> davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
>             https://patchwork.kernel.org/patch/615681/
> davinci: changed SRAM allocator to shared ram.
>             https://patchwork.kernel.org/patch/549351/

Who is going to be applying these patches to the tree?

Should this driver go through a davinci subtree because of these
dependancies?

thanks,

greg k-h

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

* RE: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-25 21:20     ` Greg KH
@ 2011-04-26  6:51       ` Nori, Sekhar
  -1 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-04-26  6:51 UTC (permalink / raw)
  To: Greg KH, Subhasish Ghosh
  Cc: davinci-linux-open-source, linux-arm-kernel, Watkins, Melissa,
	sachi, Greg Kroah-Hartman, Andrew Morton, Randy Dunlap,
	open list

On Tue, Apr 26, 2011 at 02:50:56, Greg KH wrote:
> On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
> > This patch adds support for the TTY compliant
> > Soft-UART device emulated on PRUSS.
> > 
> > This patch depends on:
> > davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
> >             https://patchwork.kernel.org/patch/615681/

This is already in mainline. Plus this patch
doesn't really seem to depend on this commit.

> > davinci: changed SRAM allocator to shared ram.
> >             https://patchwork.kernel.org/patch/549351/

There should be no build time dependency with this patch
(the above patch just changes which pool of SRAM the
allocation happens from)

But, this brings out an important dependency of the patch
calling platform specific sram allocator functions. There
has been SRAM allocator consolidation work done by Russell
and as a result the SRAM allocator API for DaVinci will
actually change. The driver should probably just get sram
space through platform data so that it doesn't depend on the
platform specific sram allocation function.

> 
> Who is going to be applying these patches to the tree?
> 
> Should this driver go through a davinci subtree because of these
> dependancies?

No, driver and platform changes can be merged separately
if the above aspect is taken care of. Russell has been
pushing back on merging driver patches through his tree
unless absolutely required.

Thanks,
Sekhar


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-26  6:51       ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-04-26  6:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 26, 2011 at 02:50:56, Greg KH wrote:
> On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
> > This patch adds support for the TTY compliant
> > Soft-UART device emulated on PRUSS.
> > 
> > This patch depends on:
> > davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
> >             https://patchwork.kernel.org/patch/615681/

This is already in mainline. Plus this patch
doesn't really seem to depend on this commit.

> > davinci: changed SRAM allocator to shared ram.
> >             https://patchwork.kernel.org/patch/549351/

There should be no build time dependency with this patch
(the above patch just changes which pool of SRAM the
allocation happens from)

But, this brings out an important dependency of the patch
calling platform specific sram allocator functions. There
has been SRAM allocator consolidation work done by Russell
and as a result the SRAM allocator API for DaVinci will
actually change. The driver should probably just get sram
space through platform data so that it doesn't depend on the
platform specific sram allocation function.

> 
> Who is going to be applying these patches to the tree?
> 
> Should this driver go through a davinci subtree because of these
> dependancies?

No, driver and platform changes can be merged separately
if the above aspect is taken care of. Russell has been
pushing back on merging driver patches through his tree
unless absolutely required.

Thanks,
Sekhar

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

* Re: [PATCH v4 11/11] da850: pruss CAN board specific additions.
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-04-26 10:57     ` Sergei Shtylyov
  -1 siblings, 0 replies; 166+ messages in thread
From: Sergei Shtylyov @ 2011-04-26 10:57 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, Kevin Hilman, sachi, Russell King,
	nsekhar, open list, m-watkins, linux-arm-kernel

Hello.

On 22-04-2011 16:08, Subhasish Ghosh wrote:

> This patch adds the pruss CAN pinmux 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 |   46 +++++++++++++++++++++++++++++++
>   1 files changed, 46 insertions(+), 0 deletions(-)

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index e7fdf31..e1ff18c 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
[...]
> @@ -1117,6 +1118,43 @@ static __init int da850_evm_init_cpufreq(void)
>   static __init int da850_evm_init_cpufreq(void) { return 0; }
>   #endif
>
> +static const short da850_evm_pruss_can_pins[] = {
> +	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
> +	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
> +	-1
> +};
> +
> +static int __init da850_evm_pruss_can_setup(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);

    Yet you continue to initialize... you should stop here I think.

> +	/* 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);

    Doesn't gpio_request_one() handle freeing GPIO on error?

WBR, Sergei

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

* [PATCH v4 11/11] da850: pruss CAN board specific additions.
@ 2011-04-26 10:57     ` Sergei Shtylyov
  0 siblings, 0 replies; 166+ messages in thread
From: Sergei Shtylyov @ 2011-04-26 10:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

On 22-04-2011 16:08, Subhasish Ghosh wrote:

> This patch adds the pruss CAN pinmux 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 |   46 +++++++++++++++++++++++++++++++
>   1 files changed, 46 insertions(+), 0 deletions(-)

> diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
> index e7fdf31..e1ff18c 100644
> --- a/arch/arm/mach-davinci/board-da850-evm.c
> +++ b/arch/arm/mach-davinci/board-da850-evm.c
[...]
> @@ -1117,6 +1118,43 @@ static __init int da850_evm_init_cpufreq(void)
>   static __init int da850_evm_init_cpufreq(void) { return 0; }
>   #endif
>
> +static const short da850_evm_pruss_can_pins[] = {
> +	DA850_PRUSS_PRU0_R31_0, DA850_PRUSS_PRU1_R30_15,
> +	DA850_PRUSS_PRU1_R31_18, DA850_GPIO2_0,
> +	-1
> +};
> +
> +static int __init da850_evm_pruss_can_setup(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);

    Yet you continue to initialize... you should stop here I think.

> +	/* 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);

    Doesn't gpio_request_one() handle freeing GPIO on error?

WBR, Sergei

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

* Re: [PATCH v4 03/11] da850: pruss platform specific additions.
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-04-26 11:06     ` Sergei Shtylyov
  -1 siblings, 0 replies; 166+ messages in thread
From: Sergei Shtylyov @ 2011-04-26 11:06 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:15/17=88%),
	Russell King (maintainer:ARM PORT),
	Michael Williamson (commit_signer:6/17=35%),
	Cyril Chemparathy (commit_signer:3/17=18%),
	Sergei Shtylyov (commit_signer:2/17=12%),
	open list

Hello.

On 22-04-2011 16:08, Subhasish Ghosh wrote:

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

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

[...]

> diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
> index 09b8ddb..0c23035 100644
> --- a/arch/arm/mach-davinci/include/mach/da8xx.h
> +++ b/arch/arm/mach-davinci/include/mach/da8xx.h
[...]
>   #include<mach/edma.h>
> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>   #define DA8XX_DDR2_CTL_BASE	0xb0000000
>   #define DA8XX_ARM_RAM_BASE	0xffff0000
>   #define DA8XX_SHARED_RAM_BASE	0x80000000
> +#define DA8XX_PRUSS_MEM_BASE	0x01C30000

    Keep the list sorted please. Also, this macro doesn't seem used outside 
devices-da8xx.c, so should be moved there...

WBR, Sergei

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

* [PATCH v4 03/11] da850: pruss platform specific additions.
@ 2011-04-26 11:06     ` Sergei Shtylyov
  0 siblings, 0 replies; 166+ messages in thread
From: Sergei Shtylyov @ 2011-04-26 11:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

On 22-04-2011 16:08, Subhasish Ghosh wrote:

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

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

[...]

> diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
> index 09b8ddb..0c23035 100644
> --- a/arch/arm/mach-davinci/include/mach/da8xx.h
> +++ b/arch/arm/mach-davinci/include/mach/da8xx.h
[...]
>   #include<mach/edma.h>
> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>   #define DA8XX_DDR2_CTL_BASE	0xb0000000
>   #define DA8XX_ARM_RAM_BASE	0xffff0000
>   #define DA8XX_SHARED_RAM_BASE	0x80000000
> +#define DA8XX_PRUSS_MEM_BASE	0x01C30000

    Keep the list sorted please. Also, this macro doesn't seem used outside 
devices-da8xx.c, so should be moved there...

WBR, Sergei

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-26  6:51       ` Nori, Sekhar
@ 2011-04-26 12:45         ` Greg KH
  -1 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-04-26 12:45 UTC (permalink / raw)
  To: Nori, Sekhar
  Cc: Greg KH, Subhasish Ghosh, davinci-linux-open-source,
	linux-arm-kernel, Watkins, Melissa, sachi, Andrew Morton,
	Randy Dunlap, open list

On Tue, Apr 26, 2011 at 12:21:04PM +0530, Nori, Sekhar wrote:
> On Tue, Apr 26, 2011 at 02:50:56, Greg KH wrote:
> > On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
> > > This patch adds support for the TTY compliant
> > > Soft-UART device emulated on PRUSS.
> > > 
> > > This patch depends on:
> > > davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
> > >             https://patchwork.kernel.org/patch/615681/
> 
> This is already in mainline. Plus this patch
> doesn't really seem to depend on this commit.
> 
> > > davinci: changed SRAM allocator to shared ram.
> > >             https://patchwork.kernel.org/patch/549351/
> 
> There should be no build time dependency with this patch
> (the above patch just changes which pool of SRAM the
> allocation happens from)
> 
> But, this brings out an important dependency of the patch
> calling platform specific sram allocator functions. There
> has been SRAM allocator consolidation work done by Russell
> and as a result the SRAM allocator API for DaVinci will
> actually change. The driver should probably just get sram
> space through platform data so that it doesn't depend on the
> platform specific sram allocation function.

Ok, care to fix up the code then?

> > Who is going to be applying these patches to the tree?
> > 
> > Should this driver go through a davinci subtree because of these
> > dependancies?
> 
> No, driver and platform changes can be merged separately
> if the above aspect is taken care of. Russell has been
> pushing back on merging driver patches through his tree
> unless absolutely required.

That's fine, I'll take it through my tree then, care to resolve the
above issue and resend it?

thanks,

greg k-h

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-26 12:45         ` Greg KH
  0 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-04-26 12:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 26, 2011 at 12:21:04PM +0530, Nori, Sekhar wrote:
> On Tue, Apr 26, 2011 at 02:50:56, Greg KH wrote:
> > On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
> > > This patch adds support for the TTY compliant
> > > Soft-UART device emulated on PRUSS.
> > > 
> > > This patch depends on:
> > > davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
> > >             https://patchwork.kernel.org/patch/615681/
> 
> This is already in mainline. Plus this patch
> doesn't really seem to depend on this commit.
> 
> > > davinci: changed SRAM allocator to shared ram.
> > >             https://patchwork.kernel.org/patch/549351/
> 
> There should be no build time dependency with this patch
> (the above patch just changes which pool of SRAM the
> allocation happens from)
> 
> But, this brings out an important dependency of the patch
> calling platform specific sram allocator functions. There
> has been SRAM allocator consolidation work done by Russell
> and as a result the SRAM allocator API for DaVinci will
> actually change. The driver should probably just get sram
> space through platform data so that it doesn't depend on the
> platform specific sram allocation function.

Ok, care to fix up the code then?

> > Who is going to be applying these patches to the tree?
> > 
> > Should this driver go through a davinci subtree because of these
> > dependancies?
> 
> No, driver and platform changes can be merged separately
> if the above aspect is taken care of. Russell has been
> pushing back on merging driver patches through his tree
> unless absolutely required.

That's fine, I'll take it through my tree then, care to resolve the
above issue and resend it?

thanks,

greg k-h

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-26 12:45         ` Greg KH
@ 2011-04-27  5:23           ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  5:23 UTC (permalink / raw)
  To: Greg KH, Nori, Sekhar
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

>> There should be no build time dependency with this patch
>> (the above patch just changes which pool of SRAM the
>> allocation happens from)
>>
>> But, this brings out an important dependency of the patch
>> calling platform specific sram allocator functions. There
>> has been SRAM allocator consolidation work done by Russell
>> and as a result the SRAM allocator API for DaVinci will
>> actually change.

I earlier had an implementation where I would get the sram memory addresses
through the .resource structure and ioremap it in the driver.

>>The driver should probably just get sram
>> space through platform data so that it doesn't depend on the
>> platform specific sram allocation function.

Are you suggesting that I go back to that implementation.
Also, should I remove the dependency list from the patch comments then.


--------------------------------------------------
From: "Greg KH" <gregkh@suse.de>
Sent: Tuesday, April 26, 2011 6:15 PM
To: "Nori, Sekhar" <nsekhar@ti.com>
Cc: "Greg KH" <greg@kroah.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; 
<linux-arm-kernel@lists.infradead.org>; "Watkins, Melissa" 
<m-watkins@ti.com>; <sachi@mistralsolutions.com>; "Andrew Morton" 
<akpm@linux-foundation.org>; "Randy Dunlap" <randy.dunlap@oracle.com>; "open 
list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v4 08/11] tty: add pruss SUART driver

> On Tue, Apr 26, 2011 at 12:21:04PM +0530, Nori, Sekhar wrote:
>> On Tue, Apr 26, 2011 at 02:50:56, Greg KH wrote:
>> > On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
>> > > This patch adds support for the TTY compliant
>> > > Soft-UART device emulated on PRUSS.
>> > >
>> > > This patch depends on:
>> > > davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
>> > >             https://patchwork.kernel.org/patch/615681/
>>
>> This is already in mainline. Plus this patch
>> doesn't really seem to depend on this commit.
>>
>> > > davinci: changed SRAM allocator to shared ram.
>> > >             https://patchwork.kernel.org/patch/549351/
>>
>> There should be no build time dependency with this patch
>> (the above patch just changes which pool of SRAM the
>> allocation happens from)
>>
>> But, this brings out an important dependency of the patch
>> calling platform specific sram allocator functions. There
>> has been SRAM allocator consolidation work done by Russell
>> and as a result the SRAM allocator API for DaVinci will
>> actually change. The driver should probably just get sram
>> space through platform data so that it doesn't depend on the
>> platform specific sram allocation function.
>
> Ok, care to fix up the code then?
>
>> > Who is going to be applying these patches to the tree?
>> >
>> > Should this driver go through a davinci subtree because of these
>> > dependancies?
>>
>> No, driver and platform changes can be merged separately
>> if the above aspect is taken care of. Russell has been
>> pushing back on merging driver patches through his tree
>> unless absolutely required.
>
> That's fine, I'll take it through my tree then, care to resolve the
> above issue and resend it?
>
> thanks,
>
> greg k-h 


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-27  5:23           ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  5:23 UTC (permalink / raw)
  To: linux-arm-kernel

>> There should be no build time dependency with this patch
>> (the above patch just changes which pool of SRAM the
>> allocation happens from)
>>
>> But, this brings out an important dependency of the patch
>> calling platform specific sram allocator functions. There
>> has been SRAM allocator consolidation work done by Russell
>> and as a result the SRAM allocator API for DaVinci will
>> actually change.

I earlier had an implementation where I would get the sram memory addresses
through the .resource structure and ioremap it in the driver.

>>The driver should probably just get sram
>> space through platform data so that it doesn't depend on the
>> platform specific sram allocation function.

Are you suggesting that I go back to that implementation.
Also, should I remove the dependency list from the patch comments then.


--------------------------------------------------
From: "Greg KH" <gregkh@suse.de>
Sent: Tuesday, April 26, 2011 6:15 PM
To: "Nori, Sekhar" <nsekhar@ti.com>
Cc: "Greg KH" <greg@kroah.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; 
<davinci-linux-open-source@linux.davincidsp.com>; 
<linux-arm-kernel@lists.infradead.org>; "Watkins, Melissa" 
<m-watkins@ti.com>; <sachi@mistralsolutions.com>; "Andrew Morton" 
<akpm@linux-foundation.org>; "Randy Dunlap" <randy.dunlap@oracle.com>; "open 
list" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v4 08/11] tty: add pruss SUART driver

> On Tue, Apr 26, 2011 at 12:21:04PM +0530, Nori, Sekhar wrote:
>> On Tue, Apr 26, 2011 at 02:50:56, Greg KH wrote:
>> > On Fri, Apr 22, 2011 at 05:38:26PM +0530, Subhasish Ghosh wrote:
>> > > This patch adds support for the TTY compliant
>> > > Soft-UART device emulated on PRUSS.
>> > >
>> > > This patch depends on:
>> > > davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
>> > >             https://patchwork.kernel.org/patch/615681/
>>
>> This is already in mainline. Plus this patch
>> doesn't really seem to depend on this commit.
>>
>> > > davinci: changed SRAM allocator to shared ram.
>> > >             https://patchwork.kernel.org/patch/549351/
>>
>> There should be no build time dependency with this patch
>> (the above patch just changes which pool of SRAM the
>> allocation happens from)
>>
>> But, this brings out an important dependency of the patch
>> calling platform specific sram allocator functions. There
>> has been SRAM allocator consolidation work done by Russell
>> and as a result the SRAM allocator API for DaVinci will
>> actually change. The driver should probably just get sram
>> space through platform data so that it doesn't depend on the
>> platform specific sram allocation function.
>
> Ok, care to fix up the code then?
>
>> > Who is going to be applying these patches to the tree?
>> >
>> > Should this driver go through a davinci subtree because of these
>> > dependancies?
>>
>> No, driver and platform changes can be merged separately
>> if the above aspect is taken care of. Russell has been
>> pushing back on merging driver patches through his tree
>> unless absolutely required.
>
> That's fine, I'll take it through my tree then, care to resolve the
> above issue and resend it?
>
> thanks,
>
> greg k-h 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-22 16:00     ` Marc Kleine-Budde
@ 2011-04-27  6:39       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  6:39 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: davinci-linux-open-source, sachi, Samuel Ortiz, nsekhar,
	open list, m-watkins, linux-arm-kernel

Hi Mark,


- Is it ok to have u32 etc for __iomem cookie ?

> +
> +s32 pruss_disable(struct device *dev, u8 pruss_num)
make it a int function

SG -- Ok will do

> +
> +	/* Reset PRU */
> +	iowrite32(PRUCORE_CONTROL_RESETVAL,
> +				&h_pruss->control);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;

make it a void function?

SG -- This should be int, in case of invalid pru num, we ret an error.


> +}
> +EXPORT_SYMBOL_GPL(pruss_disable);
> +
> +s32 pruss_enable(struct device *dev, u8 pruss_num)
int?

SG -- Ok will do


> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	/* Reset PRU  */
> +	spin_lock(&pruss->lock);
> +	iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);

no need to lock the ram reset below?

SG -- I don't think its required. We just reset the RAM during init and 
since each pru can only be attached to only one device, the access
        will be already serialized based upon the pru num.


> +	/* Reset any garbage in the ram */
> +	if (pruss_num == PRUCORE_0)
> +		for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram0[i]);
> +	else if (pruss_num == PRUCORE_1)
> +		for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram1[i]);
if you make a array for these
+struct pruss_map {
+	u8 dram0[512];
+	u8 res1[7680];

+	u8 dram1[512];
+	u8 res2[7680];
..}
you don't need the if..else..

SG - The dram/iram is not contiguous, there is a reserved space in between, 
how do I declare an array for it.


> +/* Load the specified PRU with code */
> +s32 pruss_load(struct device *dev, u8 pruss_num,
> +			u32 *pruss_code, u32 code_size_in_words)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 __iomem *pruss_iram;
> +	u32 i;
> +
> +	if (pruss_num == PRUCORE_0)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
> +	else if (pruss_num == PRUCORE_1)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
> +	else
same here

SG - same here.


> +s32 pruss_run(struct device *dev, u8 pruss_num)
int?

SG - Ok, Will do.


> +	while (cnt--) {
> +		temp_reg = ioread32(&h_pruss->control);
> +		if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
> +				PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
> +				PRUCORE_CONTROL_RUNSTATE_HALT)
> +			break;
how long might this take? what about some delay, sleep, or reschedule?

SG - This does not take more than 10 to 20 counts,


> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
we usually don't use "p" variable names for pointers

SG - Ok, will remove.


> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
void function?

SG - Ok, will do.

> +
> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
void?

SG - Ok, will do.

> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset ;
> +	*pdatatoread = ioread8(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb);
> +
> +s32 pruss_readb_multi(struct device *dev, u32 offset,
> +		u8 *pdatatoread, u16 bytestoread)
viod?

SG - Ok, will do.

> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u8 __iomem *paddresstoread;
> +	u16 i;
int?

SG - Ok, will do.



> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb_multi);
> +
> +s32 pruss_writel(struct device *dev, u32 offset,
> +		u32 pdatatowrite)
void?

SG - Ok, will do.


> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writel);
> +
> +s32 pruss_writel_multi(struct device *dev, u32 offset,
> +		u32 *pdatatowrite, u16 wordstowrite)
void?

SG - Ok, will do.

> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u32 __iomem *paddresstowrite;
> +	u16 i;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +
> +	for (i = 0; i < wordstowrite; i++)
> +		iowrite32(*pdatatowrite++, paddresstowrite++);
memcopy_to_iomem?

SG -- I did not understand, could you please elaborate.


> +
> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
void?

SG - Ok, will do.


> +}
> +EXPORT_SYMBOL_GPL(pruss_rmwl);
> +
> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
void? or return the read value

SG - Ok, will do.

 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27  6:39       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  6:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mark,


- Is it ok to have u32 etc for __iomem cookie ?

> +
> +s32 pruss_disable(struct device *dev, u8 pruss_num)
make it a int function

SG -- Ok will do

> +
> +	/* Reset PRU */
> +	iowrite32(PRUCORE_CONTROL_RESETVAL,
> +				&h_pruss->control);
> +	spin_unlock(&pruss->lock);
> +
> +	return 0;

make it a void function?

SG -- This should be int, in case of invalid pru num, we ret an error.


> +}
> +EXPORT_SYMBOL_GPL(pruss_disable);
> +
> +s32 pruss_enable(struct device *dev, u8 pruss_num)
int?

SG -- Ok will do


> +
> +	if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
> +		return -EINVAL;
> +
> +	h_pruss = &pruss_mmap->core[pruss_num];
> +
> +	/* Reset PRU  */
> +	spin_lock(&pruss->lock);
> +	iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);

no need to lock the ram reset below?

SG -- I don't think its required. We just reset the RAM during init and 
since each pru can only be attached to only one device, the access
        will be already serialized based upon the pru num.


> +	/* Reset any garbage in the ram */
> +	if (pruss_num == PRUCORE_0)
> +		for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram0[i]);
> +	else if (pruss_num == PRUCORE_1)
> +		for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
> +			iowrite32(0x0, &pruss_mmap->dram1[i]);
if you make a array for these
+struct pruss_map {
+	u8 dram0[512];
+	u8 res1[7680];

+	u8 dram1[512];
+	u8 res2[7680];
..}
you don't need the if..else..

SG - The dram/iram is not contiguous, there is a reserved space in between, 
how do I declare an array for it.


> +/* Load the specified PRU with code */
> +s32 pruss_load(struct device *dev, u8 pruss_num,
> +			u32 *pruss_code, u32 code_size_in_words)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
> +	u32 __iomem *pruss_iram;
> +	u32 i;
> +
> +	if (pruss_num == PRUCORE_0)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
> +	else if (pruss_num == PRUCORE_1)
> +		pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
> +	else
same here

SG - same here.


> +s32 pruss_run(struct device *dev, u8 pruss_num)
int?

SG - Ok, Will do.


> +	while (cnt--) {
> +		temp_reg = ioread32(&h_pruss->control);
> +		if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
> +				PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
> +				PRUCORE_CONTROL_RUNSTATE_HALT)
> +			break;
how long might this take? what about some delay, sleep, or reschedule?

SG - This does not take more than 10 to 20 counts,


> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstowrite;
we usually don't use "p" variable names for pointers

SG - Ok, will remove.


> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
void function?

SG - Ok, will do.

> +
> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
void?

SG - Ok, will do.

> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	void __iomem *paddresstoread;
> +
> +	paddresstoread = pruss->ioaddr + offset ;
> +	*pdatatoread = ioread8(paddresstoread);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb);
> +
> +s32 pruss_readb_multi(struct device *dev, u32 offset,
> +		u8 *pdatatoread, u16 bytestoread)
viod?

SG - Ok, will do.

> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u8 __iomem *paddresstoread;
> +	u16 i;
int?

SG - Ok, will do.



> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_readb_multi);
> +
> +s32 pruss_writel(struct device *dev, u32 offset,
> +		u32 pdatatowrite)
void?

SG - Ok, will do.


> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pruss_writel);
> +
> +s32 pruss_writel_multi(struct device *dev, u32 offset,
> +		u32 *pdatatowrite, u16 wordstowrite)
void?

SG - Ok, will do.

> +{
> +	struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> +	u32 __iomem *paddresstowrite;
> +	u16 i;
> +
> +	paddresstowrite = pruss->ioaddr + offset;
> +
> +	for (i = 0; i < wordstowrite; i++)
> +		iowrite32(*pdatatowrite++, paddresstowrite++);
memcopy_to_iomem?

SG -- I did not understand, could you please elaborate.


> +
> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
void?

SG - Ok, will do.


> +}
> +EXPORT_SYMBOL_GPL(pruss_rmwl);
> +
> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
void? or return the read value

SG - Ok, will do.

 

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

* Re: [PATCH v4 03/11] da850: pruss platform specific additions.
  2011-04-26 11:06     ` Sergei Shtylyov
@ 2011-04-27  6:43       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  6:43 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:15/17=88%),
	Russell King (maintainer:ARM PORT),
	Michael Williamson (commit_signer:6/17=35%),
	Cyril Chemparathy (commit_signer:3/17=18%),
	Sergei Shtylyov (commit_signer:2/17=12%),
	open list


>>   #include<mach/edma.h>
>> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>>   #define DA8XX_DDR2_CTL_BASE 0xb0000000
>>   #define DA8XX_ARM_RAM_BASE 0xffff0000
>>   #define DA8XX_SHARED_RAM_BASE 0x80000000
>> +#define DA8XX_PRUSS_MEM_BASE 0x01C30000
>
>    Keep the list sorted please. Also, this macro doesn't seem used outside 
> devices-da8xx.c, so should be moved there...

SG - But would it not be better to have all device addresses at the same 
place.
 


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

* [PATCH v4 03/11] da850: pruss platform specific additions.
@ 2011-04-27  6:43       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  6:43 UTC (permalink / raw)
  To: linux-arm-kernel


>>   #include<mach/edma.h>
>> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>>   #define DA8XX_DDR2_CTL_BASE 0xb0000000
>>   #define DA8XX_ARM_RAM_BASE 0xffff0000
>>   #define DA8XX_SHARED_RAM_BASE 0x80000000
>> +#define DA8XX_PRUSS_MEM_BASE 0x01C30000
>
>    Keep the list sorted please. Also, this macro doesn't seem used outside 
> devices-da8xx.c, so should be moved there...

SG - But would it not be better to have all device addresses at the same 
place.
 

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

* Re: [PATCH v4 11/11] da850: pruss CAN board specific additions.
  2011-04-26 10:57     ` Sergei Shtylyov
@ 2011-04-27  7:03       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  7:03 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: davinci-linux-open-source, Kevin Hilman, sachi, Russell King,
	nsekhar, open list, m-watkins, linux-arm-kernel


>> +static int __init da850_evm_pruss_can_setup(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);
>
>    Yet you continue to initialize... you should stop here I think.

SG - Ok, will ret error.

>
>> + /* 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);
>
>    Doesn't gpio_request_one() handle freeing GPIO on error?

SG - It does handle error, will remove. But I have another problem,
        Suppose the init failed due to some other reason during probe.
        How can I do a gpio_free, do I need some kind of deinit for the 
setup ?

 


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

* [PATCH v4 11/11] da850: pruss CAN board specific additions.
@ 2011-04-27  7:03       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27  7:03 UTC (permalink / raw)
  To: linux-arm-kernel


>> +static int __init da850_evm_pruss_can_setup(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);
>
>    Yet you continue to initialize... you should stop here I think.

SG - Ok, will ret error.

>
>> + /* 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);
>
>    Doesn't gpio_request_one() handle freeing GPIO on error?

SG - It does handle error, will remove. But I have another problem,
        Suppose the init failed due to some other reason during probe.
        How can I do a gpio_free, do I need some kind of deinit for the 
setup ?

 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27  6:39       ` Subhasish Ghosh
@ 2011-04-27  7:29         ` Marc Kleine-Budde
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-27  7:29 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, sachi, Samuel Ortiz, nsekhar,
	open list, m-watkins, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 6277 bytes --]

On 04/27/2011 08:39 AM, Subhasish Ghosh wrote:
> Hi Mark,

I'm Marc.

> - Is it ok to have u32 etc for __iomem cookie ?

no - "void __iomem *" is "void __iomem *"


>> +s32 pruss_disable(struct device *dev, u8 pruss_num)
> make it a int function
> 
> SG -- Ok will do
> 
>> +
>> +    /* Reset PRU */
>> +    iowrite32(PRUCORE_CONTROL_RESETVAL,
>> +                &h_pruss->control);
>> +    spin_unlock(&pruss->lock);
>> +
>> +    return 0;
> 
> make it a void function?
> 
> SG -- This should be int, in case of invalid pru num, we ret an error.

Yes - Sorry.

>> +}
>> +EXPORT_SYMBOL_GPL(pruss_disable);
>> +
>> +s32 pruss_enable(struct device *dev, u8 pruss_num)
> int?
> 
> SG -- Ok will do
> 
> 
>> +
>> +    if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
>> +        return -EINVAL;
>> +
>> +    h_pruss = &pruss_mmap->core[pruss_num];
>> +
>> +    /* Reset PRU  */
>> +    spin_lock(&pruss->lock);
>> +    iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);
> 
> no need to lock the ram reset below?
> 
> SG -- I don't think its required. We just reset the RAM during init and
> since each pru can only be attached to only one device, the access
>        will be already serialized based upon the pru num.

In the other function you lock the access to the ram, but not here.

>> +    /* Reset any garbage in the ram */
>> +    if (pruss_num == PRUCORE_0)
>> +        for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
>> +            iowrite32(0x0, &pruss_mmap->dram0[i]);
>> +    else if (pruss_num == PRUCORE_1)
>> +        for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
>> +            iowrite32(0x0, &pruss_mmap->dram1[i]);
> if you make a array for these
> +struct pruss_map {
> +    u8 dram0[512];
> +    u8 res1[7680];
> 
> +    u8 dram1[512];
> +    u8 res2[7680];
> ..}
> you don't need the if..else..
> 
> SG - The dram/iram is not contiguous, there is a reserved space in
> between, how do I declare an array for it.

This is the struct you have:

struct pruss_map {
	u8 dram0[512];
	u8 res1[7680];

	u8 dram1[512];
	u8 res2[7680];
...
}

If you want to describe the ram with an array it translates to:

struct pruss_dram {
	u8 dram[512];
	u8 res[7680];
};

struct pruss_map {
	struct pruss_dram[2];
...
};

BTW: Why do you declare the dram as "u8" "u32" seems more natural to me.

>> +/* Load the specified PRU with code */
>> +s32 pruss_load(struct device *dev, u8 pruss_num,
>> +            u32 *pruss_code, u32 code_size_in_words)
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
>> +    u32 __iomem *pruss_iram;
>> +    u32 i;
>> +
>> +    if (pruss_num == PRUCORE_0)
>> +        pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
>> +    else if (pruss_num == PRUCORE_1)
>> +        pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
>> +    else
> same here
> 
> SG - same here.

same here :)

>> +s32 pruss_run(struct device *dev, u8 pruss_num)
> int?
> 
> SG - Ok, Will do.
> 
> 
>> +    while (cnt--) {
>> +        temp_reg = ioread32(&h_pruss->control);
>> +        if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
>> +                PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
>> +                PRUCORE_CONTROL_RUNSTATE_HALT)
>> +            break;
> how long might this take? what about some delay, sleep, or reschedule?
> 
> SG - This does not take more than 10 to 20 counts,

Does it make sense, that the timeout is a parameter to that function?

> 
> 
>> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    void __iomem *paddresstowrite;
> we usually don't use "p" variable names for pointers
> 
> SG - Ok, will remove.
> 
> 
>> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
> void function?
> 
> SG - Ok, will do.
> 
>> +
>> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
> void?
> 
> SG - Ok, will do.
> 
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    void __iomem *paddresstoread;
>> +
>> +    paddresstoread = pruss->ioaddr + offset ;
>> +    *pdatatoread = ioread8(paddresstoread);
>> +
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_readb);
>> +
>> +s32 pruss_readb_multi(struct device *dev, u32 offset,
>> +        u8 *pdatatoread, u16 bytestoread)
> viod?
> 
> SG - Ok, will do.
> 
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    u8 __iomem *paddresstoread;
>> +    u16 i;
> int?
> 
> SG - Ok, will do.
> 
> 
> 
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_readb_multi);
>> +
>> +s32 pruss_writel(struct device *dev, u32 offset,
>> +        u32 pdatatowrite)
> void?
> 
> SG - Ok, will do.
> 
> 
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_writel);
>> +
>> +s32 pruss_writel_multi(struct device *dev, u32 offset,
>> +        u32 *pdatatowrite, u16 wordstowrite)
> void?
> 
> SG - Ok, will do.
> 
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    u32 __iomem *paddresstowrite;
>> +    u16 i;
>> +
>> +    paddresstowrite = pruss->ioaddr + offset;
>> +
>> +    for (i = 0; i < wordstowrite; i++)
>> +        iowrite32(*pdatatowrite++, paddresstowrite++);
> memcopy_to_iomem?
> 
> SG -- I did not understand, could you please elaborate.

You could use memcpy_toio() - although it seems it does copy bytes
internally.

http://lxr.linux.no/linux+v2.6.38/arch/arm/include/asm/io.h#L222
> 
> 
>> +
>> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
> void?
> 
> SG - Ok, will do.
> 
> 
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_rmwl);
>> +
>> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
> void? or return the read value
> 
> SG - Ok, will do.
> 
> 
> 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27  7:29         ` Marc Kleine-Budde
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-27  7:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/27/2011 08:39 AM, Subhasish Ghosh wrote:
> Hi Mark,

I'm Marc.

> - Is it ok to have u32 etc for __iomem cookie ?

no - "void __iomem *" is "void __iomem *"


>> +s32 pruss_disable(struct device *dev, u8 pruss_num)
> make it a int function
> 
> SG -- Ok will do
> 
>> +
>> +    /* Reset PRU */
>> +    iowrite32(PRUCORE_CONTROL_RESETVAL,
>> +                &h_pruss->control);
>> +    spin_unlock(&pruss->lock);
>> +
>> +    return 0;
> 
> make it a void function?
> 
> SG -- This should be int, in case of invalid pru num, we ret an error.

Yes - Sorry.

>> +}
>> +EXPORT_SYMBOL_GPL(pruss_disable);
>> +
>> +s32 pruss_enable(struct device *dev, u8 pruss_num)
> int?
> 
> SG -- Ok will do
> 
> 
>> +
>> +    if ((pruss_num != PRUCORE_0) && (pruss_num != PRUCORE_1))
>> +        return -EINVAL;
>> +
>> +    h_pruss = &pruss_mmap->core[pruss_num];
>> +
>> +    /* Reset PRU  */
>> +    spin_lock(&pruss->lock);
>> +    iowrite32(PRUCORE_CONTROL_RESETVAL, &h_pruss->control);
> 
> no need to lock the ram reset below?
> 
> SG -- I don't think its required. We just reset the RAM during init and
> since each pru can only be attached to only one device, the access
>        will be already serialized based upon the pru num.

In the other function you lock the access to the ram, but not here.

>> +    /* Reset any garbage in the ram */
>> +    if (pruss_num == PRUCORE_0)
>> +        for (i = 0; i < PRUSS_PRU0_RAM_SZ; i++)
>> +            iowrite32(0x0, &pruss_mmap->dram0[i]);
>> +    else if (pruss_num == PRUCORE_1)
>> +        for (i = 0; i < PRUSS_PRU1_RAM_SZ; i++)
>> +            iowrite32(0x0, &pruss_mmap->dram1[i]);
> if you make a array for these
> +struct pruss_map {
> +    u8 dram0[512];
> +    u8 res1[7680];
> 
> +    u8 dram1[512];
> +    u8 res2[7680];
> ..}
> you don't need the if..else..
> 
> SG - The dram/iram is not contiguous, there is a reserved space in
> between, how do I declare an array for it.

This is the struct you have:

struct pruss_map {
	u8 dram0[512];
	u8 res1[7680];

	u8 dram1[512];
	u8 res2[7680];
...
}

If you want to describe the ram with an array it translates to:

struct pruss_dram {
	u8 dram[512];
	u8 res[7680];
};

struct pruss_map {
	struct pruss_dram[2];
...
};

BTW: Why do you declare the dram as "u8" "u32" seems more natural to me.

>> +/* Load the specified PRU with code */
>> +s32 pruss_load(struct device *dev, u8 pruss_num,
>> +            u32 *pruss_code, u32 code_size_in_words)
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    struct pruss_map __iomem *pruss_mmap = pruss->ioaddr;
>> +    u32 __iomem *pruss_iram;
>> +    u32 i;
>> +
>> +    if (pruss_num == PRUCORE_0)
>> +        pruss_iram = (u32 __iomem *)&pruss_mmap->iram0;
>> +    else if (pruss_num == PRUCORE_1)
>> +        pruss_iram = (u32 __iomem *)&pruss_mmap->iram1;
>> +    else
> same here
> 
> SG - same here.

same here :)

>> +s32 pruss_run(struct device *dev, u8 pruss_num)
> int?
> 
> SG - Ok, Will do.
> 
> 
>> +    while (cnt--) {
>> +        temp_reg = ioread32(&h_pruss->control);
>> +        if (((temp_reg & PRUCORE_CONTROL_RUNSTATE_MASK) >>
>> +                PRUCORE_CONTROL_RUNSTATE_SHIFT) ==
>> +                PRUCORE_CONTROL_RUNSTATE_HALT)
>> +            break;
> how long might this take? what about some delay, sleep, or reschedule?
> 
> SG - This does not take more than 10 to 20 counts,

Does it make sense, that the timeout is a parameter to that function?

> 
> 
>> +s32 pruss_writeb(struct device *dev, u32 offset, u8 pdatatowrite)
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    void __iomem *paddresstowrite;
> we usually don't use "p" variable names for pointers
> 
> SG - Ok, will remove.
> 
> 
>> +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val)
> void function?
> 
> SG - Ok, will do.
> 
>> +
>> +s32 pruss_readb(struct device *dev, u32 offset, u8 *pdatatoread)
> void?
> 
> SG - Ok, will do.
> 
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    void __iomem *paddresstoread;
>> +
>> +    paddresstoread = pruss->ioaddr + offset ;
>> +    *pdatatoread = ioread8(paddresstoread);
>> +
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_readb);
>> +
>> +s32 pruss_readb_multi(struct device *dev, u32 offset,
>> +        u8 *pdatatoread, u16 bytestoread)
> viod?
> 
> SG - Ok, will do.
> 
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    u8 __iomem *paddresstoread;
>> +    u16 i;
> int?
> 
> SG - Ok, will do.
> 
> 
> 
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_readb_multi);
>> +
>> +s32 pruss_writel(struct device *dev, u32 offset,
>> +        u32 pdatatowrite)
> void?
> 
> SG - Ok, will do.
> 
> 
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_writel);
>> +
>> +s32 pruss_writel_multi(struct device *dev, u32 offset,
>> +        u32 *pdatatowrite, u16 wordstowrite)
> void?
> 
> SG - Ok, will do.
> 
>> +{
>> +    struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>> +    u32 __iomem *paddresstowrite;
>> +    u16 i;
>> +
>> +    paddresstowrite = pruss->ioaddr + offset;
>> +
>> +    for (i = 0; i < wordstowrite; i++)
>> +        iowrite32(*pdatatowrite++, paddresstowrite++);
> memcopy_to_iomem?
> 
> SG -- I did not understand, could you please elaborate.

You could use memcpy_toio() - although it seems it does copy bytes
internally.

http://lxr.linux.no/linux+v2.6.38/arch/arm/include/asm/io.h#L222
> 
> 
>> +
>> +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val)
> void?
> 
> SG - Ok, will do.
> 
> 
>> +}
>> +EXPORT_SYMBOL_GPL(pruss_rmwl);
>> +
>> +s32 pruss_readl(struct device *dev, u32 offset, u32 *pdatatoread)
> void? or return the read value
> 
> SG - Ok, will do.
> 
> 
> 

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/20110427/0ddba555/attachment-0001.sig>

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27  7:29         ` Marc Kleine-Budde
@ 2011-04-27  9:12           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 166+ messages in thread
From: Russell King - ARM Linux @ 2011-04-27  9:12 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Subhasish Ghosh, sachi, davinci-linux-open-source, Samuel Ortiz,
	nsekhar, open list, m-watkins, linux-arm-kernel

On Wed, Apr 27, 2011 at 09:29:59AM +0200, Marc Kleine-Budde wrote:
> On 04/27/2011 08:39 AM, Subhasish Ghosh wrote:
> > - Is it ok to have u32 etc for __iomem cookie ?
> 
> no - "void __iomem *" is "void __iomem *"

Actually, it is _provided_ you don't directly dereference it.  You can
then do pointer arithmetic on it in the usual way - which is about the
only valid thing to do with an __iomem pointer.  The voidness just acts
as an additional check against direct dereferences of this.

The important thing though is that the code passes sparse checks.

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27  9:12           ` Russell King - ARM Linux
  0 siblings, 0 replies; 166+ messages in thread
From: Russell King - ARM Linux @ 2011-04-27  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 27, 2011 at 09:29:59AM +0200, Marc Kleine-Budde wrote:
> On 04/27/2011 08:39 AM, Subhasish Ghosh wrote:
> > - Is it ok to have u32 etc for __iomem cookie ?
> 
> no - "void __iomem *" is "void __iomem *"

Actually, it is _provided_ you don't directly dereference it.  You can
then do pointer arithmetic on it in the usual way - which is about the
only valid thing to do with an __iomem pointer.  The voidness just acts
as an additional check against direct dereferences of this.

The important thing though is that the code passes sparse checks.

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

* Re: [PATCH v4 03/11] da850: pruss platform specific additions.
  2011-04-27  6:43       ` Subhasish Ghosh
@ 2011-04-27 10:05         ` Sergei Shtylyov
  -1 siblings, 0 replies; 166+ messages in thread
From: Sergei Shtylyov @ 2011-04-27 10:05 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:15/17=88%),
	Russell King (maintainer:ARM PORT),
	Michael Williamson (commit_signer:6/17=35%),
	Cyril Chemparathy (commit_signer:3/17=18%),
	Sergei Shtylyov (commit_signer:2/17=12%),
	open list

Hello.

On 27-04-2011 10:43, Subhasish Ghosh wrote:

>>> #include<mach/edma.h>
>>> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>>> #define DA8XX_DDR2_CTL_BASE 0xb0000000
>>> #define DA8XX_ARM_RAM_BASE 0xffff0000
>>> #define DA8XX_SHARED_RAM_BASE 0x80000000
>>> +#define DA8XX_PRUSS_MEM_BASE 0x01C30000

>> Keep the list sorted please. Also, this macro doesn't seem used outside
>> devices-da8xx.c, so should be moved there...

> SG - But would it not be better to have all device addresses at the same place.

    They are not at the same place already -- which is intentional. The ones 
used locally in devices-da8xx.c should be #define'd there.

WBR, Sergei

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

* [PATCH v4 03/11] da850: pruss platform specific additions.
@ 2011-04-27 10:05         ` Sergei Shtylyov
  0 siblings, 0 replies; 166+ messages in thread
From: Sergei Shtylyov @ 2011-04-27 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

On 27-04-2011 10:43, Subhasish Ghosh wrote:

>>> #include<mach/edma.h>
>>> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>>> #define DA8XX_DDR2_CTL_BASE 0xb0000000
>>> #define DA8XX_ARM_RAM_BASE 0xffff0000
>>> #define DA8XX_SHARED_RAM_BASE 0x80000000
>>> +#define DA8XX_PRUSS_MEM_BASE 0x01C30000

>> Keep the list sorted please. Also, this macro doesn't seem used outside
>> devices-da8xx.c, so should be moved there...

> SG - But would it not be better to have all device addresses at the same place.

    They are not at the same place already -- which is intentional. The ones 
used locally in devices-da8xx.c should be #define'd there.

WBR, Sergei

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

* Re: [PATCH v4 03/11] da850: pruss platform specific additions.
  2011-04-27 10:05         ` Sergei Shtylyov
@ 2011-04-27 10:19           ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 10:19 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:15/17=88%),
	Russell King (maintainer:ARM PORT),
	Michael Williamson (commit_signer:6/17=35%),
	Cyril Chemparathy (commit_signer:3/17=18%),
	Sergei Shtylyov (commit_signer:2/17=12%),
	open list

>>>> #include<mach/edma.h>
>>>> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>>>> #define DA8XX_DDR2_CTL_BASE 0xb0000000
>>>> #define DA8XX_ARM_RAM_BASE 0xffff0000
>>>> #define DA8XX_SHARED_RAM_BASE 0x80000000
>>>> +#define DA8XX_PRUSS_MEM_BASE 0x01C30000
>
>>> Keep the list sorted please. Also, this macro doesn't seem used outside
>>> devices-da8xx.c, so should be moved there...
>
>> SG - But would it not be better to have all device addresses at the same 
>> place.
>
>    They are not at the same place already -- which is intentional. The 
> ones used locally in devices-da8xx.c should be #define'd there.

SG -- Ok, Will do 


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

* [PATCH v4 03/11] da850: pruss platform specific additions.
@ 2011-04-27 10:19           ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 10:19 UTC (permalink / raw)
  To: linux-arm-kernel

>>>> #include<mach/edma.h>
>>>> @@ -73,6 +75,7 @@ extern unsigned int da850_max_speed;
>>>> #define DA8XX_DDR2_CTL_BASE 0xb0000000
>>>> #define DA8XX_ARM_RAM_BASE 0xffff0000
>>>> #define DA8XX_SHARED_RAM_BASE 0x80000000
>>>> +#define DA8XX_PRUSS_MEM_BASE 0x01C30000
>
>>> Keep the list sorted please. Also, this macro doesn't seem used outside
>>> devices-da8xx.c, so should be moved there...
>
>> SG - But would it not be better to have all device addresses at the same 
>> place.
>
>    They are not at the same place already -- which is intentional. The 
> ones used locally in devices-da8xx.c should be #define'd there.

SG -- Ok, Will do 

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

* RE: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-27  5:23           ` Subhasish Ghosh
@ 2011-04-27 11:19             ` Nori, Sekhar
  -1 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-04-27 11:19 UTC (permalink / raw)
  To: Subhasish Ghosh, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

On Wed, Apr 27, 2011 at 10:53:38, Subhasish Ghosh wrote:
> >> There should be no build time dependency with this patch
> >> (the above patch just changes which pool of SRAM the
> >> allocation happens from)
> >>
> >> But, this brings out an important dependency of the patch
> >> calling platform specific sram allocator functions. There
> >> has been SRAM allocator consolidation work done by Russell
> >> and as a result the SRAM allocator API for DaVinci will
> >> actually change.
> 
> I earlier had an implementation where I would get the sram memory addresses
> through the .resource structure and ioremap it in the driver.

This is wrong since it assumes the whole SRAM is available
for usage by your driver. We already have an allocator
for SRAM.

> 
> >>The driver should probably just get sram
> >> space through platform data so that it doesn't depend on the
> >> platform specific sram allocation function.
> 
> Are you suggesting that I go back to that implementation.

No, the platform code should use the SRAM allocator and
pass on the allocated memory to the driver.

Thanks,
Sekhar


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-27 11:19             ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-04-27 11:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 27, 2011 at 10:53:38, Subhasish Ghosh wrote:
> >> There should be no build time dependency with this patch
> >> (the above patch just changes which pool of SRAM the
> >> allocation happens from)
> >>
> >> But, this brings out an important dependency of the patch
> >> calling platform specific sram allocator functions. There
> >> has been SRAM allocator consolidation work done by Russell
> >> and as a result the SRAM allocator API for DaVinci will
> >> actually change.
> 
> I earlier had an implementation where I would get the sram memory addresses
> through the .resource structure and ioremap it in the driver.

This is wrong since it assumes the whole SRAM is available
for usage by your driver. We already have an allocator
for SRAM.

> 
> >>The driver should probably just get sram
> >> space through platform data so that it doesn't depend on the
> >> platform specific sram allocation function.
> 
> Are you suggesting that I go back to that implementation.

No, the platform code should use the SRAM allocator and
pass on the allocated memory to the driver.

Thanks,
Sekhar

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-27 11:19             ` Nori, Sekhar
@ 2011-04-27 13:15               ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 13:15 UTC (permalink / raw)
  To: Nori, Sekhar, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

 >> >>The driver should probably just get sram
>> >> space through platform data so that it doesn't depend on the
>> >> platform specific sram allocation function.
>>
>> Are you suggesting that I go back to that implementation.
>
> No, the platform code should use the SRAM allocator and
> pass on the allocated memory to the driver.

SG - So, should I call the sram_alloc() in the platform setup function. 
Something like this:

suart_probe() {
...
pdata.setup(&sram_aadr);
...use sram data;
}

suart_remove() {
...
pdata.free(&sram_aadr);
...
} 


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-27 13:15               ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

 >> >>The driver should probably just get sram
>> >> space through platform data so that it doesn't depend on the
>> >> platform specific sram allocation function.
>>
>> Are you suggesting that I go back to that implementation.
>
> No, the platform code should use the SRAM allocator and
> pass on the allocated memory to the driver.

SG - So, should I call the sram_alloc() in the platform setup function. 
Something like this:

suart_probe() {
...
pdata.setup(&sram_aadr);
...use sram data;
}

suart_remove() {
...
pdata.free(&sram_aadr);
...
} 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-04-27 13:16     ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-27 13:16 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Subhasish Ghosh, davinci-linux-open-source, sachi, Samuel Ortiz,
	nsekhar, open list, m-watkins

On Friday 22 April 2011, Subhasish Ghosh wrote:
> This patch adds the pruss MFD driver and associated include files.
> For details regarding the PRUSS please refer the folowing link:
> http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem
> 
> The rational behind the MFD driver being the fact that multiple devices can
> be implemented on the cores independently. This is determined by the nature
> of the program which is loaded into the PRU's instruction memory.
> A device may be de-initialized and another loaded or two different devices
> can be run simultaneously on the two cores.
> It's also possible, as in our case, to implement a single device on both
> the PRU's resulting in improved load sharing.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>

Hi Subhasish,

This looks like great progress since the last time I looked at the
pruss mfd driver, good work there!

Thanks to your explanations and the documentation link, I now have
a better understanding of what is actually going on here, but I'd
still like to understandhow the decision is made regarding what programs
are loaded into each PRU and how the MFD cells are set up.

Is this a fixed setting for each board that strictly depends on how
the external pins are connected, or is it possible to use the same
hardware for different purposes based on the program?

If I read your code correctly, you hardwire the usage of the two
PRUs in the da850 board code, which makes it impossible to use
them in different ways even if the hardware supports it. If this is
indeed the case, using an MFD device might not be the best option
and we should try to come up with a way to dynamically repurpose
the PRU with some user interface.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27 13:16     ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-27 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 22 April 2011, Subhasish Ghosh wrote:
> This patch adds the pruss MFD driver and associated include files.
> For details regarding the PRUSS please refer the folowing link:
> http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem
> 
> The rational behind the MFD driver being the fact that multiple devices can
> be implemented on the cores independently. This is determined by the nature
> of the program which is loaded into the PRU's instruction memory.
> A device may be de-initialized and another loaded or two different devices
> can be run simultaneously on the two cores.
> It's also possible, as in our case, to implement a single device on both
> the PRU's resulting in improved load sharing.
> 
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>

Hi Subhasish,

This looks like great progress since the last time I looked at the
pruss mfd driver, good work there!

Thanks to your explanations and the documentation link, I now have
a better understanding of what is actually going on here, but I'd
still like to understandhow the decision is made regarding what programs
are loaded into each PRU and how the MFD cells are set up.

Is this a fixed setting for each board that strictly depends on how
the external pins are connected, or is it possible to use the same
hardware for different purposes based on the program?

If I read your code correctly, you hardwire the usage of the two
PRUs in the da850 board code, which makes it impossible to use
them in different ways even if the hardware supports it. If this is
indeed the case, using an MFD device might not be the best option
and we should try to come up with a way to dynamically repurpose
the PRU with some user interface.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27  9:12           ` Russell King - ARM Linux
@ 2011-04-27 13:18             ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 13:18 UTC (permalink / raw)
  To: Russell King - ARM Linux, Marc Kleine-Budde
  Cc: sachi, davinci-linux-open-source, Samuel Ortiz, nsekhar,
	open list, m-watkins, linux-arm-kernel

My problem is, I am doing something like this:

s32 pruss_writel_multi(struct device *dev, u32 offset,
                u32 *pdatatowrite, u16 wordstowrite)
{
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u32 __iomem *paddresstowrite;
        u16 i;

        paddresstowrite = pruss->ioaddr + offset;

        for (i = 0; i < wordstowrite; i++)
                iowrite32(*pdatatowrite++, paddresstowrite++);

        return 0;
}

So, if I make paddresstowrite as void, it will not work. 
The above implementation does not generate any sparse errors though.


> On Wed, Apr 27, 2011 at 09:29:59AM +0200, Marc Kleine-Budde wrote:
>> On 04/27/2011 08:39 AM, Subhasish Ghosh wrote:
>> > - Is it ok to have u32 etc for __iomem cookie ?
>> 
>> no - "void __iomem *" is "void __iomem *"
> 
> Actually, it is _provided_ you don't directly dereference it.  You can
> then do pointer arithmetic on it in the usual way - which is about the
> only valid thing to do with an __iomem pointer.  The voidness just acts
> as an additional check against direct dereferences of this.
> 
> The important thing though is that the code passes sparse checks. 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27 13:18             ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 13:18 UTC (permalink / raw)
  To: linux-arm-kernel

My problem is, I am doing something like this:

s32 pruss_writel_multi(struct device *dev, u32 offset,
                u32 *pdatatowrite, u16 wordstowrite)
{
        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
        u32 __iomem *paddresstowrite;
        u16 i;

        paddresstowrite = pruss->ioaddr + offset;

        for (i = 0; i < wordstowrite; i++)
                iowrite32(*pdatatowrite++, paddresstowrite++);

        return 0;
}

So, if I make paddresstowrite as void, it will not work. 
The above implementation does not generate any sparse errors though.


> On Wed, Apr 27, 2011 at 09:29:59AM +0200, Marc Kleine-Budde wrote:
>> On 04/27/2011 08:39 AM, Subhasish Ghosh wrote:
>> > - Is it ok to have u32 etc for __iomem cookie ?
>> 
>> no - "void __iomem *" is "void __iomem *"
> 
> Actually, it is _provided_ you don't directly dereference it.  You can
> then do pointer arithmetic on it in the usual way - which is about the
> only valid thing to do with an __iomem pointer.  The voidness just acts
> as an additional check against direct dereferences of this.
> 
> The important thing though is that the code passes sparse checks. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27 13:18             ` Subhasish Ghosh
@ 2011-04-27 13:35               ` Marc Kleine-Budde
  -1 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-27 13:35 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Russell King - ARM Linux, sachi, davinci-linux-open-source,
	Samuel Ortiz, nsekhar, open list, m-watkins, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1225 bytes --]

On 04/27/2011 03:18 PM, Subhasish Ghosh wrote:
> My problem is, I am doing something like this:
> 
> s32 pruss_writel_multi(struct device *dev, u32 offset,
>                u32 *pdatatowrite, u16 wordstowrite)
> {
>        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>        u32 __iomem *paddresstowrite;
>        u16 i;
> 
>        paddresstowrite = pruss->ioaddr + offset;
> 
>        for (i = 0; i < wordstowrite; i++)
>                iowrite32(*pdatatowrite++, paddresstowrite++);
> 
>        return 0;
> }
> 
> So, if I make paddresstowrite as void, it will not work. The above
> implementation does not generate any sparse errors though.

Incrementing a u32 pointer will result in increasing the address by 4
bytes. Incrementing a void pointer will result in increasing the address
by just one byte. (Pointer arithmetic on void * is a gnu extension but
IMHO a pretty nice one, though)

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27 13:35               ` Marc Kleine-Budde
  0 siblings, 0 replies; 166+ messages in thread
From: Marc Kleine-Budde @ 2011-04-27 13:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/27/2011 03:18 PM, Subhasish Ghosh wrote:
> My problem is, I am doing something like this:
> 
> s32 pruss_writel_multi(struct device *dev, u32 offset,
>                u32 *pdatatowrite, u16 wordstowrite)
> {
>        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>        u32 __iomem *paddresstowrite;
>        u16 i;
> 
>        paddresstowrite = pruss->ioaddr + offset;
> 
>        for (i = 0; i < wordstowrite; i++)
>                iowrite32(*pdatatowrite++, paddresstowrite++);
> 
>        return 0;
> }
> 
> So, if I make paddresstowrite as void, it will not work. The above
> implementation does not generate any sparse errors though.

Incrementing a u32 pointer will result in increasing the address by 4
bytes. Incrementing a void pointer will result in increasing the address
by just one byte. (Pointer arithmetic on void * is a gnu extension but
IMHO a pretty nice one, though)

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/20110427/d0a11efa/attachment.sig>

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27 13:16     ` Arnd Bergmann
@ 2011-04-27 13:38       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 13:38 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: davinci-linux-open-source, sachi, Samuel Ortiz, nsekhar,
	open list, m-watkins

PRU's resulting in improved load sharing.
>>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>
> Hi Subhasish,
>
> This looks like great progress since the last time I looked at the
> pruss mfd driver, good work there!
>
> Thanks to your explanations and the documentation link, I now have
> a better understanding of what is actually going on here, but I'd
> still like to understandhow the decision is made regarding what programs
> are loaded into each PRU and how the MFD cells are set up.

>
> Is this a fixed setting for each board that strictly depends on how
> the external pins are connected, or is it possible to use the same
> hardware for different purposes based on the program?

SG  -- The PRU pins are exposed as is on the main board,
            we have separate add on daughter cards
            specific to the protocol implemented on it.

>
> If I read your code correctly, you hardwire the usage of the two
> PRUs in the da850 board code, which makes it impossible to use
> them in different ways even if the hardware supports it. If this is
> indeed the case, using an MFD device might not be the best option
> and we should try to come up with a way to dynamically repurpose
> the PRU with some user interface.

SG -- It depends upon how the firmware is implemented. If another
            firmware is downloaded on it, it will emulate another device.
            Also, if a firmware emulated on it supports switching between 
devices,
            that too is possible. Its just a microcontroller, we can do 
whatever we feel like
            with it. Both the PRUs have separate instruction/data ram, so 
both can be used
            to implement two different devices.
 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27 13:38       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-27 13:38 UTC (permalink / raw)
  To: linux-arm-kernel

PRU's resulting in improved load sharing.
>>
>> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
>
> Hi Subhasish,
>
> This looks like great progress since the last time I looked at the
> pruss mfd driver, good work there!
>
> Thanks to your explanations and the documentation link, I now have
> a better understanding of what is actually going on here, but I'd
> still like to understandhow the decision is made regarding what programs
> are loaded into each PRU and how the MFD cells are set up.

>
> Is this a fixed setting for each board that strictly depends on how
> the external pins are connected, or is it possible to use the same
> hardware for different purposes based on the program?

SG  -- The PRU pins are exposed as is on the main board,
            we have separate add on daughter cards
            specific to the protocol implemented on it.

>
> If I read your code correctly, you hardwire the usage of the two
> PRUs in the da850 board code, which makes it impossible to use
> them in different ways even if the hardware supports it. If this is
> indeed the case, using an MFD device might not be the best option
> and we should try to come up with a way to dynamically repurpose
> the PRU with some user interface.

SG -- It depends upon how the firmware is implemented. If another
            firmware is downloaded on it, it will emulate another device.
            Also, if a firmware emulated on it supports switching between 
devices,
            that too is possible. Its just a microcontroller, we can do 
whatever we feel like
            with it. Both the PRUs have separate instruction/data ram, so 
both can be used
            to implement two different devices.
 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27 13:38       ` Subhasish Ghosh
@ 2011-04-27 14:05         ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-27 14:05 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	nsekhar, open list, m-watkins

On Wednesday 27 April 2011, Subhasish Ghosh wrote:
> >
> > If I read your code correctly, you hardwire the usage of the two
> > PRUs in the da850 board code, which makes it impossible to use
> > them in different ways even if the hardware supports it. If this is
> > indeed the case, using an MFD device might not be the best option
> > and we should try to come up with a way to dynamically repurpose
> > the PRU with some user interface.
> 
> SG -- It depends upon how the firmware is implemented. If another
>             firmware is downloaded on it, it will emulate another device.
>             Also, if a firmware emulated on it supports switching between 
> devices,
>             that too is possible. Its just a microcontroller, we can do 
> whatever we feel like
>             with it. Both the PRUs have separate instruction/data ram, so 
> both can be used
>             to implement two different devices.

I see. So the problem that I see with the current code is that you
force the system to provide a set of devices from the MFD, which
then get passed to the individual drivers (uart and can) that load
the firmware they need. Please correct me if I am reading your code
wrong.

What I suggest you do instead is to have the request_firmware
call in the low-level MFD driver, so the user can provide the
firmware that he/she wants to use, and then the MFD driver will
create the devices that match the firmware loaded into the device.

You can easily do that by adding a small header to the firmware
format and interpret that header by the MFD driver. When the name
of the subdevice is part of that header, the MFD driver does not
need to understand the difference, it can simply pass that on
when creating its child devices.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-27 14:05         ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-27 14:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 27 April 2011, Subhasish Ghosh wrote:
> >
> > If I read your code correctly, you hardwire the usage of the two
> > PRUs in the da850 board code, which makes it impossible to use
> > them in different ways even if the hardware supports it. If this is
> > indeed the case, using an MFD device might not be the best option
> > and we should try to come up with a way to dynamically repurpose
> > the PRU with some user interface.
> 
> SG -- It depends upon how the firmware is implemented. If another
>             firmware is downloaded on it, it will emulate another device.
>             Also, if a firmware emulated on it supports switching between 
> devices,
>             that too is possible. Its just a microcontroller, we can do 
> whatever we feel like
>             with it. Both the PRUs have separate instruction/data ram, so 
> both can be used
>             to implement two different devices.

I see. So the problem that I see with the current code is that you
force the system to provide a set of devices from the MFD, which
then get passed to the individual drivers (uart and can) that load
the firmware they need. Please correct me if I am reading your code
wrong.

What I suggest you do instead is to have the request_firmware
call in the low-level MFD driver, so the user can provide the
firmware that he/she wants to use, and then the MFD driver will
create the devices that match the firmware loaded into the device.

You can easily do that by adding a small header to the firmware
format and interpret that header by the MFD driver. When the name
of the subdevice is part of that header, the MFD driver does not
need to understand the difference, it can simply pass that on
when creating its child devices.

	Arnd

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

* RE: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-27 13:15               ` Subhasish Ghosh
@ 2011-04-27 17:50                 ` Nori, Sekhar
  -1 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-04-27 17:50 UTC (permalink / raw)
  To: Subhasish Ghosh, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

Hi Subhasish,

On Wed, Apr 27, 2011 at 18:45:06, Subhasish Ghosh wrote:
>  >> >>The driver should probably just get sram
> >> >> space through platform data so that it doesn't depend on the
> >> >> platform specific sram allocation function.
> >>
> >> Are you suggesting that I go back to that implementation.
> >
> > No, the platform code should use the SRAM allocator and
> > pass on the allocated memory to the driver.
> 
> SG - So, should I call the sram_alloc() in the platform setup function. 

Can you please shed some light on how SRAM
is being used in the driver? Looking at the
driver, it looks like it is used as a shared
buffer between the PRU firmware and kernel.

If yes, how do you cope with dynamic allocation
of SRAM? That is, how do you inform the firmware
what portion of SRAM has been allocated to the
driver?

Also, usage of SRAM is not required for basic driver
function, correct? So, a platform which does not
have SRAM to spare for this driver could still have
a portion of SDRAM/DDR allocated to be used as the
shared buffer? I guess SRAM was used only for lower
access times. But it should still be possible to
sustain lower baudrates with SDRAM/DDR?

Thanks,
Sekhar


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-04-27 17:50                 ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-04-27 17:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Subhasish,

On Wed, Apr 27, 2011 at 18:45:06, Subhasish Ghosh wrote:
>  >> >>The driver should probably just get sram
> >> >> space through platform data so that it doesn't depend on the
> >> >> platform specific sram allocation function.
> >>
> >> Are you suggesting that I go back to that implementation.
> >
> > No, the platform code should use the SRAM allocator and
> > pass on the allocated memory to the driver.
> 
> SG - So, should I call the sram_alloc() in the platform setup function. 

Can you please shed some light on how SRAM
is being used in the driver? Looking at the
driver, it looks like it is used as a shared
buffer between the PRU firmware and kernel.

If yes, how do you cope with dynamic allocation
of SRAM? That is, how do you inform the firmware
what portion of SRAM has been allocated to the
driver?

Also, usage of SRAM is not required for basic driver
function, correct? So, a platform which does not
have SRAM to spare for this driver could still have
a portion of SDRAM/DDR allocated to be used as the
shared buffer? I guess SRAM was used only for lower
access times. But it should still be possible to
sustain lower baudrates with SDRAM/DDR?

Thanks,
Sekhar

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27 14:05         ` Arnd Bergmann
@ 2011-04-28  7:17           ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-28  7:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	nsekhar, open list, m-watkins

Hi,

>> SG -- It depends upon how the firmware is implemented. If another
>>             firmware is downloaded on it, it will emulate another device.
>>             Also, if a firmware emulated on it supports switching between
>> devices,
>>             that too is possible. Its just a microcontroller, we can do
>> whatever we feel like
>>             with it. Both the PRUs have separate instruction/data ram, so
>> both can be used
>>             to implement two different devices.
>
> I see. So the problem that I see with the current code is that you
> force the system to provide a set of devices from the MFD, which
> then get passed to the individual drivers (uart and can) that load
> the firmware they need. Please correct me if I am reading your code
> wrong.
>
> What I suggest you do instead is to have the request_firmware
> call in the low-level MFD driver, so the user can provide the
> firmware that he/she wants to use, and then the MFD driver will
> create the devices that match the firmware loaded into the device.
>
> You can easily do that by adding a small header to the firmware
> format and interpret that header by the MFD driver. When the name
> of the subdevice is part of that header, the MFD driver does not
> need to understand the difference, it can simply pass that on
> when creating its child devices.

I don't understand why loading the firmware should be done at the MFD 
driver.
The user already specifies the device he/she wants to start on the PRU via 
modprobe.
A driver can be inserted, which can download a printer firmware on one PRU 
and a
scanner firmware on the other. This way both cores can be used for separate 
purposes.
I mean, say in a real MFD controller, that will also have two separate cores 
running on it,
just that, the firmware on it would not be downloaded runtime but fused in 
some non volatile memory. 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-28  7:17           ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-28  7:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

>> SG -- It depends upon how the firmware is implemented. If another
>>             firmware is downloaded on it, it will emulate another device.
>>             Also, if a firmware emulated on it supports switching between
>> devices,
>>             that too is possible. Its just a microcontroller, we can do
>> whatever we feel like
>>             with it. Both the PRUs have separate instruction/data ram, so
>> both can be used
>>             to implement two different devices.
>
> I see. So the problem that I see with the current code is that you
> force the system to provide a set of devices from the MFD, which
> then get passed to the individual drivers (uart and can) that load
> the firmware they need. Please correct me if I am reading your code
> wrong.
>
> What I suggest you do instead is to have the request_firmware
> call in the low-level MFD driver, so the user can provide the
> firmware that he/she wants to use, and then the MFD driver will
> create the devices that match the firmware loaded into the device.
>
> You can easily do that by adding a small header to the firmware
> format and interpret that header by the MFD driver. When the name
> of the subdevice is part of that header, the MFD driver does not
> need to understand the difference, it can simply pass that on
> when creating its child devices.

I don't understand why loading the firmware should be done at the MFD 
driver.
The user already specifies the device he/she wants to start on the PRU via 
modprobe.
A driver can be inserted, which can download a printer firmware on one PRU 
and a
scanner firmware on the other. This way both cores can be used for separate 
purposes.
I mean, say in a real MFD controller, that will also have two separate cores 
running on it,
just that, the firmware on it would not be downloaded runtime but fused in 
some non volatile memory. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-27 13:35               ` Marc Kleine-Budde
@ 2011-04-28  7:22                 ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-28  7:22 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Russell King - ARM Linux, sachi, davinci-linux-open-source,
	Samuel Ortiz, nsekhar, open list, m-watkins, linux-arm-kernel

Hi,

On 04/27/2011 03:18 PM, Subhasish Ghosh wrote:
> My problem is, I am doing something like this:
>
> s32 pruss_writel_multi(struct device *dev, u32 offset,
>                u32 *pdatatowrite, u16 wordstowrite)
> {
>        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>        u32 __iomem *paddresstowrite;
>        u16 i;
>
>        paddresstowrite = pruss->ioaddr + offset;
>
>        for (i = 0; i < wordstowrite; i++)
>                iowrite32(*pdatatowrite++, paddresstowrite++);
>
>        return 0;
> }
>
> So, if I make paddresstowrite as void, it will not work. The above
> implementation does not generate any sparse errors though.

Yes, that why I can work with readb_multi even if I have void __iomen *.

But, how do I solve this problem. In the above function, I must use u32 
__iomem * 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-28  7:22                 ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-04-28  7:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 04/27/2011 03:18 PM, Subhasish Ghosh wrote:
> My problem is, I am doing something like this:
>
> s32 pruss_writel_multi(struct device *dev, u32 offset,
>                u32 *pdatatowrite, u16 wordstowrite)
> {
>        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
>        u32 __iomem *paddresstowrite;
>        u16 i;
>
>        paddresstowrite = pruss->ioaddr + offset;
>
>        for (i = 0; i < wordstowrite; i++)
>                iowrite32(*pdatatowrite++, paddresstowrite++);
>
>        return 0;
> }
>
> So, if I make paddresstowrite as void, it will not work. The above
> implementation does not generate any sparse errors though.

Yes, that why I can work with readb_multi even if I have void __iomen *.

But, how do I solve this problem. In the above function, I must use u32 
__iomem * 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-28  7:17           ` Subhasish Ghosh
@ 2011-04-28  7:35             ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-28  7:35 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	nsekhar, open list, m-watkins

On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
> >
> > You can easily do that by adding a small header to the firmware
> > format and interpret that header by the MFD driver. When the name
> > of the subdevice is part of that header, the MFD driver does not
> > need to understand the difference, it can simply pass that on
> > when creating its child devices.
> 
> I don't understand why loading the firmware should be done at the MFD 
> driver.
> The user already specifies the device he/she wants to start on the PRU via 
> modprobe.
> A driver can be inserted, which can download a printer firmware on one PRU 
> and a
> scanner firmware on the other. This way both cores can be used for separate 
> purposes.
> I mean, say in a real MFD controller, that will also have two separate cores 
> running on it,
> just that, the firmware on it would not be downloaded runtime but fused in 
> some non volatile memory. 

Then I must be misreading what your code currently does, because it does not
match your explanations. What I see in the platform code is that you create
MFD cells for specific devices that get automatically created by the MFD
driver. This will cause udev to load the drivers for these devices, which
then load the firmware they need.

Also, I cannot see how the method you describe would make it possible to
the same driver into both units, e.g. when you want to have two serial
ports. The reason is that you currently hardcode the PRU number in the
driver and that you cannot load a single driver twice.

Finally, I'm trying to make sure that whatever solution you come up with
will still work when we migrate the code to using a flattened device tree.
In that case, you would ideally put the device firmware into the device
tree as a property that matches whatever you have connected on the specific
board (at least as an option, you can still fall back to request_firmware).
You definitely want automatic module loading in that case.

Note that using module loading with specific parameters in order to
match the hardware is not a recommended procedure any more. The code
really needs to work the same way when all drivers are built into the
kernel. It should not be hard to use the firmware loading mechanism
in the MFD driver to both load the firmware and configure the devices
appropriately so we always use the right driver for the currently
active devices.

	Arnd

BTW, something is wrong with your email client line wrapping. I've fixed
this up manually before when replying, but please find a way to get this
right in the future.

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-28  7:35             ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-28  7:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
> >
> > You can easily do that by adding a small header to the firmware
> > format and interpret that header by the MFD driver. When the name
> > of the subdevice is part of that header, the MFD driver does not
> > need to understand the difference, it can simply pass that on
> > when creating its child devices.
> 
> I don't understand why loading the firmware should be done at the MFD 
> driver.
> The user already specifies the device he/she wants to start on the PRU via 
> modprobe.
> A driver can be inserted, which can download a printer firmware on one PRU 
> and a
> scanner firmware on the other. This way both cores can be used for separate 
> purposes.
> I mean, say in a real MFD controller, that will also have two separate cores 
> running on it,
> just that, the firmware on it would not be downloaded runtime but fused in 
> some non volatile memory. 

Then I must be misreading what your code currently does, because it does not
match your explanations. What I see in the platform code is that you create
MFD cells for specific devices that get automatically created by the MFD
driver. This will cause udev to load the drivers for these devices, which
then load the firmware they need.

Also, I cannot see how the method you describe would make it possible to
the same driver into both units, e.g. when you want to have two serial
ports. The reason is that you currently hardcode the PRU number in the
driver and that you cannot load a single driver twice.

Finally, I'm trying to make sure that whatever solution you come up with
will still work when we migrate the code to using a flattened device tree.
In that case, you would ideally put the device firmware into the device
tree as a property that matches whatever you have connected on the specific
board (at least as an option, you can still fall back to request_firmware).
You definitely want automatic module loading in that case.

Note that using module loading with specific parameters in order to
match the hardware is not a recommended procedure any more. The code
really needs to work the same way when all drivers are built into the
kernel. It should not be hard to use the firmware loading mechanism
in the MFD driver to both load the firmware and configure the devices
appropriately so we always use the right driver for the currently
active devices.

	Arnd

BTW, something is wrong with your email client line wrapping. I've fixed
this up manually before when replying, but please find a way to get this
right in the future.

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-28  7:22                 ` Subhasish Ghosh
@ 2011-04-28  7:46                   ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-28  7:46 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Marc Kleine-Budde, Russell King - ARM Linux, sachi,
	davinci-linux-open-source, Samuel Ortiz, nsekhar, open list,
	m-watkins, linux-arm-kernel

On Thursday 28 April 2011 09:22:49 Subhasish Ghosh wrote:
> On 04/27/2011 03:18 PM, Subhasish Ghosh wrote:
> > My problem is, I am doing something like this:
> >
> > s32 pruss_writel_multi(struct device *dev, u32 offset,
> >                u32 *pdatatowrite, u16 wordstowrite)
> > {
> >        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> >        u32 __iomem *paddresstowrite;
> >        u16 i;
> >
> >        paddresstowrite = pruss->ioaddr + offset;
> >
> >        for (i = 0; i < wordstowrite; i++)
> >                iowrite32(*pdatatowrite++, paddresstowrite++);
> >
> >        return 0;
> > }
> >
> > So, if I make paddresstowrite as void, it will not work. The above
> > implementation does not generate any sparse errors though.
> 
> Yes, that why I can work with readb_multi even if I have void __iomen *.
> 
> But, how do I solve this problem. In the above function, I must use u32 
> __iomem * 
> 

I believe you were talking about different things. The code you cited
above looks correct to me. For clarity, I would write the loop as

       for (i = 0; i < wordstowrite; i++)
               iowrite32(pdatatowrite[i], &paddresstowrite[i]);

but your version is just as correct, and I would not complain about it.

It is absolutely valid to pass either a 'void __iomem *' or a 'u32 __iomem *'
into iowrite32(). What is not valid is to cast between a 'void __iomem *'
and a plain 'u32' (no pointer). While that may work in most cases, there
are a lot of reasons why that is considered bad style and you should never
write code like that. I believe that is what Marc was referring to, but you
don't do it in your code.

The initial comments that Marc made were about the return value of the
accessor functions that always return success. Just make those return
void instead. Again, this is unrelated to the pointer types.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-04-28  7:46                   ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-04-28  7:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 28 April 2011 09:22:49 Subhasish Ghosh wrote:
> On 04/27/2011 03:18 PM, Subhasish Ghosh wrote:
> > My problem is, I am doing something like this:
> >
> > s32 pruss_writel_multi(struct device *dev, u32 offset,
> >                u32 *pdatatowrite, u16 wordstowrite)
> > {
> >        struct pruss_priv *pruss = dev_get_drvdata(dev->parent);
> >        u32 __iomem *paddresstowrite;
> >        u16 i;
> >
> >        paddresstowrite = pruss->ioaddr + offset;
> >
> >        for (i = 0; i < wordstowrite; i++)
> >                iowrite32(*pdatatowrite++, paddresstowrite++);
> >
> >        return 0;
> > }
> >
> > So, if I make paddresstowrite as void, it will not work. The above
> > implementation does not generate any sparse errors though.
> 
> Yes, that why I can work with readb_multi even if I have void __iomen *.
> 
> But, how do I solve this problem. In the above function, I must use u32 
> __iomem * 
> 

I believe you were talking about different things. The code you cited
above looks correct to me. For clarity, I would write the loop as

       for (i = 0; i < wordstowrite; i++)
               iowrite32(pdatatowrite[i], &paddresstowrite[i]);

but your version is just as correct, and I would not complain about it.

It is absolutely valid to pass either a 'void __iomem *' or a 'u32 __iomem *'
into iowrite32(). What is not valid is to cast between a 'void __iomem *'
and a plain 'u32' (no pointer). While that may work in most cases, there
are a lot of reasons why that is considered bad style and you should never
write code like that. I believe that is what Marc was referring to, but you
don't do it in your code.

The initial comments that Marc made were about the return value of the
accessor functions that always return success. Just make those return
void instead. Again, this is unrelated to the pointer types.

	Arnd

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-27 17:50                 ` Nori, Sekhar
@ 2011-05-02  8:34                   ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-02  8:34 UTC (permalink / raw)
  To: Nori, Sekhar, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list


> Hi Subhasish,
> 
> On Wed, Apr 27, 2011 at 18:45:06, Subhasish Ghosh wrote:
>>  >> >>The driver should probably just get sram
>> >> >> space through platform data so that it doesn't depend on the
>> >> >> platform specific sram allocation function.
>> >>
>> >> Are you suggesting that I go back to that implementation.
>> >
>> > No, the platform code should use the SRAM allocator and
>> > pass on the allocated memory to the driver.
>> 
>> SG - So, should I call the sram_alloc() in the platform setup function. 
> 
> Can you please shed some light on how SRAM
> is being used in the driver? Looking at the
> driver, it looks like it is used as a shared
> buffer between the PRU firmware and kernel.
> 
> If yes, how do you cope with dynamic allocation
> of SRAM? That is, how do you inform the firmware
> what portion of SRAM has been allocated to the
> driver?
> 
> Also, usage of SRAM is not required for basic driver
> function, correct? So, a platform which does not
> have SRAM to spare for this driver could still have
> a portion of SDRAM/DDR allocated to be used as the
> shared buffer? I guess SRAM was used only for lower
> access times. But it should still be possible to
> sustain lower baudrates with SDRAM/DDR?

The sram is allocated dynamically in the driver. 
After allocation, we write the pointer into the PRU, so in case the
driver allocates memory form the DDR, it will write this info into the
PRU and it will work. But, because of DDR access latencies, the UART
will work only for lower baud rates. 

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-02  8:34                   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-02  8:34 UTC (permalink / raw)
  To: linux-arm-kernel


> Hi Subhasish,
> 
> On Wed, Apr 27, 2011 at 18:45:06, Subhasish Ghosh wrote:
>>  >> >>The driver should probably just get sram
>> >> >> space through platform data so that it doesn't depend on the
>> >> >> platform specific sram allocation function.
>> >>
>> >> Are you suggesting that I go back to that implementation.
>> >
>> > No, the platform code should use the SRAM allocator and
>> > pass on the allocated memory to the driver.
>> 
>> SG - So, should I call the sram_alloc() in the platform setup function. 
> 
> Can you please shed some light on how SRAM
> is being used in the driver? Looking at the
> driver, it looks like it is used as a shared
> buffer between the PRU firmware and kernel.
> 
> If yes, how do you cope with dynamic allocation
> of SRAM? That is, how do you inform the firmware
> what portion of SRAM has been allocated to the
> driver?
> 
> Also, usage of SRAM is not required for basic driver
> function, correct? So, a platform which does not
> have SRAM to spare for this driver could still have
> a portion of SDRAM/DDR allocated to be used as the
> shared buffer? I guess SRAM was used only for lower
> access times. But it should still be possible to
> sustain lower baudrates with SDRAM/DDR?

The sram is allocated dynamically in the driver. 
After allocation, we write the pointer into the PRU, so in case the
driver allocates memory form the DDR, it will write this info into the
PRU and it will work. But, because of DDR access latencies, the UART
will work only for lower baud rates. 

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

* RE: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-02  8:34                   ` Subhasish Ghosh
@ 2011-05-02 17:15                     ` Nori, Sekhar
  -1 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-02 17:15 UTC (permalink / raw)
  To: Subhasish Ghosh, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

On Mon, May 02, 2011 at 14:04:11, Subhasish Ghosh wrote:

> >> SG - So, should I call the sram_alloc() in the platform setup function. 
> > 
> > Can you please shed some light on how SRAM
> > is being used in the driver? Looking at the
> > driver, it looks like it is used as a shared
> > buffer between the PRU firmware and kernel.
> > 
> > If yes, how do you cope with dynamic allocation
> > of SRAM? That is, how do you inform the firmware
> > what portion of SRAM has been allocated to the
> > driver?
> > 
> > Also, usage of SRAM is not required for basic driver
> > function, correct? So, a platform which does not
> > have SRAM to spare for this driver could still have
> > a portion of SDRAM/DDR allocated to be used as the
> > shared buffer? I guess SRAM was used only for lower
> > access times. But it should still be possible to
> > sustain lower baudrates with SDRAM/DDR?
> 
> The sram is allocated dynamically in the driver. 
> After allocation, we write the pointer into the PRU, so in case the
> driver allocates memory form the DDR, it will write this info into the
> PRU and it will work. But, because of DDR access latencies, the UART
> will work only for lower baud rates. 

Thanks for the clarification. In this case, the driver
should use platform callbacks to get/put fast fifo
space. In case this callback is not populated by the
platform or returns an error, the driver should fall
back to allocating from DDR.

Thanks,
Sekhar


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-02 17:15                     ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-02 17:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 02, 2011 at 14:04:11, Subhasish Ghosh wrote:

> >> SG - So, should I call the sram_alloc() in the platform setup function. 
> > 
> > Can you please shed some light on how SRAM
> > is being used in the driver? Looking at the
> > driver, it looks like it is used as a shared
> > buffer between the PRU firmware and kernel.
> > 
> > If yes, how do you cope with dynamic allocation
> > of SRAM? That is, how do you inform the firmware
> > what portion of SRAM has been allocated to the
> > driver?
> > 
> > Also, usage of SRAM is not required for basic driver
> > function, correct? So, a platform which does not
> > have SRAM to spare for this driver could still have
> > a portion of SDRAM/DDR allocated to be used as the
> > shared buffer? I guess SRAM was used only for lower
> > access times. But it should still be possible to
> > sustain lower baudrates with SDRAM/DDR?
> 
> The sram is allocated dynamically in the driver. 
> After allocation, we write the pointer into the PRU, so in case the
> driver allocates memory form the DDR, it will write this info into the
> PRU and it will work. But, because of DDR access latencies, the UART
> will work only for lower baud rates. 

Thanks for the clarification. In this case, the driver
should use platform callbacks to get/put fast fifo
space. In case this callback is not populated by the
platform or returns an error, the driver should fall
back to allocating from DDR.

Thanks,
Sekhar

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-04-28  7:35             ` Arnd Bergmann
@ 2011-05-04  7:18               ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-04  7:18 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	nsekhar, open list, m-watkins

Hi Arnd,

How about just doing something like:

#> echo da8xx_pruss_uart >> firmware.bin

i.e  just append the device name (from the board file) into the firmware
file.

In the driver probe, we can parse from the bottom, when it reaches
"da8xx_pruss", the rest of the upper data is the firmware and from
the full name, we can determine if it's a CAN, UART or any other
peripheral.

So, based on the platform_data, which the MFD driver received,
it can find out which device to initialize.

Also, does the line wrapping look any better ?


> On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
>> >
>> > You can easily do that by adding a small header to the firmware
>> > format and interpret that header by the MFD driver. When the name
>> > of the subdevice is part of that header, the MFD driver does not
>> > need to understand the difference, it can simply pass that on
>> > when creating its child devices.
>>
>> I don't understand why loading the firmware should be done at the MFD
>> driver.
>> The user already specifies the device he/she wants to start on the PRU
>> via
>> modprobe.
>> A driver can be inserted, which can download a printer firmware on one
>> PRU
>> and a
>> scanner firmware on the other. This way both cores can be used for
>> separate
>> purposes.
>> I mean, say in a real MFD controller, that will also have two separate
>> cores
>> running on it,
>> just that, the firmware on it would not be downloaded runtime but fused
>> in
>> some non volatile memory.
>
> Then I must be misreading what your code currently does, because it does
> not
> match your explanations. What I see in the platform code is that you
> create
> MFD cells for specific devices that get automatically created by the MFD
> driver. This will cause udev to load the drivers for these devices, which
> then load the firmware they need.
>
> Also, I cannot see how the method you describe would make it possible to
> the same driver into both units, e.g. when you want to have two serial
> ports. The reason is that you currently hardcode the PRU number in the
> driver and that you cannot load a single driver twice.
>
> Finally, I'm trying to make sure that whatever solution you come up with
> will still work when we migrate the code to using a flattened device tree.
> In that case, you would ideally put the device firmware into the device
> tree as a property that matches whatever you have connected on the
> specific
> board (at least as an option, you can still fall back to
> request_firmware).
> You definitely want automatic module loading in that case.
>
> Note that using module loading with specific parameters in order to
> match the hardware is not a recommended procedure any more. The code
> really needs to work the same way when all drivers are built into the
> kernel. It should not be hard to use the firmware loading mechanism
> in the MFD driver to both load the firmware and configure the devices
> appropriately so we always use the right driver for the currently
> active devices.
>
> Arnd
>
> BTW, something is wrong with your email client line wrapping. I've fixed
> this up manually before when replying, but please find a way to get this
> right in the future. 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-04  7:18               ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-04  7:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

How about just doing something like:

#> echo da8xx_pruss_uart >> firmware.bin

i.e  just append the device name (from the board file) into the firmware
file.

In the driver probe, we can parse from the bottom, when it reaches
"da8xx_pruss", the rest of the upper data is the firmware and from
the full name, we can determine if it's a CAN, UART or any other
peripheral.

So, based on the platform_data, which the MFD driver received,
it can find out which device to initialize.

Also, does the line wrapping look any better ?


> On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
>> >
>> > You can easily do that by adding a small header to the firmware
>> > format and interpret that header by the MFD driver. When the name
>> > of the subdevice is part of that header, the MFD driver does not
>> > need to understand the difference, it can simply pass that on
>> > when creating its child devices.
>>
>> I don't understand why loading the firmware should be done at the MFD
>> driver.
>> The user already specifies the device he/she wants to start on the PRU
>> via
>> modprobe.
>> A driver can be inserted, which can download a printer firmware on one
>> PRU
>> and a
>> scanner firmware on the other. This way both cores can be used for
>> separate
>> purposes.
>> I mean, say in a real MFD controller, that will also have two separate
>> cores
>> running on it,
>> just that, the firmware on it would not be downloaded runtime but fused
>> in
>> some non volatile memory.
>
> Then I must be misreading what your code currently does, because it does
> not
> match your explanations. What I see in the platform code is that you
> create
> MFD cells for specific devices that get automatically created by the MFD
> driver. This will cause udev to load the drivers for these devices, which
> then load the firmware they need.
>
> Also, I cannot see how the method you describe would make it possible to
> the same driver into both units, e.g. when you want to have two serial
> ports. The reason is that you currently hardcode the PRU number in the
> driver and that you cannot load a single driver twice.
>
> Finally, I'm trying to make sure that whatever solution you come up with
> will still work when we migrate the code to using a flattened device tree.
> In that case, you would ideally put the device firmware into the device
> tree as a property that matches whatever you have connected on the
> specific
> board (at least as an option, you can still fall back to
> request_firmware).
> You definitely want automatic module loading in that case.
>
> Note that using module loading with specific parameters in order to
> match the hardware is not a recommended procedure any more. The code
> really needs to work the same way when all drivers are built into the
> kernel. It should not be hard to use the firmware loading mechanism
> in the MFD driver to both load the firmware and configure the devices
> appropriately so we always use the right driver for the currently
> active devices.
>
> Arnd
>
> BTW, something is wrong with your email client line wrapping. I've fixed
> this up manually before when replying, but please find a way to get this
> right in the future. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-04  7:18               ` Subhasish Ghosh
@ 2011-05-04 13:44                 ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-04 13:44 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	nsekhar, open list, m-watkins

On Wednesday 04 May 2011, Subhasish Ghosh wrote:
> How about just doing something like:
> 
> #> echo da8xx_pruss_uart >> firmware.bin
> 
> i.e  just append the device name (from the board file) into the firmware
> file.

That sounds fine to me. I would put a header in the beginning, but feel free
to use whatever format you find useful there.

> In the driver probe, we can parse from the bottom, when it reaches
> "da8xx_pruss", the rest of the upper data is the firmware and from
> the full name, we can determine if it's a CAN, UART or any other
> peripheral.
> 
> So, based on the platform_data, which the MFD driver received,
> it can find out which device to initialize.

In my opinion, the MFD driver should not know the possible values
at all, or look at platform_data for the children, but take all
that information from the firmware file.

The only thing that the MFD driver needs to know is how many PRUs
there are and how they are connected to the host bus (memory
regions, irqs, clocks, ...). It can then load firmware files,
either one for the entire MFD or one per PRU core (whatever
works best for you) and create child devices with the information
it finds in there about what code to load into each PRU
and what drivers to load for them.

When you prepend the "da8xx_pruss_" string to the name you find
in the firmware file, the pruss driver can be sure that it does
not accidentally load a different module, e.g. when a malicious
user was able to exchange the firmware file.

> Also, does the line wrapping look any better ?

Looks good now, yes.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-04 13:44                 ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-04 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 04 May 2011, Subhasish Ghosh wrote:
> How about just doing something like:
> 
> #> echo da8xx_pruss_uart >> firmware.bin
> 
> i.e  just append the device name (from the board file) into the firmware
> file.

That sounds fine to me. I would put a header in the beginning, but feel free
to use whatever format you find useful there.

> In the driver probe, we can parse from the bottom, when it reaches
> "da8xx_pruss", the rest of the upper data is the firmware and from
> the full name, we can determine if it's a CAN, UART or any other
> peripheral.
> 
> So, based on the platform_data, which the MFD driver received,
> it can find out which device to initialize.

In my opinion, the MFD driver should not know the possible values
at all, or look at platform_data for the children, but take all
that information from the firmware file.

The only thing that the MFD driver needs to know is how many PRUs
there are and how they are connected to the host bus (memory
regions, irqs, clocks, ...). It can then load firmware files,
either one for the entire MFD or one per PRU core (whatever
works best for you) and create child devices with the information
it finds in there about what code to load into each PRU
and what drivers to load for them.

When you prepend the "da8xx_pruss_" string to the name you find
in the firmware file, the pruss driver can be sure that it does
not accidentally load a different module, e.g. when a malicious
user was able to exchange the firmware file.

> Also, does the line wrapping look any better ?

Looks good now, yes.

	Arnd

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

* RE: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-04  7:18               ` Subhasish Ghosh
@ 2011-05-04 14:38                 ` Nori, Sekhar
  -1 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-04 14:38 UTC (permalink / raw)
  To: Subhasish Ghosh, Arnd Bergmann
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	open list, Watkins, Melissa

Hi Subhasish,

On Wed, May 04, 2011 at 12:48:43, Subhasish Ghosh wrote:
> Hi Arnd,
> 
> How about just doing something like:
> 
> #> echo da8xx_pruss_uart >> firmware.bin
> 
> i.e  just append the device name (from the board file) into the firmware
> file.
> 
> In the driver probe, we can parse from the bottom, when it reaches
> "da8xx_pruss", the rest of the upper data is the firmware and from
> the full name, we can determine if it's a CAN, UART or any other
> peripheral.
> 
> So, based on the platform_data, which the MFD driver received,
> it can find out which device to initialize.

If you are defining a firmware header, it may be
worthwhile making sure you include information
on features of the device being supported (I
assume there will be differences in CAN features if
the firmware uses both PRUs to support CAN versus
UART on one PRU and CAN on another PRU).

The MFD driver can parse this information and
pass this on to the UART or CAN drivers.

Thanks,
Sekhar

> 
> Also, does the line wrapping look any better ?
> 
> 
> > On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
> >> >
> >> > You can easily do that by adding a small header to the firmware
> >> > format and interpret that header by the MFD driver. When the name
> >> > of the subdevice is part of that header, the MFD driver does not
> >> > need to understand the difference, it can simply pass that on
> >> > when creating its child devices.
> >>
> >> I don't understand why loading the firmware should be done at the MFD
> >> driver.
> >> The user already specifies the device he/she wants to start on the PRU
> >> via
> >> modprobe.
> >> A driver can be inserted, which can download a printer firmware on one
> >> PRU
> >> and a
> >> scanner firmware on the other. This way both cores can be used for
> >> separate
> >> purposes.
> >> I mean, say in a real MFD controller, that will also have two separate
> >> cores
> >> running on it,
> >> just that, the firmware on it would not be downloaded runtime but fused
> >> in
> >> some non volatile memory.
> >
> > Then I must be misreading what your code currently does, because it does
> > not
> > match your explanations. What I see in the platform code is that you
> > create
> > MFD cells for specific devices that get automatically created by the MFD
> > driver. This will cause udev to load the drivers for these devices, which
> > then load the firmware they need.
> >
> > Also, I cannot see how the method you describe would make it possible to
> > the same driver into both units, e.g. when you want to have two serial
> > ports. The reason is that you currently hardcode the PRU number in the
> > driver and that you cannot load a single driver twice.
> >
> > Finally, I'm trying to make sure that whatever solution you come up with
> > will still work when we migrate the code to using a flattened device tree.
> > In that case, you would ideally put the device firmware into the device
> > tree as a property that matches whatever you have connected on the
> > specific
> > board (at least as an option, you can still fall back to
> > request_firmware).
> > You definitely want automatic module loading in that case.
> >
> > Note that using module loading with specific parameters in order to
> > match the hardware is not a recommended procedure any more. The code
> > really needs to work the same way when all drivers are built into the
> > kernel. It should not be hard to use the firmware loading mechanism
> > in the MFD driver to both load the firmware and configure the devices
> > appropriately so we always use the right driver for the currently
> > active devices.
> >
> > Arnd
> >
> > BTW, something is wrong with your email client line wrapping. I've fixed
> > this up manually before when replying, but please find a way to get this
> > right in the future. 
> 
> 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-04 14:38                 ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-04 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Subhasish,

On Wed, May 04, 2011 at 12:48:43, Subhasish Ghosh wrote:
> Hi Arnd,
> 
> How about just doing something like:
> 
> #> echo da8xx_pruss_uart >> firmware.bin
> 
> i.e  just append the device name (from the board file) into the firmware
> file.
> 
> In the driver probe, we can parse from the bottom, when it reaches
> "da8xx_pruss", the rest of the upper data is the firmware and from
> the full name, we can determine if it's a CAN, UART or any other
> peripheral.
> 
> So, based on the platform_data, which the MFD driver received,
> it can find out which device to initialize.

If you are defining a firmware header, it may be
worthwhile making sure you include information
on features of the device being supported (I
assume there will be differences in CAN features if
the firmware uses both PRUs to support CAN versus
UART on one PRU and CAN on another PRU).

The MFD driver can parse this information and
pass this on to the UART or CAN drivers.

Thanks,
Sekhar

> 
> Also, does the line wrapping look any better ?
> 
> 
> > On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
> >> >
> >> > You can easily do that by adding a small header to the firmware
> >> > format and interpret that header by the MFD driver. When the name
> >> > of the subdevice is part of that header, the MFD driver does not
> >> > need to understand the difference, it can simply pass that on
> >> > when creating its child devices.
> >>
> >> I don't understand why loading the firmware should be done at the MFD
> >> driver.
> >> The user already specifies the device he/she wants to start on the PRU
> >> via
> >> modprobe.
> >> A driver can be inserted, which can download a printer firmware on one
> >> PRU
> >> and a
> >> scanner firmware on the other. This way both cores can be used for
> >> separate
> >> purposes.
> >> I mean, say in a real MFD controller, that will also have two separate
> >> cores
> >> running on it,
> >> just that, the firmware on it would not be downloaded runtime but fused
> >> in
> >> some non volatile memory.
> >
> > Then I must be misreading what your code currently does, because it does
> > not
> > match your explanations. What I see in the platform code is that you
> > create
> > MFD cells for specific devices that get automatically created by the MFD
> > driver. This will cause udev to load the drivers for these devices, which
> > then load the firmware they need.
> >
> > Also, I cannot see how the method you describe would make it possible to
> > the same driver into both units, e.g. when you want to have two serial
> > ports. The reason is that you currently hardcode the PRU number in the
> > driver and that you cannot load a single driver twice.
> >
> > Finally, I'm trying to make sure that whatever solution you come up with
> > will still work when we migrate the code to using a flattened device tree.
> > In that case, you would ideally put the device firmware into the device
> > tree as a property that matches whatever you have connected on the
> > specific
> > board (at least as an option, you can still fall back to
> > request_firmware).
> > You definitely want automatic module loading in that case.
> >
> > Note that using module loading with specific parameters in order to
> > match the hardware is not a recommended procedure any more. The code
> > really needs to work the same way when all drivers are built into the
> > kernel. It should not be hard to use the firmware loading mechanism
> > in the MFD driver to both load the firmware and configure the devices
> > appropriately so we always use the right driver for the currently
> > active devices.
> >
> > Arnd
> >
> > BTW, something is wrong with your email client line wrapping. I've fixed
> > this up manually before when replying, but please find a way to get this
> > right in the future. 
> 
> 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-04 14:38                 ` Nori, Sekhar
@ 2011-05-05 13:25                   ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-05 13:25 UTC (permalink / raw)
  To: Nori, Sekhar, Arnd Bergmann
  Cc: linux-arm-kernel, davinci-linux-open-source, sachi, Samuel Ortiz,
	open list, Watkins, Melissa

I am a bit lost,

If I understand correctly, there are two problems

1. In case of udev based driver loading, we will end up
loading both the drivers and the associated firmware.
This is not acceptable because both UART & CAN
use PRU0 & PRU1.

2. How do we switch between devices at run time.
This is required because MFD devices should be
capable of doing that.


Ok, if that understanding is somewhat correct, then, what we are
trying to do is load the firmware from the MFD driver itself.

So, in case of a switch between device, say from UART to CAN,
all the user has to do is copy a new firmware.

This firmware should contain some info regarding the device, like
say, device name & prunum.

So, in case a device requires both PRUs, then the firmware would
download for both PRUs.

In case a device requires only one PRU, then it can be downloaded
only into the requested PRU. So, the other PRU remains open for
any other firmware/device.

After loading the firmware, the MFD device should create the
platform devices based upon the firmware.

So, if only one PRU is used for UART, then the other PRU can be
used for CAN and the MFD should create two platform_devices.

If the UART uses both the PRUs, then the MFD should download
the firmware into both the PRUs but create only one platform_device.

But, in this case how do we download two different firmware
on two different PRUs. One way is to keep the firmware files
as its now, but add another file say firmware-config.txt,
consisting a list of parameters like,

START
MFD_ID0#0
MFD_ID0_PRU_NUM#PRU0
MFD_ID1#1
MFD_ID1_PRU_NUM#PRU1
END

OR

START
MFD_ID0#0
MFD_ID0_PRU_NUM#PRU0:PRU1
END

So, the MFD driver can do a request_firmware on this file first,
parse the device info and decide to request the main firmware.
This becomes something like the devices table that we have on
PPC.

Also, if PRU0 is loaded, we need some way of maintaining the
usage_count, So that the PRU0 is not loaded again accidently.
We can increase the usage_count from the MFD driver.
But, to decrement the usage_count, we can add an API
which will be called when the CAN or UART driver is rmmod.


Now how do we handle switch between devices.

We can either do a rmmod of the MFD driver, then again modprobe it.
So, the request_firmware is run again and the appropriate device is
loaded based upon the changed firmware-config.txt.

But, this does not look good, say what if the MFD driver is in-build.
Another way is that we can add a sysfs entry, which when written
with anything can re-evaluate the firmware_config.

What the hell, does anything make any sense ?


> Hi Subhasish,
>
> On Wed, May 04, 2011 at 12:48:43, Subhasish Ghosh wrote:
>> Hi Arnd,
>>
>> How about just doing something like:
>>
>> #> echo da8xx_pruss_uart >> firmware.bin
>>
>> i.e  just append the device name (from the board file) into the firmware
>> file.
>>
>> In the driver probe, we can parse from the bottom, when it reaches
>> "da8xx_pruss", the rest of the upper data is the firmware and from
>> the full name, we can determine if it's a CAN, UART or any other
>> peripheral.
>>
>> So, based on the platform_data, which the MFD driver received,
>> it can find out which device to initialize.
>
> If you are defining a firmware header, it may be
> worthwhile making sure you include information
> on features of the device being supported (I
> assume there will be differences in CAN features if
> the firmware uses both PRUs to support CAN versus
> UART on one PRU and CAN on another PRU).
>
> The MFD driver can parse this information and
> pass this on to the UART or CAN drivers.
>
> Thanks,
> Sekhar
>
>>
>> Also, does the line wrapping look any better ?
>>
>>
>> > On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
>> >> >
>> >> > You can easily do that by adding a small header to the firmware
>> >> > format and interpret that header by the MFD driver. When the name
>> >> > of the subdevice is part of that header, the MFD driver does not
>> >> > need to understand the difference, it can simply pass that on
>> >> > when creating its child devices.
>> >>
>> >> I don't understand why loading the firmware should be done at the MFD
>> >> driver.
>> >> The user already specifies the device he/she wants to start on the PRU
>> >> via
>> >> modprobe.
>> >> A driver can be inserted, which can download a printer firmware on one
>> >> PRU
>> >> and a
>> >> scanner firmware on the other. This way both cores can be used for
>> >> separate
>> >> purposes.
>> >> I mean, say in a real MFD controller, that will also have two separate
>> >> cores
>> >> running on it,
>> >> just that, the firmware on it would not be downloaded runtime but 
>> >> fused
>> >> in
>> >> some non volatile memory.
>> >
>> > Then I must be misreading what your code currently does, because it 
>> > does
>> > not
>> > match your explanations. What I see in the platform code is that you
>> > create
>> > MFD cells for specific devices that get automatically created by the 
>> > MFD
>> > driver. This will cause udev to load the drivers for these devices, 
>> > which
>> > then load the firmware they need.
>> >
>> > Also, I cannot see how the method you describe would make it possible 
>> > to
>> > the same driver into both units, e.g. when you want to have two serial
>> > ports. The reason is that you currently hardcode the PRU number in the
>> > driver and that you cannot load a single driver twice.
>> >
>> > Finally, I'm trying to make sure that whatever solution you come up 
>> > with
>> > will still work when we migrate the code to using a flattened device 
>> > tree.
>> > In that case, you would ideally put the device firmware into the device
>> > tree as a property that matches whatever you have connected on the
>> > specific
>> > board (at least as an option, you can still fall back to
>> > request_firmware).
>> > You definitely want automatic module loading in that case.
>> >
>> > Note that using module loading with specific parameters in order to
>> > match the hardware is not a recommended procedure any more. The code
>> > really needs to work the same way when all drivers are built into the
>> > kernel. It should not be hard to use the firmware loading mechanism
>> > in the MFD driver to both load the firmware and configure the devices
>> > appropriately so we always use the right driver for the currently
>> > active devices.
>> >
>> > Arnd
>> >
>> > BTW, something is wrong with your email client line wrapping. I've 
>> > fixed
>> > this up manually before when replying, but please find a way to get 
>> > this
>> > right in the future.
>>
>>
> 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-05 13:25                   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-05 13:25 UTC (permalink / raw)
  To: linux-arm-kernel

I am a bit lost,

If I understand correctly, there are two problems

1. In case of udev based driver loading, we will end up
loading both the drivers and the associated firmware.
This is not acceptable because both UART & CAN
use PRU0 & PRU1.

2. How do we switch between devices at run time.
This is required because MFD devices should be
capable of doing that.


Ok, if that understanding is somewhat correct, then, what we are
trying to do is load the firmware from the MFD driver itself.

So, in case of a switch between device, say from UART to CAN,
all the user has to do is copy a new firmware.

This firmware should contain some info regarding the device, like
say, device name & prunum.

So, in case a device requires both PRUs, then the firmware would
download for both PRUs.

In case a device requires only one PRU, then it can be downloaded
only into the requested PRU. So, the other PRU remains open for
any other firmware/device.

After loading the firmware, the MFD device should create the
platform devices based upon the firmware.

So, if only one PRU is used for UART, then the other PRU can be
used for CAN and the MFD should create two platform_devices.

If the UART uses both the PRUs, then the MFD should download
the firmware into both the PRUs but create only one platform_device.

But, in this case how do we download two different firmware
on two different PRUs. One way is to keep the firmware files
as its now, but add another file say firmware-config.txt,
consisting a list of parameters like,

START
MFD_ID0#0
MFD_ID0_PRU_NUM#PRU0
MFD_ID1#1
MFD_ID1_PRU_NUM#PRU1
END

OR

START
MFD_ID0#0
MFD_ID0_PRU_NUM#PRU0:PRU1
END

So, the MFD driver can do a request_firmware on this file first,
parse the device info and decide to request the main firmware.
This becomes something like the devices table that we have on
PPC.

Also, if PRU0 is loaded, we need some way of maintaining the
usage_count, So that the PRU0 is not loaded again accidently.
We can increase the usage_count from the MFD driver.
But, to decrement the usage_count, we can add an API
which will be called when the CAN or UART driver is rmmod.


Now how do we handle switch between devices.

We can either do a rmmod of the MFD driver, then again modprobe it.
So, the request_firmware is run again and the appropriate device is
loaded based upon the changed firmware-config.txt.

But, this does not look good, say what if the MFD driver is in-build.
Another way is that we can add a sysfs entry, which when written
with anything can re-evaluate the firmware_config.

What the hell, does anything make any sense ?


> Hi Subhasish,
>
> On Wed, May 04, 2011 at 12:48:43, Subhasish Ghosh wrote:
>> Hi Arnd,
>>
>> How about just doing something like:
>>
>> #> echo da8xx_pruss_uart >> firmware.bin
>>
>> i.e  just append the device name (from the board file) into the firmware
>> file.
>>
>> In the driver probe, we can parse from the bottom, when it reaches
>> "da8xx_pruss", the rest of the upper data is the firmware and from
>> the full name, we can determine if it's a CAN, UART or any other
>> peripheral.
>>
>> So, based on the platform_data, which the MFD driver received,
>> it can find out which device to initialize.
>
> If you are defining a firmware header, it may be
> worthwhile making sure you include information
> on features of the device being supported (I
> assume there will be differences in CAN features if
> the firmware uses both PRUs to support CAN versus
> UART on one PRU and CAN on another PRU).
>
> The MFD driver can parse this information and
> pass this on to the UART or CAN drivers.
>
> Thanks,
> Sekhar
>
>>
>> Also, does the line wrapping look any better ?
>>
>>
>> > On Thursday 28 April 2011 09:17:21 Subhasish Ghosh wrote:
>> >> >
>> >> > You can easily do that by adding a small header to the firmware
>> >> > format and interpret that header by the MFD driver. When the name
>> >> > of the subdevice is part of that header, the MFD driver does not
>> >> > need to understand the difference, it can simply pass that on
>> >> > when creating its child devices.
>> >>
>> >> I don't understand why loading the firmware should be done at the MFD
>> >> driver.
>> >> The user already specifies the device he/she wants to start on the PRU
>> >> via
>> >> modprobe.
>> >> A driver can be inserted, which can download a printer firmware on one
>> >> PRU
>> >> and a
>> >> scanner firmware on the other. This way both cores can be used for
>> >> separate
>> >> purposes.
>> >> I mean, say in a real MFD controller, that will also have two separate
>> >> cores
>> >> running on it,
>> >> just that, the firmware on it would not be downloaded runtime but 
>> >> fused
>> >> in
>> >> some non volatile memory.
>> >
>> > Then I must be misreading what your code currently does, because it 
>> > does
>> > not
>> > match your explanations. What I see in the platform code is that you
>> > create
>> > MFD cells for specific devices that get automatically created by the 
>> > MFD
>> > driver. This will cause udev to load the drivers for these devices, 
>> > which
>> > then load the firmware they need.
>> >
>> > Also, I cannot see how the method you describe would make it possible 
>> > to
>> > the same driver into both units, e.g. when you want to have two serial
>> > ports. The reason is that you currently hardcode the PRU number in the
>> > driver and that you cannot load a single driver twice.
>> >
>> > Finally, I'm trying to make sure that whatever solution you come up 
>> > with
>> > will still work when we migrate the code to using a flattened device 
>> > tree.
>> > In that case, you would ideally put the device firmware into the device
>> > tree as a property that matches whatever you have connected on the
>> > specific
>> > board (at least as an option, you can still fall back to
>> > request_firmware).
>> > You definitely want automatic module loading in that case.
>> >
>> > Note that using module loading with specific parameters in order to
>> > match the hardware is not a recommended procedure any more. The code
>> > really needs to work the same way when all drivers are built into the
>> > kernel. It should not be hard to use the firmware loading mechanism
>> > in the MFD driver to both load the firmware and configure the devices
>> > appropriately so we always use the right driver for the currently
>> > active devices.
>> >
>> > Arnd
>> >
>> > BTW, something is wrong with your email client line wrapping. I've 
>> > fixed
>> > this up manually before when replying, but please find a way to get 
>> > this
>> > right in the future.
>>
>>
> 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-05 13:25                   ` Subhasish Ghosh
@ 2011-05-05 14:12                     ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-05 14:12 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

On Thursday 05 May 2011, Subhasish Ghosh wrote:
> I am a bit lost,
> 
> If I understand correctly, there are two problems
> 
> 1. In case of udev based driver loading, we will end up
> loading both the drivers and the associated firmware.
> This is not acceptable because both UART & CAN
> use PRU0 & PRU1.
> 
> 2. How do we switch between devices at run time.
> This is required because MFD devices should be
> capable of doing that.
> 
> 
> Ok, if that understanding is somewhat correct, then, what we are
> trying to do is load the firmware from the MFD driver itself.

I would describe the problem differently:

You hardcode the usage of the pruss in the platform code,
even though it is completely defined by the software you
load into it. I think it is essential that all the configuration
of the pruss is dynamic and not hardcoded in the platform
code, so that it is at all possible to load other firmware
into it.

Describing the device in the firmware file instead of the platform
code is one way to get there, but there may be other ways that
you could come up with.

> So, in case of a switch between device, say from UART to CAN,
> all the user has to do is copy a new firmware.
> 
> This firmware should contain some info regarding the device, like
> say, device name & prunum.

Right.

> So, in case a device requires both PRUs, then the firmware would
> download for both PRUs.
> 
> In case a device requires only one PRU, then it can be downloaded
> only into the requested PRU. So, the other PRU remains open for
> any other firmware/device.
> 
> After loading the firmware, the MFD device should create the
> platform devices based upon the firmware.
> 
> So, if only one PRU is used for UART, then the other PRU can be
> used for CAN and the MFD should create two platform_devices.
> 
> If the UART uses both the PRUs, then the MFD should download
> the firmware into both the PRUs but create only one platform_device.

As I mentioned, I did not have a good idea for how to abstract
the fact that there may be either one or two child devices,
depending on the firmware. A possible way to deal with this
would be to have only a single firmware image files that contains
the code for both PRUs, with a header indicating how many devices
there should be and what they are called.

> But, in this case how do we download two different firmware
> on two different PRUs. One way is to keep the firmware files
> as its now, but add another file say firmware-config.txt,
> consisting a list of parameters like,
> 
> START
> MFD_ID0#0
> MFD_ID0_PRU_NUM#PRU0
> MFD_ID1#1
> MFD_ID1_PRU_NUM#PRU1
> END
> 
> OR
> 
> START
> MFD_ID0#0
> MFD_ID0_PRU_NUM#PRU0:PRU1
> END
> 
> So, the MFD driver can do a request_firmware on this file first,
> parse the device info and decide to request the main firmware.
> This becomes something like the devices table that we have on
> PPC.

Yes, this would be another option. I generally don't like
parsing data in the kernel, but it's not completely unrealistic.

> Also, if PRU0 is loaded, we need some way of maintaining the
> usage_count, So that the PRU0 is not loaded again accidently.
> We can increase the usage_count from the MFD driver.
> But, to decrement the usage_count, we can add an API
> which will be called when the CAN or UART driver is rmmod.

Not necesarily. You can make the interface so that the
child device gets registered after the firmware got loaded,
but unregistered if you start loading new firmware. We have
hotplug support for a lot of devices, and it's not hard to
write the serial/can/... drivers in a way that allows the
underlying device to go away.

You should not actually need to unload the device driver.
E.g. when the drivers are built into the kernel, you can still
remove the device and put it back in there using the 
->probe and ->remove callbacks of the platform driver.

> Now how do we handle switch between devices.
> 
> We can either do a rmmod of the MFD driver, then again modprobe it.
> So, the request_firmware is run again and the appropriate device is
> loaded based upon the changed firmware-config.txt.
> 
> But, this does not look good, say what if the MFD driver is in-build.
> Another way is that we can add a sysfs entry, which when written
> with anything can re-evaluate the firmware_config.

Yes, I think that a sysfs entry would be good here, basically
to reset the entire unit and remove the child devices, followed
by a new call to request_firmware.

Instead of passing a configuration file into the MFD driver and
calling it a firmware, I can see three other options that I believe
would be nicer:

1. have a single firmware blob that describes the child devices
and the code that is to be loaded into both units. If they are
acting as one device, either make sure you only create one
child node, or create one with a name that no driver binds to.

2. Call request_firmware separately for the two child devices,
and configure them separately based on the information in the
firmware files. In the case where they should act as a single
device, call the children e.g. "pruss-uart-a" and "pruss-uart-b",
then bind to both names in the pruss-uart drivers and only
start using the device when you have both nodes for the same
parent.

3. Do the configuration through sysfs files in the MFD device node,
which then cause the creation of the child devices. This means you
need extra user space scripts to write the addititonal files, but
is also the most flexible way.


	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-05 14:12                     ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-05 14:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 05 May 2011, Subhasish Ghosh wrote:
> I am a bit lost,
> 
> If I understand correctly, there are two problems
> 
> 1. In case of udev based driver loading, we will end up
> loading both the drivers and the associated firmware.
> This is not acceptable because both UART & CAN
> use PRU0 & PRU1.
> 
> 2. How do we switch between devices at run time.
> This is required because MFD devices should be
> capable of doing that.
> 
> 
> Ok, if that understanding is somewhat correct, then, what we are
> trying to do is load the firmware from the MFD driver itself.

I would describe the problem differently:

You hardcode the usage of the pruss in the platform code,
even though it is completely defined by the software you
load into it. I think it is essential that all the configuration
of the pruss is dynamic and not hardcoded in the platform
code, so that it is at all possible to load other firmware
into it.

Describing the device in the firmware file instead of the platform
code is one way to get there, but there may be other ways that
you could come up with.

> So, in case of a switch between device, say from UART to CAN,
> all the user has to do is copy a new firmware.
> 
> This firmware should contain some info regarding the device, like
> say, device name & prunum.

Right.

> So, in case a device requires both PRUs, then the firmware would
> download for both PRUs.
> 
> In case a device requires only one PRU, then it can be downloaded
> only into the requested PRU. So, the other PRU remains open for
> any other firmware/device.
> 
> After loading the firmware, the MFD device should create the
> platform devices based upon the firmware.
> 
> So, if only one PRU is used for UART, then the other PRU can be
> used for CAN and the MFD should create two platform_devices.
> 
> If the UART uses both the PRUs, then the MFD should download
> the firmware into both the PRUs but create only one platform_device.

As I mentioned, I did not have a good idea for how to abstract
the fact that there may be either one or two child devices,
depending on the firmware. A possible way to deal with this
would be to have only a single firmware image files that contains
the code for both PRUs, with a header indicating how many devices
there should be and what they are called.

> But, in this case how do we download two different firmware
> on two different PRUs. One way is to keep the firmware files
> as its now, but add another file say firmware-config.txt,
> consisting a list of parameters like,
> 
> START
> MFD_ID0#0
> MFD_ID0_PRU_NUM#PRU0
> MFD_ID1#1
> MFD_ID1_PRU_NUM#PRU1
> END
> 
> OR
> 
> START
> MFD_ID0#0
> MFD_ID0_PRU_NUM#PRU0:PRU1
> END
> 
> So, the MFD driver can do a request_firmware on this file first,
> parse the device info and decide to request the main firmware.
> This becomes something like the devices table that we have on
> PPC.

Yes, this would be another option. I generally don't like
parsing data in the kernel, but it's not completely unrealistic.

> Also, if PRU0 is loaded, we need some way of maintaining the
> usage_count, So that the PRU0 is not loaded again accidently.
> We can increase the usage_count from the MFD driver.
> But, to decrement the usage_count, we can add an API
> which will be called when the CAN or UART driver is rmmod.

Not necesarily. You can make the interface so that the
child device gets registered after the firmware got loaded,
but unregistered if you start loading new firmware. We have
hotplug support for a lot of devices, and it's not hard to
write the serial/can/... drivers in a way that allows the
underlying device to go away.

You should not actually need to unload the device driver.
E.g. when the drivers are built into the kernel, you can still
remove the device and put it back in there using the 
->probe and ->remove callbacks of the platform driver.

> Now how do we handle switch between devices.
> 
> We can either do a rmmod of the MFD driver, then again modprobe it.
> So, the request_firmware is run again and the appropriate device is
> loaded based upon the changed firmware-config.txt.
> 
> But, this does not look good, say what if the MFD driver is in-build.
> Another way is that we can add a sysfs entry, which when written
> with anything can re-evaluate the firmware_config.

Yes, I think that a sysfs entry would be good here, basically
to reset the entire unit and remove the child devices, followed
by a new call to request_firmware.

Instead of passing a configuration file into the MFD driver and
calling it a firmware, I can see three other options that I believe
would be nicer:

1. have a single firmware blob that describes the child devices
and the code that is to be loaded into both units. If they are
acting as one device, either make sure you only create one
child node, or create one with a name that no driver binds to.

2. Call request_firmware separately for the two child devices,
and configure them separately based on the information in the
firmware files. In the case where they should act as a single
device, call the children e.g. "pruss-uart-a" and "pruss-uart-b",
then bind to both names in the pruss-uart drivers and only
start using the device when you have both nodes for the same
parent.

3. Do the configuration through sysfs files in the MFD device node,
which then cause the creation of the child devices. This means you
need extra user space scripts to write the addititonal files, but
is also the most flexible way.


	Arnd

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-22 12:08   ` Subhasish Ghosh
@ 2011-05-09 13:39     ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-09 13:39 UTC (permalink / raw)
  To: davinci-linux-open-source, Greg Kroah-Hartman
  Cc: linux-arm-kernel, m-watkins, nsekhar, sachi,
	Greg Kroah-Hartman (maintainer:TTY LAYER,commit_signer:2/4=50% 
	,commit_signer:1/2=50%), Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

Hi Greg,

I am observing a RX FIFO sized data loss problem with my driver.

I observed that if I start the TX before the RX, then there are no errors,
but, if I start a TX after a RX, then I observe the error (FIFO sized data 
chunks missing).

Say, for example, if I use all three UARTS and on all three I start RX, then 
for every TX started I would observe
one error on all the RX data buffer.

So, if I start only two TX, then I will see only two errors on all the three 
RX UARTS.

>From this observation I concluded that somehow the TX start was effecting 
the RX.
So, I disabled the complete TX section in the driver, but even when the 
complete TX was disabled
I observed the same errors in RX.

>From here I concluded that the error was happening before my drivers TX 
routine was getting called.
I traced it down to the below function, this is a sub-system specific 
function in the file serial-core.c

static int uart_carrier_raised(struct tty_port *port)
{
        struct uart_state *state = container_of(port, struct uart_state, 
port);
        struct uart_port *uport = state->uart_port;
        int mctrl;

        spin_lock_irq(&uport->lock);
        uport->ops->enable_ms(uport);
        mctrl = uport->ops->get_mctrl(uport);
        spin_unlock_irq(&uport->lock);
        if (mctrl & TIOCM_CAR) {
                return 1;
        }
        return 0;
}

In this function I moved the "return 1" to the beginning of the function, 
this solved the bug that we are having. There was no data loss.

I think, the two spin locks used in this function is somehow effecting the 
RX.

I then modified this function to as follows and the error is not observed 
anymore.

static int uart_carrier_raised(struct tty_port *port)
{
        struct uart_state *state = container_of(port, struct uart_state, 
port);
        struct uart_port *uport = state->uart_port;
        int mctrl;
        unsigned long flags = 0;

        spin_lock_irqsave(&uport->lock, flags);
        uport->ops->enable_ms(uport);
        mctrl = uport->ops->get_mctrl(uport);
        spin_unlock_irqrestore(&uport->lock, flags);
        if (mctrl & TIOCM_CAR) {
                return 1;
        }
        return 0;
}

Is this a BUG in the TTY sub-system or am I doing something wrong in my 
driver.

I also changed one driver function to as follows:

static u32 pruss_suart_get_mctrl(struct uart_port *port)
{
        return TIOCM_CAR;
}

Best Regards,
Subhasish Ghosh
--------------------------------------------------
From: "Subhasish Ghosh" <subhasish@mistralsolutions.com>
Sent: Friday, April 22, 2011 5:38 PM
To: <davinci-linux-open-source@linux.davincidsp.com>
Cc: <linux-arm-kernel@lists.infradead.org>; <m-watkins@ti.com>; 
<nsekhar@ti.com>; <sachi@mistralsolutions.com>; "Subhasish Ghosh" 
<subhasish@mistralsolutions.com>; "Greg Kroah-Hartman (maintainer:TTY 
LAYER,commit_signer:2/4=50%,commit_signer:1/2=50%)" <gregkh@suse.de>; 
"Andrew Morton (commit_signer:1/4=25%)" <akpm@linux-foundation.org>; "Randy 
Dunlap (commit_signer:1/4=25%)" <randy.dunlap@oracle.com>; "open list" 
<linux-kernel@vger.kernel.org>
Subject: [PATCH v4 08/11] tty: add pruss SUART driver

> This patch adds support for the TTY compliant
> Soft-UART device emulated on PRUSS.
>
> This patch depends on:
> davinci: macro rename DA8XX_LPSC0_DMAX to DA8XX_LPSC0_PRUSS.
>            https://patchwork.kernel.org/patch/615681/
> davinci: changed SRAM allocator to shared ram.
>            https://patchwork.kernel.org/patch/549351/
>
> Signed-off-by: Subhasish Ghosh <subhasish@mistralsolutions.com>
> ---
> drivers/tty/serial/Kconfig             |   18 +
> drivers/tty/serial/Makefile            |    6 +
> drivers/tty/serial/pruss_suart.c       | 1061 ++++++++++++++++++++
> drivers/tty/serial/pruss_suart.h       | 1038 +++++++++++++++++++
> drivers/tty/serial/pruss_suart_api.c   | 1710 
> ++++++++++++++++++++++++++++++++
> drivers/tty/serial/pruss_suart_utils.c |  393 ++++++++
> include/linux/serial_core.h            |    2 +
> 7 files changed, 4228 insertions(+), 0 deletions(-)
> create mode 100644 drivers/tty/serial/pruss_suart.c
> create mode 100644 drivers/tty/serial/pruss_suart.h
> create mode 100644 drivers/tty/serial/pruss_suart_api.c
> create mode 100644 drivers/tty/serial/pruss_suart_utils.c
>
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 2b83346..6c26ebf 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1596,4 +1596,22 @@ 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.
> +
> +config SERIAL_PRUSS_SUART
> + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850
> + select SERIAL_CORE
> + tristate "PRUSS based SoftUART emulation on DA8XX"
> + ---help---
> + This driver emulates up to eight different UARTs on the PRUSS.
> + You may modify the NR_SUARTS macro in the driver to emulate
> + less number of UARTS as per your requirement.
> + If not sure, mark No
> +
> +config PRUSS_SUART_MCASP
> + depends on ARCH_DAVINCI_DA830 && SERIAL_PRUSS_SUART
> + default "0"
> + int "McASP number"
> + ---help---
> + Enter the McASP number to use with SUART (0, 1 or 2).
> + You will need to recompile the kernel if this is changed.
> endmenu
> diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
> index 8ea92e9..e1eaaf3 100644
> --- a/drivers/tty/serial/Makefile
> +++ b/drivers/tty/serial/Makefile
> @@ -92,3 +92,9 @@ 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
> +
> +pruss_uart-objs := pruss_suart.o \
> + pruss_suart_api.o \
> + pruss_suart_utils.o
> +
> +obj-$(CONFIG_SERIAL_PRUSS_SUART) += pruss_uart.o
> diff --git a/drivers/tty/serial/pruss_suart.c 
> b/drivers/tty/serial/pruss_suart.c
> new file mode 100644
> index 0000000..37c3c21
> --- /dev/null
> +++ b/drivers/tty/serial/pruss_suart.c
> @@ -0,0 +1,1061 @@
> +/*
> + * 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) 2010, 2011 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 <linux/platform_device.h>
> +#include <linux/firmware.h>
> +#include <linux/clk.h>
> +#include <linux/serial_reg.h>
> +#include <linux/delay.h>
> +#include <linux/bitops.h>
> +#include <mach/sram.h>
> +#include "pruss_suart.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
> +
> +/* 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;
> + unsigned long tx_empty[NR_SUART];
> + struct clk *clk_mcasp;
> + struct suart_fifo suart_fifo_addr[NR_SUART];
> + struct suart_handle suart_hdl[NR_SUART];
> + struct pruss_suart_iomap suart_iomap;
> + struct tasklet_struct tx_task[NR_SUART];
> + 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;
> + unsigned long flags = 0;
> + struct uart_port *port = &soft_uart->port[uart_no];
> + 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 */
> + spin_lock_irqsave(&port->lock, flags);
> + 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]);
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +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 (uart_circ_empty(xmit) ||
> + uart_tx_stopped(&soft_uart->port[uart_no])) {
> + pruss_suart_stop_tx(&soft_uart->port[uart_no]);
> + set_bit(0, &soft_uart->tx_empty[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 (pru_softuart_write(dev,
> + &soft_uart->suart_hdl[uart_no],
> + (u32 *)&soft_uart->suart_fifo_addr
> + [uart_no].fifo_phys_addr_tx, count) != 0) {
> + dev_err(dev, "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 suart_tx_task(unsigned long data)
> +{
> + struct uart_port *port = (struct uart_port *)data;
> + struct omapl_pru_suart *soft_uart =
> + container_of(port, struct omapl_pru_suart, port[port->line]);
> +
> + omapl_pru_tx_chars(soft_uart, port->line);
> +}
> +
> +static void omapl_pru_rx_chars(struct omapl_pru_suart *soft_uart, u32 
> uart_no)
> +{
> + struct tty_struct *tty = NULL;
> + 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]);
> +
> + pru_softuart_read_data(dev, &soft_uart->suart_hdl[uart_no],
> + suart_data, data_len + 1, &data_len_read);
> +
> + tty = tty_port_tty_get(&soft_uart->port[uart_no].state->port);
> +
> + if (!tty)
> + return;
> +
> + /* 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 {
> + 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;
> + }
> + 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]);
> + tty_flip_buffer_push(tty);
> + tty_kref_put(tty);
> +}
> +
> +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(&port->lock, flags);
> +
> + do {
> + ret = pru_softuart_get_isrstatus(dev, uart_num, &txrx_flag);
> + if (ret != 0) {
> + dev_err(dev, "suart%d: failed to get interrupt, ret:"
> + " 0x%X txrx_flag 0x%X\n",
> + port->line, ret, txrx_flag);
> + spin_unlock_irqrestore(&port->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]);
> + tasklet_schedule(&soft_uart->tx_task[port->line]);
> + }
> + } while (txrx_flag & (PRU_RX_INTR | PRU_TX_INTR));
> +
> + spin_unlock_irqrestore(&port->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;
> + unsigned long flags = 0;
> +
> + spin_lock_irqsave(&port->lock, flags);
> + /* 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);
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void pruss_suart_enable_ms(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;
> + dev_err(dev, "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;
> + unsigned long flags = 0;
> +
> + /* unmask the tx interrupts */
> + spin_lock_irqsave(&port->lock, flags);
> + suart_intr_setmask(dev, soft_uart->suart_hdl[port->line].uart_num,
> +    PRU_TX_INTR, CHN_TXRX_IE_MASK_CMPLT);
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> + if (test_and_clear_bit(0, &soft_uart->tx_empty[port->line]))
> + 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)
> +{
> + struct omapl_pru_suart *soft_uart =
> +     container_of(port, struct omapl_pru_suart, port[port->line]);
> + struct device *dev = soft_uart->dev;
> + dev_dbg(dev, "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 &= ~(CRTSCTS | CMSPAR | CSTOPB
> +       | PARENB | PARODD | CMSPAR);
> + }
> +
> + 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 (pru_softuart_setdatabits
> + (dev, &soft_uart->suart_hdl[port->line], cval, cval) != 0)
> + dev_err(dev, "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 (pru_softuart_setbaud(dev, &soft_uart->suart_hdl[port->line],
> + SUART_DEFAULT_BAUD / baud,
> + SUART_DEFAULT_BAUD / baud) != 0)
> + dev_err(dev, "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);
> + }
> +/*
> + * Characters 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);
> + }
> + /*
> + * update the per port timeout
> + */
> + uart_update_timeout(port, termios->c_cflag, baud);
> +
> + 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;
> + unsigned long flags = 0;
> + s32 retval;
> +
> + /*
> + * Disable interrupts from this port
> + */
> + spin_lock_irqsave(&port->lock, flags);
> + 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);
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> + 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
> + */
> + spin_lock_irqsave(&port->lock, flags);
> + 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);
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> + 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;
> + unsigned long flags = 0;
> +
> + /*
> + * Disable interrupts from this port
> + */
> + /* Disable BI and FE intr */
> + spin_lock_irqsave(&port->lock, flags);
> + 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);
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> + /* 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;
> + struct suart_config pru_suart_config;
> + s16 timeout = 0;
> + u32 err = 0;
> +
> + if (soft_uart == NULL) {
> + dev_err(&pdev->dev, "soft_uart ptr failed\n");
> + return -ENODEV;
> + }
> + err = pru_softuart_open(&soft_uart->suart_hdl[port->line]);
> + if (err != 0) {
> + dev_err(&pdev->dev, "failed to open suart: %d\n", err);
> + err = -ENODEV;
> + goto exit;
> + }
> + set_bit(0, &soft_uart->tx_empty[port->line]);
> +
> + /* set fifo /timeout */
> + if (SUART_FIFO_TIMEOUT_MIN > suart_timeout) {
> + dev_err(&pdev->dev, "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) {
> + dev_err(&pdev->dev, "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_softuart_setconfig(dev, &soft_uart->suart_hdl[port->line],
> + &pru_suart_config) != 0) {
> + 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 struct pruss_suart_initparams init_params = {
> + .tx_baud_value = SUART_DEFAULT_BAUD,
> + .rx_baud_value = SUART_DEFAULT_BAUD,
> + .oversampling = SUART_DEFAULT_OVRSMPL,
> +};
> +
> +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;
> + struct resource *res;
> + struct clk *clk_pruss = NULL;
> + const struct firmware *fw;
> + s32 err, i;
> +
> + pdata = dev->platform_data;
> + if (!pdata) {
> + dev_err(&pdev->dev, "platform data not found\n");
> + return -EINVAL;
> + }
> + (pdata->setup)();
> +
> + soft_uart = kzalloc(sizeof(struct omapl_pru_suart), GFP_KERNEL);
> + if (!soft_uart)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get resource");
> + return -ENOMEM;
> + }
> +
> + if (!request_mem_region(res->start,
> + resource_size(res),
> + 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(res->start,
> + resource_size(res));
> + 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;
> +
> + clk_pruss = clk_get(NULL, "pruss");
> + if (IS_ERR(clk_pruss)) {
> + dev_err(&pdev->dev, "no clock available: pruss\n");
> + err = -ENODEV;
> + goto probe_exit_iounmap;
> + }
> + soft_uart->clk_freq_pru = clk_get_rate(clk_pruss);
> + clk_put(clk_pruss);
> +
> + 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(&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", fw->size);
> +
> + /* download firmware into pru  & init */
> + err = pru_softuart_init(dev, &init_params, fw->data, fw->size,
> + soft_uart->clk_freq_pru / 1000000,
> + &soft_uart->suart_iomap);
> + if (err) {
> + dev_err(&pdev->dev, "pruss init error\n");
> + err = -ENODEV;
> + goto probe_release_fw;
> + }
> + release_firmware(fw);
> +
> + 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 =
> + soft_uart->suart_iomap.mcasp_io_addr;
> + 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;
> + 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;
> + tasklet_init(&soft_uart->tx_task[i], suart_tx_task,
> + (unsigned long)&soft_uart->port[i]);
> + uart_add_one_port(&pruss_suart_reg, &soft_uart->port[i]);
> + }
> +
> + 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(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(res->start,
> + resource_size(res));
> +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;
> + struct resource *res;
> + int i;
> +
> + pdata = dev->platform_data;
> + if (!pdata)
> + dev_err(&pdev->dev, "platform data not found\n");
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get resource");
> + return -ENOMEM;
> + }
> +
> + 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);
> + clk_put(soft_uart->clk_mcasp);
> + pru_mcasp_deinit();
> + clk_disable(soft_uart->clk_mcasp);
> + iounmap(soft_uart->suart_iomap.mcasp_io_addr);
> + if (pdata) {
> + release_mem_region(res->start,
> + resource_size(res));
> + }
> + 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;
> +
> + pr_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);
> + pr_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/pruss_suart.h 
> b/drivers/tty/serial/pruss_suart.h
> new file mode 100644
> index 0000000..f3a2a9d
> --- /dev/null
> +++ b/drivers/tty/serial/pruss_suart.h
> @@ -0,0 +1,1038 @@
> +/*
> + * Copyright (C) 2010, 2011 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/io.h>
> +#include <linux/mfd/pruss.h>
> +
> +#define SINGLE_PRU 0
> +#define BOTH_PRU 1
> +#define PRU_ACTIVE BOTH_PRU
> +#define PRU_CLK_228 228
> +#define PRU_CLK_186 186
> +
> +#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)
> +
> +#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)
> +
> +#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 | \
> + PRU_SUART_HALF_RX)
> +#define PRU_SUART3_CONFIG_RX_SER (PRU_SUART_SERIALIZER_13)
> +#define PRU_SUART3_CONFIG_TX_SER (PRU_SUART_SERIALIZER_14)
> +
> +#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)
> +
> +#define SUART_NUM_OF_CHANNELS_PER_SUART 2
> +#define SUART_NUM_OF_BYTES_PER_CHANNEL 16
> +
> +#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_TX_OVRSMPL 0
> +#define SUART_DEFAULT_OVRSMPL SUART_8X_OVRSMPL
> +
> +#define SUART_DEFAULT_OVRSMPL_OFFSET 26
> +#define SUART_CHN_OFFSET 31
> +#define SERIALIZER_OFFSET 8
> +
> +#if (SUART_DEFAULT_OVRSMPL == SUART_16X_OVRSMPL)
> +#define SUART_DEFAULT_BAUD 57600
> +#else
> +#define SUART_DEFAULT_BAUD 115200
> +#endif
> +
> +#define PRU_MODE_INVALID 0x0
> +#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)
> +
> +/* MCASP */
> +
> +#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)
> +
> +/* SUART REGS */
> +
> +/* 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 STATUS Register*/
> +#define PRU_SUART_CH_STATUS_EN_BIT_MASK 0x8000
> +
> +/* 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)
> +
> +/* 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)
> +
> +/*
> + *  This enum is used to specify the direction of the channel in UART
> + */
> +enum SUART_CHN_DIR {
> + SUART_CHN_TX = 1,
> + SUART_CHN_RX = 2
> +};
> +
> +/*
> + *  This enum is used to specify the state of the channel in UART. It
> + *  is either enabled or disabled.
> + */
> +enum SUART_CHN_STATE {
> + SUART_CHN_DISABLED = 0,
> + SUART_CHN_ENABLED = 1
> +};
> +
> +enum SUART_EN_BITSPERCHAR {
> + 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
> +};
> +
> +enum SUART_EN_UARTNUM {
> + 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
> +};
> +
> +enum SUART_EN_UARTTYPE {
> + ePRU_SUART_HALF_TX = 1,
> + ePRU_SUART_HALF_RX,
> + ePRU_SUART_FULL_TX_RX,
> + ePRU_SUART_HALF_TX_DISABLED = 4,
> + ePRU_SUART_HALF_RX_DISABLED = 8
> +};
> +
> +enum SUART_EN_TXCHANNEL {
> + 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
> +};
> +
> +enum SUART_EN_RXCHANNEL {
> + 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
> +};
> +
> +enum SUART_EN_UART_STATUS {
> + ePRU_SUART_UART_FREE = 0,
> + ePRU_SUART_UART_IN_USE
> +};
> +
> +struct pru_suart_cnh_cntrl_config1 {
> + u32 mode:2;
> + u32 service_req:1;
> + u32 asp_id:2;
> + u32 reserved1:3;
> + u32 serializer_num:4;
> + u32 reserved2:4;
> + u32 presacler:10;
> + u32 over_sampling:2;
> + u32 framing_mask:1;
> + u32 break_mask:1;
> + u32 timeout_mask:1;
> + u32 reserved3:1;
> +};
> +
> +struct pru_suart_chn_config2_status {
> + u32 bits_per_char:4;
> + u32 reserved1:4;
> + u32 data_len:4;
> + u32 reserved2:4;
> + u32 txrx_ready:1;
> + u32 txrx_complete:1;
> + u32 txrx_error:1;
> + u32 txrx_underrun:1;
> + u32 framing_error:1;
> + u32 break_error:1;
> + u32 timeout_error:1;
> + u32 reserved3:8;
> + u32 chn_state:1;
> +};
> +
> +struct pru_suart_regs_ovly {
> + struct pru_suart_cnh_cntrl_config1 ch_ctrl_config1;
> + struct pru_suart_chn_config2_status ch_config2_txrx_status;
> + u32 ch_txrx_data;
> + u32 reserved1;
> +};
> +
> +struct pru_suart_tx_cntx_priv {
> + u32 asp_xsrctl_base;
> + u32 asp_xbuf_base;
> + u16 buff_addr;
> + u8 buff_size;
> + u8 bits_loaded;
> +};
> +
> +struct pru_suart_rx_cntx_priv {
> + u32 asp_rbuf_base;
> + u32 asp_rsrctl_base;
> + u32 reserved1;
> + u32 reserved2;
> + u32 reserved3;
> + u32 reserved4;
> +};
> +
> +struct suart_config {
> + 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;
> +};
> +
> +struct suart_handle {
> + u16 uart_num;
> + u16 uart_type;
> + u16 uart_tx_channel;
> + u16 uart_rx_channel;
> + u16 uart_status;
> +};
> +
> +struct pruss_suart_iomap {
> + void __iomem *mcasp_io_addr;
> + void *p_fifo_buff_phys_base;
> + void *p_fifo_buff_virt_base;
> +};
> +
> +struct pruss_suart_initparams {
> + u32 tx_baud_value;
> + u32 rx_baud_value;
> + u32 oversampling;
> +};
> +
> +/* MCASP */
> +struct omapl_mcasp_regs_ovly {
> + 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 ditcsra[6];
> + u32 ditcsrb[6];
> + u32 ditudra[6];
> + u32 ditudrb[6];
> + 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 xbuf[16];
> + u32 rsvd7[16];
> + u32 rbuf[16];
> +};
> +
> +/*
> + *  SUART Config regs
> + */
> +struct suart_struct_pru_regs {
> + u16 chn_ctrl;
> + u16 chn_config1;
> + u16 chn_config2;
> + u16 chn_txrx_status;
> + u32 chn_txrx_data;
> +};
> +
> +extern s32 pru_softuart_init(struct device *dev,
> + struct pruss_suart_initparams *,
> + const u8 *pru_suart_emu_code, u32 fw_size,
> + u32 clk_rate_pruss,
> + struct pruss_suart_iomap *pruss_ioaddr);
> +
> +extern s32 pru_softuart_open(struct suart_handle *h_suart);
> +
> +extern s32 pru_softuart_close(struct suart_handle *h_uart);
> +
> +extern s32 pru_softuart_setbaud(struct device *dev,
> + struct suart_handle *h_uart,
> + u16 tx_clk_divisor, u16 rx_clk_divisor);
> +
> +extern s32 pru_softuart_setdatabits(struct device *dev,
> + struct suart_handle *h_uart,
> + u16 tx_data_bits, u16 rx_data_bits);
> +
> +extern s32 pru_softuart_setconfig(struct device *dev,
> + struct suart_handle *h_uart,
> + struct suart_config *config_uart);
> +
> +extern s32 pru_softuart_getconfig(struct device *dev,
> + struct suart_handle *h_uart,
> + struct suart_config *config_uart);
> +
> +extern s32 pru_softuart_pending_tx_request(struct device *dev);
> +
> +extern s32 pru_softuart_write(struct device *dev,
> + struct suart_handle *h_uart,
> + u32 *pt_tx_data_buf, u16 data_len);
> +
> +extern s32 pru_softuart_read(struct device *dev,
> + struct suart_handle *h_uart,
> + u32 *pt_data_buf, u16 data_len);
> +
> +extern s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
> + u32 txrxmode,
> + u32 intrmask);
> +
> +extern s32 pru_softuart_clr_tx_status(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 pru_softuart_get_tx_status(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 pru_softuart_clr_rx_status(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 pru_softuart_get_rx_status(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num,
> + u16 *txrx_flag);
> +
> +extern s32 pru_intr_clr_isrstatus(struct device *dev, u16 uart_num,
> + u32 txrxmode);
> +
> +extern s32 suart_intr_getmask(struct device *dev, u16 uart_num,
> + u32 txrxmode,
> + u32 intrmask);
> +
> +extern s32 suart_intr_setmask(struct device *dev, u16 uart_num,
> + u32 txrxmode, u32 intrmask);
> +
> +extern s32 pru_softuart_get_tx_data_len(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 pru_softuart_get_rx_data_len(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 suart_arm_to_pru_intr(struct device *dev, u16 uart_num);
> +
> +extern void pru_mcasp_deinit(void);
> +
> +extern s32 pru_softuart_read_data(struct device *dev,
> + struct suart_handle *h_uart,
> + u8 *p_data_buffer, s32 max_len,
> + u32 *pdata_read);
> +
> +extern s32 pru_softuart_stop_receive(struct device *dev,
> + struct suart_handle *h_uart);
> +
> +extern s32 suart_pru_to_host_intr_enable(struct device *dev,
> + u16 uart_num,
> + u32 txrxmode, s32 flag);
> +
> +extern void pru_set_fifo_timeout(struct device *dev, s16 timeout);
> +
> +extern void suart_mcasp_config(u32 tx_baud_value,
> + u32 rx_baud_value, u32 oversampling,
> + struct pruss_suart_iomap *pruss_ioaddr);
> +
> +extern void suart_mcasp_reset(struct pruss_suart_iomap *pruss_ioaddr);
> +
> +extern short suart_asp_baud_set(u32 tx_baud_value,
> + u32 rx_baud_value, u32 oversampling,
> + struct pruss_suart_iomap *pruss_ioaddr);
> +
> +extern short suart_asp_serializer_deactivate(u16 sr_num,
> + struct pruss_suart_iomap *pruss_ioaddr);
> +
> +extern void suart_mcasp_tx_serialzier_set(u32 serializer_num,
> + struct pruss_suart_iomap *pruss_ioaddr);
> +#endif
> diff --git a/drivers/tty/serial/pruss_suart_api.c 
> b/drivers/tty/serial/pruss_suart_api.c
> new file mode 100644
> index 0000000..15178f5
> --- /dev/null
> +++ b/drivers/tty/serial/pruss_suart_api.c
> @@ -0,0 +1,1710 @@
> +/*
> + * Copyright (C) 2010, 2011 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.h>
> +#include "pruss_suart.h"
> +
> +static u8 uart_statu_table[8];
> +static struct 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};
> +
> +static  s32 pru_softuart_clr_rx_fifo(struct device *dev,
> + struct suart_handle *h_uart);
> +static s32 arm_to_pru_intr_init(struct device *dev);
> +
> +#if (PRU_ACTIVE == BOTH_PRU)
> +static void pru_set_ram_data(struct device *dev,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + u32 datatowrite;
> + u32 i;
> + struct pru_suart_regs_ovly *pru_suart_regs = NULL;
> + u32 __iomem *p_sr_ctl_addr = (u32 __iomem *)(pruss_ioaddr->
> + mcasp_io_addr + 0x180);
> + struct pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
> + struct 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_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + 0x3, SUART_CHN_RX);
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0xF << SERIALIZER_OFFSET),
> + ((0xF & uart_rx[i]) << SERIALIZER_OFFSET));
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
> + (SUART_DEFAULT_OVRSMPL <<
> + SUART_DEFAULT_OVRSMPL_OFFSET));
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_config2_txrx_status,
> + 0xF, 8);
> + if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
> + PRU_SUART_HALF_RX_DISABLED) {
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_DISABLED << SUART_CHN_OFFSET));
> + } else {
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_ENABLED << SUART_CHN_OFFSET));
> + iowrite32(MCASP_SRCTL_RX_MODE, p_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_rmwl(dev, (u32) &pru_suart_regs->ch_txrx_data,
> + 0xFFFF, RX_DEFAULT_DATA_DUMP_ADDR);
> + pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 0);
> + /* SUART1 RX context base addr */
> + pru_suart_rx_priv = (struct pru_suart_rx_cntx_priv *)
> + (PRU0_DATARAM_OFFSET + (0x090 + (i * 0x020)));
> + datatowrite = (MCASP_RBUF_BASE_ADDR + (uart_rx[i] << 2));
> + pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rbuf_base,
> + datatowrite);
> + datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2));
> + pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
> + datatowrite);
> + }
> +
> + /* PRU1 RAM BASE ADDR */
> + pru_suart_regs = (struct 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_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + 0x3, SUART_CHN_TX);
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0xF << SERIALIZER_OFFSET),
> + ((0xF & uart_tx[i]) << SERIALIZER_OFFSET));
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
> + (SUART_DEFAULT_OVRSMPL <<
> + SUART_DEFAULT_OVRSMPL_OFFSET));
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status, 0xF, 8);
> +
> + if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
> + PRU_SUART_HALF_TX_DISABLED) {
> + pruss_rmwl(dev, (u32)
> + &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_DISABLED << SUART_CHN_OFFSET));
> + } else {
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_ENABLED << SUART_CHN_OFFSET));
> + iowrite32(MCASP_SRCTL_TX_MODE,
> + p_sr_ctl_addr + uart_tx[i]);
> + }
> + pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 1);
> +
> + /* SUART1 TX context base addr */
> + pru_suart_tx_priv = (struct pru_suart_tx_cntx_priv *)
> + (PRU1_DATARAM_OFFSET + (0x0B0 + (i * 0x02C)));
> + datatowrite = (MCASP_SRCTL_BASE_ADDR + (uart_tx[i] << 2));
> + pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xsrctl_base,
> + datatowrite);
> + datatowrite = (MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2));
> + pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
> + datatowrite);
> + /* SUART1 TX formatted data base addr */
> + datatowrite = (0x0090 + (i * 0x002C));
> + pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
> + datatowrite);
> + }
> +}
> +#else
> +static void pru_set_ram_data(struct device *dev,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> +
> + struct pru_suart_regs_ovly *pru_suart_regs =
> + (struct pru_suart_regs_ovly *)pruss_ioaddr->pru_io_addr;
> + u32 i;
> + u32 *p_sr_ctl_addr = (u32 *)(pruss_ioaddr->mcasp_io_addr + 0x180);
> + struct pru_suart_tx_cntx_priv *pru_suart_tx_priv = NULL;
> + struct pru_suart_rx_cntx_priv *pru_suart_rx_priv = NULL;
> +
> + /* Channel 0 context information is Tx */
> + for (i = 0; i < 4; i++, pru_suart_regs++) {
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + 0x3, SUART_CHN_TX);
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0xF << SERIALIZER_OFFSET),
> + ((0xF & uart_tx[i]) << SERIALIZER_OFFSET));
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
> + (SUART_DEFAULT_OVRSMPL <<
> + SUART_DEFAULT_OVRSMPL_OFFSET));
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_config2_txrx_status,
> + 0xF, 8);
> + if ((uart_config[i] & PRU_SUART_HALF_TX_DISABLED) ==
> + PRU_SUART_HALF_TX_DISABLED){
> + pruss_rmwl(dev, (u32)
> + &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_DISABLED << SUART_CHN_OFFSET));
> + } else {
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_ENABLED << SUART_CHN_OFFSET));
> + iowrite32(MCASP_SRCTL_TX_MODE,
> + p_sr_ctl_addr + uart_tx[i]);
> + }
> + pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 1);
> +
> + /* SUART1 TX context base addr */
> + pru_suart_tx_priv = (struct 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)));
> + pruss_writel(dev, (u32) &pru_suart_tx_priv->asp_xbuf_base,
> + (MCASP_XBUF_BASE_ADDR + (uart_tx[i] << 2)));
> + /* SUART1 TX formatted data base addr */
> + pruss_writel(dev, (u32) &pru_suart_tx_priv->buff_addr,
> + (0x0090 + (i * 0x050)));
> +
> + /* Channel 1 is Rx context information */
> + pru_suart_regs++;
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + 0x3, SUART_CHN_RX);
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0xF << SERIALIZER_OFFSET),
> + ((0xF & uart_rx[i]) << SERIALIZER_OFFSET));
> + pruss_rmwl(dev, (u32) &pru_suart_regs->ch_ctrl_config1,
> + (0x3 << SUART_DEFAULT_OVRSMPL_OFFSET),
> + (SUART_DEFAULT_OVRSMPL <<
> + SUART_DEFAULT_OVRSMPL_OFFSET));
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status, 0xF, 8);
> +
> + if ((uart_config[i] & PRU_SUART_HALF_RX_DISABLED) ==
> + PRU_SUART_HALF_RX_DISABLED) {
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_DISABLED << SUART_CHN_OFFSET));
> + } else {
> + pruss_rmwl(dev,
> + (u32) &pru_suart_regs->ch_config2_txrx_status,
> + (0x1 << SUART_CHN_OFFSET),
> + (SUART_CHN_ENABLED << SUART_CHN_OFFSET));
> + iowrite32(MCASP_SRCTL_RX_MODE,
> + p_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_rmwl(dev, (u32) &pru_suart_regs->ch_txrx_data,
> + 0xFFFF, RX_DEFAULT_DATA_DUMP_ADDR);
> + pruss_rmwl(dev, (u32) &pru_suart_regs->reserved1, 0xFFFF, 0);
> + /* SUART1 RX context base addr */
> + pru_suart_rx_priv = (struct 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)));
> + pruss_writel(dev, (u32) &pru_suart_rx_priv->asp_rsrctl_base,
> + (MCASP_SRCTL_BASE_ADDR + (uart_rx[i] << 2)));
> + }
> +}
> +#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);
> +}
> +
> +static void pru_set_delay_count(struct device *dev, u32 pru_freq)
> +{
> + u32 delay_cnt;
> +
> + if (pru_freq == PRU_CLK_228)
> + delay_cnt = 5;
> + else if (pru_freq == PRU_CLK_186)
> + delay_cnt = 5;
> + else
> + delay_cnt = 3;
> +
> + /* PRU 0 */
> + pruss_writeb(dev, PRU_SUART_PRU0_DELAY_OFFSET,
> + (u8) delay_cnt);
> +
> + /* PRU 1 */
> + pruss_writeb(dev, PRU_SUART_PRU1_DELAY_OFFSET,
> + (u8) delay_cnt);
> +}
> +
> +static s32 suart_set_pru_id(struct device *dev, u32 pru_no)
> +{
> + u32 offset;
> + u8 reg_val = 0;
> +
> + if (PRUSS_NUM0 == pru_no)
> + offset = PRU_SUART_PRU0_ID_ADDR;
> + else if (PRUSS_NUM1 == pru_no)
> + offset = PRU_SUART_PRU1_ID_ADDR;
> + else
> + return -EINVAL;
> +
> + reg_val = pru_no;
> + pruss_writeb(dev, offset, reg_val);
> +
> + return 0;
> +}
> +
> +/*
> + * suart Initialization routine
> + */
> +s32 pru_softuart_init(struct device *dev,
> + struct pruss_suart_initparams *init_params,
> + const u8 *pru_suart_emu_code, u32 fw_size,
> + u32 clk_rate_pruss,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + u32 datatowrite[128] = {0};
> + s16 status = 0;
> + s16 idx;
> + s16 retval;
> + u16 i;
> +
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) &&
> + (PRU1_MODE == PRU_MODE_RX_TX_BOTH))
> + return -EINVAL;
> +
> + 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;
> + /* Configure McASP0  */
> + suart_mcasp_config(init_params->tx_baud_value,
> + init_params->rx_baud_value,
> + init_params->oversampling, pruss_ioaddr);
> + pruss_enable(dev, PRUSS_NUM0);
> +
> + if (PRU1_MODE != PRU_MODE_INVALID)
> + pruss_enable(dev, PRUSS_NUM1);
> +
> + /* Reset PRU RAM */
> + for (i = 0; i < (PRU0_DATARAM_SIZE / sizeof(int)); i++)
> + pruss_writel(dev, (PRU0_DATARAM_OFFSET + (i * sizeof(int))),
> + datatowrite[i]);
> + if (PRU1_MODE != PRU_MODE_INVALID) {
> + for (i = 0; i < (PRU1_DATARAM_SIZE / sizeof(int)); i++)
> + pruss_writel(dev, (PRU1_DATARAM_OFFSET +
> + (i * sizeof(int))), datatowrite[i]);
> + }
> +
> + pruss_load(dev, PRUSS_NUM0, (u32 *)pru_suart_emu_code,
> + (fw_size / sizeof(u32)));
> + if (PRU1_MODE != PRU_MODE_INVALID)
> + 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, clk_rate_pruss);
> + suart_set_pru_id(dev, PRUSS_NUM0);
> + if (PRU1_MODE != PRU_MODE_INVALID)
> + suart_set_pru_id(dev, PRUSS_NUM1);
> +
> + pru_set_rx_tx_mode(dev, PRU0_MODE, PRUSS_NUM0);
> + if (PRU1_MODE != PRU_MODE_INVALID)
> + pru_set_rx_tx_mode(dev, PRU1_MODE, PRUSS_NUM1);
> +
> + pru_set_ram_data(dev, pruss_ioaddr);
> + pruss_run(dev, PRUSS_NUM0);
> +
> + if (PRU1_MODE != PRU_MODE_INVALID)
> + pruss_run(dev, PRUSS_NUM1);
> +
> + /* Initialize uart_statu_table */
> + for (idx = 0; idx < 8; idx++)
> + 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, (u16) timeout);
> + if (PRU1_MODE != PRU_MODE_INVALID)
> + pruss_writew(dev, PRU_SUART_PRU1_IDLE_TIMEOUT_OFFSET,
> + (u16) timeout);
> +}
> +
> +void pru_mcasp_deinit(void)
> +{
> + suart_mcasp_reset(&suart_iomap);
> +}
> +
> +/* suart Instance open routine  */
> +s32 pru_softuart_open(struct suart_handle *h_suart)
> +{
> + s16 status = 0;
> + u16 uart_num = h_suart->uart_num - 1;
> +
> + if (uart_statu_table[h_suart->uart_num - 1] ==
> + ePRU_SUART_UART_IN_USE) {
> + return -EUSERS;
> + } else {
> + h_suart->uart_type = uart_config[uart_num];
> + h_suart->uart_tx_channel = uart_tx[uart_num];
> + h_suart->uart_rx_channel = uart_rx[uart_num];
> + h_suart->uart_status = ePRU_SUART_UART_IN_USE;
> + uart_statu_table[h_suart->uart_num - 1] =
> + ePRU_SUART_UART_IN_USE;
> + }
> + return status;
> +}
> +
> +/* suart instance close routine */
> +s32 pru_softuart_close(struct suart_handle *h_uart)
> +{
> + s16 status = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + } else {
> + 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;
> +}
> +
> +static s32 search_chnum(u16 uart_num, u16 *ch_num, u32 *pru_offset, u16 
> mode)
> +{
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
> + || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
> + *ch_num = (uart_num * SUART_NUM_OF_CHANNELS_PER_SUART) - 2;
> + if (uart_num <= 4) {
> + *pru_offset = PRU_SUART_PRU0_CH0_OFFSET;
> + } else {
> + *pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
> + *ch_num -= 8;
> + }
> + (mode == 2) ? ++*ch_num : *ch_num;
> + } else if (mode == 1) {
> + 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 if (mode == 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;
> + }
> + return 0;
> +}
> +
> +/*
> + * suart routine for setting relative baud rate
> + */
> +s32 pru_softuart_setbaud(struct device *dev, struct suart_handle *h_uart,
> + u16 tx_clk_divisor, u16 rx_clk_divisor)
> +{
> + u32 offset;
> + u32 pru_offset;
> + s16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 regval = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + /* Set the clock divisor value s32o the McASP */
> + if ((tx_clk_divisor > 385) || (tx_clk_divisor == 0))
> + return -EINVAL;
> + if ((rx_clk_divisor > 385) || (rx_clk_divisor == 0))
> + return -EINVAL;
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> +
> + if (tx_clk_divisor != 0) {
> + offset = pru_offset +
> + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG1_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= (~0x3FF);
> + regval |= tx_clk_divisor;
> + pruss_writew(dev, offset, regval);
> + }
> + 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 0;
> + }
> + regval = 0;
> + if (rx_clk_divisor != 0) {
> + offset = pru_offset +
> + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG1_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= (~0x3FF);
> + regval |= tx_clk_divisor;
> + pruss_writew(dev, offset, regval);
> + }
> + return status;
> +}
> +
> +/*
> + * suart routine for setting number of bits per character for a specific 
> uart
> + */
> +s32 pru_softuart_setdatabits(struct device *dev, struct suart_handle 
> *h_uart,
> + u16 tx_data_bits, u16 rx_data_bits)
> +{
> + u32 offset;
> + u32 pru_offset;
> + s16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> + u32 reg_val;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + /*
> + * 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 -EINVAL;
> +
> + if ((rx_data_bits < ePRU_SUART_DATA_BITS6)
> + || (rx_data_bits > ePRU_SUART_DATA_BITS12))
> + return -EINVAL;
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> +
> + 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);
> + reg_val &= ~(0xF);
> + reg_val |= tx_data_bits;
> + pruss_writeb(dev, offset, (u8) reg_val);
> + }
> + 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 0;
> + }
> + 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);
> + reg_val &= ~(0xF);
> + reg_val |= rx_data_bits;
> + pruss_writeb(dev, offset, (u8) rx_data_bits);
> + }
> +
> + return status;
> +}
> +
> +/*
> + * suart routine to configure specific uart
> + */
> +s32 pru_softuart_setconfig(struct device *dev, struct suart_handle 
> *h_uart,
> + struct suart_config *config_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + s16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 reg_val = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + /*
> + * 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 -EINVAL;
> + }
> + if ((config_uart->tx_bits_per_char < 8)
> + || (config_uart->tx_bits_per_char > 14)) {
> + return -EINVAL;
> + }
> + if ((config_uart->rx_bits_per_char < 8)
> + || (config_uart->rx_bits_per_char > 14)) {
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> +
> + /*
> + * 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_readw(dev, offset, (u16 *) &reg_val);
> + reg_val = reg_val | (config_uart->tx_serializer <<
> + PRU_SUART_CH_CTRL_SR_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> + offset = pru_offset +
> + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG1_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + reg_val = reg_val | (config_uart->tx_clk_divisor <<
> + PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> + offset = pru_offset +
> + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG2_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + reg_val = reg_val | (config_uart->tx_bits_per_char <<
> + PRU_SUART_CH_CONFIG2_BITPERCHAR_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> + }
> +
> + 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 0;
> + }
> +
> + /* 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_readw(dev, offset, (u16 *) &reg_val);
> + reg_val = reg_val | (config_uart->rx_serializer <<
> + PRU_SUART_CH_CTRL_SR_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> +
> + /* Configuring RX prescalar value and Oversampling */
> + offset = pru_offset +
> + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG1_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + 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_writew(dev, offset, reg_val);
> +
> + /* Configuring RX bits per character value */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
> + + PRU_SUART_CH_CONFIG2_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + reg_val = reg_val | (config_uart->rx_bits_per_char <<
> + PRU_SUART_CH_CONFIG1_DIVISOR_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> + }
> + return status;
> +}
> +
> +/*
> + * suart routine for getting the number of bytes transfered
> + */
> +s32 pru_softuart_get_tx_data_len(struct device *dev,
> + struct suart_handle *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 read_value = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> +
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG2_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &read_value);
> + read_value = ((read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
> + >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
> + return read_value;
> +}
> +
> +/*
> + * suart routine for getting the number of bytes received
> + */
> +s32 pru_softuart_get_rx_data_len(struct device *dev,
> + struct suart_handle *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 read_value = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> +
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG2_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &read_value);
> + read_value = ((read_value & PRU_SUART_CH_CONFIG1_DIVISOR_MASK)
> + >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
> + return read_value;
> +}
> +
> +/*
> + * suart routine to get the configuration information from a specific 
> uart
> + */
> +s32 pru_softuart_getconfig(struct device *dev,
> + struct suart_handle *h_uart,
> + struct suart_config *config_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 reg_val = 0;
> + s16 status = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + /*
> + * NOTE:
> + * Dependent baud rate for the given UART,the value MUST BE LESS THAN OR
> + * EQUAL TO 64, preScalarValue <= 64
> + */
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> +
> + /* 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_readw(dev, offset, (u16 *) &reg_val);
> + 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_readw(dev, offset, (u16 *) &reg_val);
> + 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_readw(dev, offset, (u16 *) &reg_val);
> + 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 0;
> + }
> + /* 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_readw(dev, offset, (u16 *) &reg_val);
> + 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_readw(dev, offset, (u16 *) &reg_val);
> + 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_readw(dev, offset, (u16 *) &reg_val);
> + 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 ISR_value = 0;
> +
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
> +     || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
> + return 0;
> + } 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 *)&ISR_value);
> + if ((ISR_value & 0x1) == 0x1)
> + return -EINVAL;
> + } 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 *)&ISR_value);
> + if ((ISR_value & 0x2) == 0x2)
> + return -EINVAL;
> + } else {
> + return 0;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * suart data transmit routine
> + */
> +s32 pru_softuart_write(struct device *dev, struct suart_handle *h_uart,
> + u32 *pt_tx_data_buf, u16 data_len)
> +{
> + u32 offset = 0;
> + u32 pru_offset;
> + s16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 reg_val = 0;
> + u16 pru_num;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH) ||
> + (PRU1_MODE == PRU_MODE_RX_TX_BOTH))
> + pru_num = h_uart->uart_num;
> + else if (PRU0_MODE == PRU_MODE_TX_ONLY)
> + pru_num = 0;
> + else if (PRU1_MODE == PRU_MODE_TX_ONLY)
> + pru_num = 1;
> + else
> + return 0;
> +
> + /* Writing data length to SUART channel register */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG2_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
> + reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> +
> + /* 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_writel(dev, offset, (u32) *pt_tx_data_buf);
> +
> + /* Service Request to PRU */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CTRL_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + 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_writew(dev, offset, reg_val);
> +
> + /* generate ARM->PRU event */
> + suart_arm_to_pru_intr(dev, pru_num);
> +
> + return status;
> +}
> +
> +/*
> + * suart data receive routine
> + */
> +s32 pru_softuart_read(struct device *dev, struct suart_handle *h_uart,
> + u32 *ptDataBuf, u16 data_len)
> +{
> + u32 offset = 0;
> + u32 pru_offset;
> + s16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 reg_val = 0;
> + u16 pru_num;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> + 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;
> + pru_num = h_uart->uart_num;
> + } else if (PRU0_MODE == PRU_MODE_RX_ONLY) {
> + pru_num = 0;
> + } else if (PRU1_MODE == PRU_MODE_RX_ONLY) {
> + pru_num = 1;
> + } else {
> + return 0;
> + }
> + /* Writing data length to SUART channel register */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CONFIG2_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + reg_val &= ~PRU_SUART_CH_CONFIG2_DATALEN_MASK;
> + reg_val = reg_val | (data_len << PRU_SUART_CH_CONFIG2_DATALEN_SHIFT);
> + pruss_writew(dev, offset, reg_val);
> +
> + /* 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_writel(dev, offset, (u32) *ptDataBuf);
> +
> + /* Service Request to PRU */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CTRL_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + 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_writew(dev, offset, reg_val);
> +
> + /* 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
> + */
> +s32 pru_softuart_read_data(struct device *dev, struct suart_handle 
> *h_uart,
> + u8 *p_data_buffer, s32 max_len,
> + u32 *pdata_read)
> +{
> + s16 ret_val = 0;
> + u8 *psrc_addr = NULL;
> + u32 data_read = 0;
> + u32 data_len = 0;
> + u32 char_len = 0;
> + u32 offset = 0;
> + u32 pru_offset;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 status = 0;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> +
> + /* 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_multi(dev, offset, (u8 *) &psrc_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_readw(dev, offset, (u16 *) &data_len);
> +
> + /* read the character length */
> + char_len = data_len & PRU_SUART_CH_CONFIG2_BITPERCHAR_MASK;
> + char_len -= 2; /* remove the START & STOP bit */
> +
> + data_len &= PRU_SUART_CH_CONFIG2_DATALEN_MASK;
> + data_len = data_len >> PRU_SUART_CH_CONFIG2_DATALEN_SHIFT;
> + data_len++;
> +
> + /* if the character length is greater than 8, then the size doubles */
> + if (char_len > 8)
> + data_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 *) &status);
> + if (CHN_TXRX_STATUS_TIMEOUT == (status & 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 *) &data_read);
> +
> + /* if the character length is greater than 8,
> + then the size doubles */
> + if (char_len > 8)
> + data_read *= 2;
> +
> +/*
> + * the data corresponding is loaded in second
> + * half during the timeout
> + */
> + if (data_read > data_len) {
> + data_read -= data_len;
> + psrc_addr += data_len;
> + }
> +
> + pru_softuart_clr_rx_fifo(dev, h_uart);
> + } else {
> + data_read = data_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 (status & CHN_TXRX_STATUS_CMPLT)
> + psrc_addr += data_len;
> + }
> +
> + /* we should be copying only max len given by the application */
> + if (data_read > max_len)
> + data_read = max_len;
> +
> +/* evaluate the virtual address of the FIFO address
> + * based on the physical addr
> + */
> + psrc_addr = (u8 *)((u32) psrc_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 < data_read; offset++)
> + *p_data_buffer++ = *psrc_addr++;
> + *pdata_read = data_read;
> + ret_val = 0;
> +
> + 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.
> + */
> +s32 pru_softuart_stop_receive(struct device *dev, struct suart_handle 
> *h_uart)
> +{
> + u16 ret_status = 0;
> + u32 offset;
> + u32 pru_offset;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 status;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> +
> + /* 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 *) &status);
> +
> + /* we need to clear the busy bit corresponding to receive channel */
> + status &= ~(CHN_TXRX_STATUS_RDY);
> + pruss_writeb(dev, offset, (u8) status);
> +
> + /* 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_readw(dev, offset, (u16 *) &status);
> + status &= PRU_SUART_CH_CTRL_SR_MASK;
> + status = status >> PRU_SUART_CH_CTRL_SR_SHIFT;
> +
> + /* we need to de-activate the serializer corresponding to this rx */
> + ret_status = suart_asp_serializer_deactivate(status, &suart_iomap);
> +
> + return ret_status;
> +}
> +
> +/*
> + * suart routine to get the tx status for a specific uart
> + */
> +s32 pru_softuart_get_tx_status(struct device *dev, struct suart_handle 
> *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_TXRXSTATUS_OFFSET;
> + pruss_readb(dev, offset, (u8 *) &status);
> + return status;
> +}
> +
> +s32 pru_softuart_clr_tx_status(struct device *dev, struct suart_handle 
> *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 1);
> +
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_TXRXSTATUS_OFFSET;
> + pruss_readb(dev, offset, (u8 *) &status);
> + status &= ~(0x2);
> + pruss_writeb(dev, offset, (u8) status);
> + return status;
> +}
> +
> +/*
> + * suart routine to get the rx status for a specific uart
> + */
> +s32 pru_softuart_get_rx_status(struct device *dev, struct suart_handle 
> *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> +
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_TXRXSTATUS_OFFSET;
> + pruss_readb(dev, offset, (u8 *) &status);
> + return status;
> +}
> +
> +static s32 pru_softuart_clr_rx_fifo(struct device *dev,
> + struct suart_handle *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> + u16 reg_val;
> + u16 uart_num;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + uart_num = h_uart->uart_num;
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> + if (PRU0_MODE == PRU_MODE_RX_ONLY)
> + uart_num = 0;
> + else if (PRU1_MODE == PRU_MODE_RX_ONLY)
> + uart_num = 1;
> +
> + /* Reset the number of bytes read into the FIFO */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
> + + PRU_SUART_CH_BYTESDONECNTR_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + reg_val &= 0x00;
> + pruss_writew(dev, offset, reg_val);
> +
> +
> + /* Service Request to PRU */
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_CTRL_OFFSET;
> + pruss_readw(dev, offset, (u16 *) &reg_val);
> + 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_writew(dev, offset, reg_val);
> + 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;
> +}
> +
> +s32 pru_softuart_clr_rx_status(struct device *dev, struct suart_handle 
> *h_uart)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u16 status = 0;
> + u16 ch_num = h_uart->uart_num - 1;
> +
> + if (h_uart == NULL) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> + search_chnum(h_uart->uart_num, &ch_num, &pru_offset, 2);
> +
> + offset = pru_offset + (ch_num * SUART_NUM_OF_BYTES_PER_CHANNEL) +
> + PRU_SUART_CH_TXRXSTATUS_OFFSET;
> + pruss_readb(dev, offset, (u8 *) &status);
> + status &= ~(0x3C);
> + pruss_writeb(dev, offset, (u8) status);
> + 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 >
> + */
> +s32 pru_softuart_get_isrstatus(struct device *dev, u16 uart_num, u16 
> *txrx_flag)
> +{
> + u32 intc_offset;
> + u32 ch_num = 0xFF;
> + u32 reg_val = 0;
> + u32 reg_val2 = 0;
> + u32 ISR_value = 0;
> + u32 ack_reg_val = 0;
> + u32 stat_inx_clr_regoffset = 0;
> +
> + /* initialize the status & Flag to known value */
> + *txrx_flag = 0;
> +
> + stat_inx_clr_regoffset = (u32) (PRUSS_INTC_STATIDXCLR & 0xFFFF);
> +
> + /* Read PRU Interrupt Status Register from PRU */
> + intc_offset = (u32) (PRUSS_INTC_STATCLRINT1 & 0xFFFF);
> +
> + pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
> + || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
> + /* Check if the interrupt occured for Tx */
> + ch_num = uart_num * 2 - 2;
> + reg_val2 = PRU_SUART0_TX_EVT_BIT << ((uart_num - 1) * 2);
> + if (ISR_value & reg_val2) {
> + /* interupt occured for TX */
> + *txrx_flag |= PRU_TX_INTR;
> + /* acknowledge the RX interrupt  */
> + ack_reg_val  = ch_num + PRU_SUART0_TX_EVT;
> + pruss_writel(dev, stat_inx_clr_regoffset,
> + ack_reg_val);
> + }
> +
> + /* Check if the interrupt occured for Rx */
> + reg_val2 = PRU_SUART0_RX_EVT_BIT << ((uart_num - 1) * 2);
> + pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
> + if (ISR_value & reg_val2) {
> + /* interupt occured for RX */
> + *txrx_flag |= PRU_RX_INTR;
> + ch_num += 1;
> +
> + /* acknowledge the RX interrupt  */
> + ack_reg_val  = ch_num + PRU_SUART0_TX_EVT;
> + pruss_writel(dev, stat_inx_clr_regoffset,
> + ack_reg_val);
> + }
> + } else {
> + ch_num = uart_num - 1;
> + if ((ISR_value & 0x03FC) != 0) {
> + reg_val2 = 1 << (uart_num + 1);
> + if (ISR_value & reg_val2) {
> + /* acknowledge the s32errupt  */
> + ack_reg_val = ch_num + PRU_SUART0_TX_EVT;
> + pruss_writel(dev, stat_inx_clr_regoffset,
> + ack_reg_val);
> + *txrx_flag |= PRU_RX_INTR;
> + }
> + }
> + pruss_readl(dev, intc_offset, (u32 *)&ISR_value);
> + if (ISR_value & 0x3FC00) {
> + reg_val2 = 1 << (uart_num + 9);
> + if (ISR_value & reg_val2) {
> + /* acknowledge the s32errupt  */
> + ack_reg_val = ch_num + PRU_SUART4_TX_EVT;
> + pruss_writel(dev, stat_inx_clr_regoffset,
> + ack_reg_val);
> + *txrx_flag |= PRU_TX_INTR;
> + }
> + }
> + }
> + 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 0;
> + }
> +
> + pruss_readb(dev, offset, (u8 *) &txrx_flag);
> + txrx_flag &= ~(0x2);
> + pruss_writeb(dev, offset, (u8) txrx_flag);
> +
> + return 0;
> +}
> +
> +s32 suart_arm_to_pru_intr(struct device *dev, u16 uart_num)
> +{
> + u32 value;
> +
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
> +     || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
> + if ((uart_num > 0) && (uart_num <= 4))
> + value = 0x20; /* PRU0 SYS_EVT32 */
> + else if ((uart_num > 4) && (uart_num <= 8))
> + value = 0x21; /* PRU0 SYS_EVT33 */
> + else
> + return -EINVAL;
> + }
> + 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)
> + value = 0x20; /* PRU0 SYS_EVT32 */
> + else if (uart_num == PRUSS_NUM1)
> + value = 0x21; /* PRU0 SYS_EVT33 */
> + else
> + return -EINVAL;
> + }
> + return pruss_writel(dev, PRUSS_INTC_STATIDXSET, value);
> +}
> +
> +static s32 arm_to_pru_intr_init(struct device *dev)
> +{
> + u32 value;
> + u32 int_offset;
> +
> + /* Clear all the host interrupts */
> + for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
> + int_offset++)
> + pruss_idx_writel(dev, PRUSS_INTC_HSTINTENIDXCLR, int_offset);
> +
> + /* Enable the global s32errupt */
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_GLBLEN & 0xFFFF), 0, 1);
> +
> + /* Enable the Host interrupts for all host channels */
> + for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
> + int_offset++)
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF),
> + 0, int_offset);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP0 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP0_CHAN);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP1 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP1_CHAN);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_HOSTMAP2 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_HOSTMAP2_CHAN);
> +
> + /* MAP Channel 0 to SYS_EVT31 */
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP7 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP7_SYS_EVT31);
> +
> + if ((PRU0_MODE == PRU_MODE_RX_TX_BOTH)
> +     || (PRU1_MODE == PRU_MODE_RX_TX_BOTH)) {
> + /* Sets the channels for the system interrupt */
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_FULL);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP9_FULL);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP10_FULL);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP11_FULL);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP12_FULL);
> + }
> + 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 channels for the system interrupt */
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP8 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP8_HALF);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP9 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP9_HALF);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP10 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP10_HALF);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP11 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP11_HALF);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_CHANMAP12 & 0xFFFF),
> + PRU_INTC_REGMAP_MASK, PRU_INTC_CHANMAP12_HALF);
> + }
> +
> + /* Clear required set of system events
> + * and enable them using indexed register
> + */
> + for (int_offset = 0; int_offset < 18; int_offset++) {
> + value = 32 + int_offset;
> + pruss_idx_writel(dev, PRUSS_INTC_STATIDXCLR, value);
> + }
> +
> + /* enable only the HOST to PRU interrupts and let the PRU to Host events
> + * enabled by the separate API on demand basis.
> + */
> + pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 31);
> + pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 32);
> + pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 33);
> + pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, 50);
> + pruss_rmwl(dev, (u32) (PRUSS_INTC_GLBLEN & 0xFFFF), 0, 1);
> +
> + /* Enable the Host interrupts for all host channels */
> + for (int_offset = 0; int_offset <= PRUSS_INTC_HOSTINTLVL_MAX;
> + int_offset++)
> + pruss_idx_writel(dev, PRUSS_INTC_HSTINTENIDXSET, int_offset);
> +
> + return 0;
> +}
> +
> +s32 suart_pru_to_host_intr_enable(struct device *dev, u16 uart_num,
> + u32 txrxmode, s32 flag)
> +{
> + u32 chn_num;
> + u32 value;
> + s16 retval = 0;
> +
> + if (uart_num > 8)
> + return -EINVAL;
> +
> + 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++;
> + value = 34 + chn_num;
> + } else if ((PRU_MODE_RX_ONLY == txrxmode)
> + && (PRU0_MODE == PRU_MODE_RX_ONLY))
> + value = 34 + chn_num;
> + else if ((PRU_MODE_RX_ONLY == txrxmode)
> + && (PRU1_MODE == PRU_MODE_RX_ONLY))
> + value = 42 + chn_num;
> + else if ((PRU_MODE_TX_ONLY == txrxmode)
> + && (PRU0_MODE == PRU_MODE_TX_ONLY))
> + value = 34 + chn_num;
> + else if ((PRU_MODE_TX_ONLY == txrxmode)
> + && (PRU1_MODE == PRU_MODE_TX_ONLY))
> + value = 42 + chn_num;
> + else
> + return -EINVAL;
> +
> + retval = flag ? pruss_idx_writel(dev, PRUSS_INTC_ENIDXSET, value) :
> + pruss_idx_writel(dev, PRUSS_INTC_ENIDXCLR, value);
> + return retval;
> +}
> +
> +s32 suart_intr_setmask(struct device *dev, u16 uart_num,
> + u32 txrxmode, u32 rmask)
> +{
> + u32 offset;
> + u32 pru_offset;
> + u32 regval = 0;
> + u32 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 -EINVAL;
> + }
> + if (2 == txrxmode)
> + 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) {
> + pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
> + offset = PRU_SUART_PRU1_IMR_OFFSET;
> + } else
> + return 0;
> +
> + regval = 1 << chn_num;
> + if (CHN_TXRX_IE_MASK_CMPLT == (rmask & CHN_TXRX_IE_MASK_CMPLT))
> + pruss_rmww(dev, offset, regval, regval);
> +
> + if ((rmask & SUART_GBL_INTR_ERR_MASK) ==
> + SUART_GBL_INTR_ERR_MASK) {
> + regval = SUART_GBL_INTR_ERR_MASK;
> + pruss_rmww(dev, offset, regval, regval);
> + }
> +
> + offset = pru_offset +
> + (chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
> + + PRU_SUART_CH_CONFIG1_OFFSET;
> + /* Framing Error Interrupt Masked */
> + if ((rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
> + regval = 0;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= ~(CHN_TXRX_IE_MASK_FE);
> + regval |= CHN_TXRX_IE_MASK_FE;
> + pruss_writew(dev, offset, (u16) regval);
> + }
> +
> + /* Break Indicator Interrupt Masked */
> + if (CHN_TXRX_IE_MASK_BI == (rmask & CHN_TXRX_IE_MASK_BI)) {
> + regval = 0;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= ~(CHN_TXRX_IE_MASK_BI);
> + regval |= CHN_TXRX_IE_MASK_BI;
> + pruss_writew(dev, offset, (u16) regval);
> + }
> +
> + /* Timeout error Interrupt Masked */
> + if (CHN_TXRX_IE_MASK_TIMEOUT ==
> + (rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
> + regval = 0;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
> + regval |= CHN_TXRX_IE_MASK_TIMEOUT;
> + pruss_writew(dev, offset, (u16) regval);
> + }
> + return 0;
> +}
> +
> +s32 suart_intr_clrmask(struct device *dev, u16 uart_num,
> + u32 txrxmode, u32 rmask)
> +{
> + u32 offset;
> + u32 pru_offset;
> + 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 -EINVAL;
> + if (2 == txrxmode)
> + 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) {
> + pru_offset = PRU_SUART_PRU1_CH0_OFFSET;
> + offset = PRU_SUART_PRU1_IMR_OFFSET;
> + } else
> + return 0;
> +
> + regval = 1 << chn_num;
> + if (CHN_TXRX_IE_MASK_CMPLT == (rmask & CHN_TXRX_IE_MASK_CMPLT))
> + pruss_rmww(dev, offset, regval, 0);
> +
> + if ((rmask & SUART_GBL_INTR_ERR_MASK) == SUART_GBL_INTR_ERR_MASK)
> + pruss_rmww(dev, offset, SUART_GBL_INTR_ERR_MASK, 0);
> +
> + offset = pru_offset +
> + (chn_num * SUART_NUM_OF_BYTES_PER_CHANNEL)
> + + PRU_SUART_CH_CONFIG1_OFFSET;
> +
> + /* Framing Error Interrupt Masked */
> + if ((rmask & CHN_TXRX_IE_MASK_FE) == CHN_TXRX_IE_MASK_FE) {
> + regval = 0;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= ~(CHN_TXRX_IE_MASK_FE);
> + pruss_writew(dev, offset, regval);
> + }
> +
> + /* Break Indicator Interrupt Masked */
> + if (CHN_TXRX_IE_MASK_BI == (rmask & CHN_TXRX_IE_MASK_BI)) {
> + regval = 0;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= ~(CHN_TXRX_IE_MASK_BI);
> + pruss_writew(dev, offset, regval);
> + }
> +
> + /* Timeout error Interrupt Masked */
> + if (CHN_TXRX_IE_MASK_TIMEOUT ==
> + (rmask & CHN_TXRX_IE_MASK_TIMEOUT)) {
> + regval = 0;
> + pruss_readw(dev, offset, (u16 *) &regval);
> + regval &= ~(CHN_TXRX_IE_MASK_TIMEOUT);
> + pruss_writew(dev, offset, regval);
> + }
> + return 0;
> +}
> +
> +s32 suart_intr_getmask(struct device *dev, u16 uart_num,
> + u32 txrxmode, u32 rmask)
> +{
> + 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 -EINVAL;
> +
> + if (2 == txrxmode)
> + 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 0;
> +
> + regval = regval << chn_num;
> + pruss_readw(dev, offset, (u16 *) &txrx_flag);
> + txrx_flag &= regval;
> +
> + if ((rmask && (txrx_flag == regval)) || (!rmask && !txrx_flag))
> + return 1;
> +
> + return 0;
> +}
> diff --git a/drivers/tty/serial/pruss_suart_utils.c 
> b/drivers/tty/serial/pruss_suart_utils.c
> new file mode 100644
> index 0000000..5ee340e
> --- /dev/null
> +++ b/drivers/tty/serial/pruss_suart_utils.c
> @@ -0,0 +1,393 @@
> +/*
> + * Copyright (C) 2010, 2011 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.h>
> +#include "pruss_suart.h"
> +
> +#define SUART_TRX_DIV_CONF_SZ 4
> +
> +static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
> + struct pruss_suart_iomap *pruss_ioaddr);
> +static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value, u32 oversampling,
> + struct 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
> + */
> +static 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
> + */
> +static 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
> + */
> +static 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_reset(struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
> + pruss_ioaddr->mcasp_io_addr;
> + /* reset mcasp. */
> + iowrite32(MCASP_SUART_GBLCTL, &mcasp0_regs->gblctl);
> + iowrite32(MCASP_SUART_RGBLCTL, &mcasp0_regs->rgblctl);
> + iowrite32(MCASP_SUART_XGBLCTL, &mcasp0_regs->xgblctl);
> + iowrite32(MCASP_SUART_XSTAT, &mcasp0_regs->xstat);
> + iowrite32(MCASP_SUART_RSTAT, &mcasp0_regs->rstat);
> +}
> +
> +void suart_mcasp_config(u32 tx_baud_value,
> + u32 rx_baud_value,
> + u32 oversampling,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
> + pruss_ioaddr->mcasp_io_addr;
> + u32 temp_reg;
> +
> + /* reset mcasp */
> + iowrite32(MCASP_SUART_GBLCTL, &mcasp0_regs->gblctl);
> + iowrite32(MCASP_SUART_RGBLCTL, &mcasp0_regs->rgblctl);
> + iowrite32(MCASP_SUART_XGBLCTL, &mcasp0_regs->xgblctl);
> +
> + /* configure receive registers */
> + if ((SUART_8X_OVRSMPL == oversampling) || (0 == oversampling)) {
> + iowrite32(MCASP_SUART_RMASK_8, &mcasp0_regs->rmask);
> + iowrite32(MCASP_SUART_RFMT_8, &mcasp0_regs->rfmt);
> + }
> + if (SUART_16X_OVRSMPL == oversampling) {
> + iowrite32(MCASP_SUART_RMASK_16, &mcasp0_regs->rmask);
> + iowrite32(MCASP_SUART_RFMT_16, &mcasp0_regs->rfmt);
> +
> + }
> +
> + iowrite32(MCASP_SUART_FSRM, &mcasp0_regs->afsrctl);
> + iowrite32(MCASP_SUART_CLKRM_CLKRP, &mcasp0_regs->aclkrctl);
> + iowrite32(MCASP_SUART_HCLKRP, &mcasp0_regs->ahclkrctl);
> + suart_mcasp_rx_baud_set(rx_baud_value, oversampling, pruss_ioaddr);
> + iowrite32(MCASP_SUART_RTDMS0, &mcasp0_regs->rtdm);
> + iowrite32(MCASP_SUART_RSYNCERR, &mcasp0_regs->rintctl);
> + iowrite32(MCASP_SUART_RMAX_RPS_256, &mcasp0_regs->rclkchk);
> +
> + /* configure transmit registers. */
> + iowrite32(MCASP_SUART_XMASK_0_31, &mcasp0_regs->xmask);
> + iowrite32(MCASP_SUART_XBUSEL_XSSZ_16_XPAD_0, &mcasp0_regs->xfmt);
> + iowrite32(MCASP_SUART_FSXM, &mcasp0_regs->afsxctl);
> + iowrite32(MCASP_SUART_CLKXM_ASYNC_CLKXP, &mcasp0_regs->aclkxctl);
> + iowrite32(MCASP_SUART_HCLKXM, &mcasp0_regs->ahclkxctl);
> +
> + suart_mcasp_tx_baud_set(tx_baud_value, pruss_ioaddr);
> + iowrite32(MCASP_SUART_XTDMS0, &mcasp0_regs->xtdm);
> + iowrite32(MCASP_SUART_XSYNCERR, &mcasp0_regs->xintctl);
> + iowrite32(MCASP_SUART_XMAX_XPS_256, &mcasp0_regs->xclkchk);
> +
> + /* Serializer as a transmitter */
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl0);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl1);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl2);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl3);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl4);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl5);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl6);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl7);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl8);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl9);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl10);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl11);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl12);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl13);
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl14);
> + iowrite32(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);
> + iowrite32(temp_reg, &mcasp0_regs->pfunc);
> +
> + iowrite32(0xFFF, &mcasp0_regs->pdout);
> +
> + /* config pin function and direction */
> + iowrite32(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);
> + iowrite32(temp_reg, &mcasp0_regs->pdir);
> +
> + iowrite32(MCASP_SUART_DIT_DISABLE, &mcasp0_regs->ditctl);
> + iowrite32(MCASP_SUART_LOOPBACK_DISABLE, &mcasp0_regs->dlbctl);
> + iowrite32(MCASP_SUART_AMUTE_DISABLE, &mcasp0_regs->amute);
> +
> + iowrite32(MCASP_SUART_XSTAT, &mcasp0_regs->xstat);
> + iowrite32(MCASP_SUART_RSTAT, &mcasp0_regs->rstat);
> +}
> +
> +void suart_mcasp_tx_serialzier_set(u32 serializer_num,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
> + pruss_ioaddr->mcasp_io_addr;
> + u32 temp_reg;
> + temp_reg = ioread32(&mcasp0_regs->pfunc);
> + temp_reg |= (0x1 << serializer_num);
> + iowrite32(temp_reg, &mcasp0_regs->pfunc);
> +}
> +
> +/*
> + * mcasp TX buard rate setting routine
> + */
> +static s16 suart_mcasp_tx_baud_set(u32 tx_baud_value,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + u32 clk_div_val;
> + u32 loop_cnt;
> + s16 status = 0;
> + s16 found_val = false;
> +
> + struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
> + 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 = true;
> + break;
> + }
> + }
> + if (found_val == true) {
> + clk_div_val = lt_tx_baud_rate[loop_cnt][2];
> + temp_reg = ioread32(&mcasp0_regs->aclkxctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->aclkxctl);
> + clk_div_val = lt_tx_baud_rate[loop_cnt][3];
> + temp_reg = ioread32(&mcasp0_regs->ahclkxctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->ahclkxctl);
> + } else {
> + return -EINVAL ;
> + }
> + return status;
> +}
> +
> +/*
> + * mcasp RX buard rate setting routine
> + */
> +static s16 suart_mcasp_rx_baud_set(u32 rx_baud_value,
> + u32 oversampling, struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + u32 clk_div_val = 0;
> + u32 loop_cnt = 0;
> + s16 status = 0;
> + u32 temp_reg = 0;
> + struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
> + pruss_ioaddr->mcasp_io_addr;
> +
> + switch (oversampling) {
> + case 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 = ioread32(&mcasp0_regs->aclkrctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
> +
> + clk_div_val =
> + lt_rx_8x_baud_rate[loop_cnt][3] - 1;
> +
> + temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
> + break;
> + }
> + }
> + status = -EINVAL;
> + break;
> + case 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 = ioread32(&mcasp0_regs->aclkrctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
> + clk_div_val = lt_rx_16x_baud_rate[loop_cnt][3];
> + temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
> + break;
> + }
> + }
> + status = -EINVAL;
> + break;
> + case SUART_TX_OVRSMPL:
> + 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 = ioread32(&mcasp0_regs->aclkrctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_ACLKXCTL_CLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->aclkrctl);
> + clk_div_val = lt_tx_baud_rate[loop_cnt][3];
> + temp_reg = ioread32(&mcasp0_regs->ahclkrctl);
> + temp_reg |= (clk_div_val <<
> + OMAPL_MCASP_AHCLKXCTL_HCLKXDIV_SHIFT);
> + iowrite32(temp_reg, &mcasp0_regs->ahclkrctl);
> + break;
> + }
> + }
> + status = -EINVAL;
> + break;
> + default:
> + status = -EINVAL;
> + break;
> + }
> +
> + return status;
> +}
> +
> +/*
> + * mcasp buard rate setting routine
> + */
> +s16 suart_asp_baud_set(u32 tx_baud_value, u32 rx_baud_value, u32 
> oversampling,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + s16 status = 0;
> +
> + 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 sr_num,
> + struct pruss_suart_iomap *pruss_ioaddr)
> +{
> + s16 status = 0;
> + struct omapl_mcasp_regs_ovly __iomem *mcasp0_regs =
> + pruss_ioaddr->mcasp_io_addr;
> + if (sr_num > 15)
> + status = -EINVAL;
> + else
> + iowrite32(MCASP_SUART_SRCTL_DISMOD, &mcasp0_regs->srctl0);
> +
> + return status;
> +}
> 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	[flat|nested] 166+ messages in thread

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-09 13:39     ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-09 13:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Greg,

I am observing a RX FIFO sized data loss problem with my driver.

I observed that if I start the TX before the RX, then there are no errors,
but, if I start a TX after a RX, then I observe the error (FIFO sized data 
chunks missing).

Say, for example, if I use all three UARTS and on all three I start RX, then 
for every TX started I would observe
one error on all the RX data buffer.

So, if I start only two TX, then I will see only two errors on all the three 
RX UARTS.

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-09 13:39     ` Subhasish Ghosh
@ 2011-05-09 13:46       ` Alan Cox
  -1 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-09 13:46 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

> I then modified this function to as follows and the error is not observed 
> anymore.

That looks like you are somehow calling uart_carrier_raised somewhere
with interrupts disabled ?

Alan

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-09 13:46       ` Alan Cox
  0 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-09 13:46 UTC (permalink / raw)
  To: linux-arm-kernel

> I then modified this function to as follows and the error is not observed 
> anymore.

That looks like you are somehow calling uart_carrier_raised somewhere
with interrupts disabled ?

Alan

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-09 13:46       ` Alan Cox
@ 2011-05-09 13:50         ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-09 13:50 UTC (permalink / raw)
  To: Alan Cox
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

>> I then modified this function to as follows and the error is not observed
>> anymore.
>
> That looks like you are somehow calling uart_carrier_raised somewhere
> with interrupts disabled ?
>
I am not calling this function in my driver atall, this is getting called by 
tty_port.c

int tty_port_block_til_ready(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp)
{
 /* Probe the carrier. For devices with no carrier detect this
                   will always return true */
                cd = tty_port_carrier_raised(port);
                if (!(port->flags & ASYNC_CLOSING) &&
                                (do_clocal || cd))
                        break;
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
                        break;
                }

 


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-09 13:50         ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-09 13:50 UTC (permalink / raw)
  To: linux-arm-kernel

>> I then modified this function to as follows and the error is not observed
>> anymore.
>
> That looks like you are somehow calling uart_carrier_raised somewhere
> with interrupts disabled ?
>
I am not calling this function in my driver atall, this is getting called by 
tty_port.c

int tty_port_block_til_ready(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp)
{
 /* Probe the carrier. For devices with no carrier detect this
                   will always return true */
                cd = tty_port_carrier_raised(port);
                if (!(port->flags & ASYNC_CLOSING) &&
                                (do_clocal || cd))
                        break;
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
                        break;
                }

 

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-09 13:50         ` Subhasish Ghosh
@ 2011-05-09 13:55           ` Alan Cox
  -1 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-09 13:55 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

On Mon, 9 May 2011 19:20:17 +0530
"Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:

> >> I then modified this function to as follows and the error is not observed
> >> anymore.
> >
> > That looks like you are somehow calling uart_carrier_raised somewhere
> > with interrupts disabled ?
> >
> I am not calling this function in my driver atall, this is getting called by 
> tty_port.c

Can you verify the status of the interrupt flags at the point that
routine is called in your code and get a backtrace of the path. It
should never be gettng called with interrupts off, and if it is we need
to know what the path is. Otherwise that code change would imply a bug
in the core code for the platform which seems less likely.
 

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-09 13:55           ` Alan Cox
  0 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-09 13:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 9 May 2011 19:20:17 +0530
"Subhasish Ghosh" <subhasish@mistralsolutions.com> wrote:

> >> I then modified this function to as follows and the error is not observed
> >> anymore.
> >
> > That looks like you are somehow calling uart_carrier_raised somewhere
> > with interrupts disabled ?
> >
> I am not calling this function in my driver atall, this is getting called by 
> tty_port.c

Can you verify the status of the interrupt flags at the point that
routine is called in your code and get a backtrace of the path. It
should never be gettng called with interrupts off, and if it is we need
to know what the path is. Otherwise that code change would imply a bug
in the core code for the platform which seems less likely.
 

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-09 13:55           ` Alan Cox
@ 2011-05-10  6:17             ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-10  6:17 UTC (permalink / raw)
  To: Alan Cox
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

Hi Alan,

>> >> I then modified this function to as follows and the error is not 
>> >> observed
>> >> anymore.
>> >
>> > That looks like you are somehow calling uart_carrier_raised somewhere
>> > with interrupts disabled ?
>> >
>> I am not calling this function in my driver atall, this is getting called 
>> by
>> tty_port.c
>
> Can you verify the status of the interrupt flags at the point that
> routine is called in your code and get a backtrace of the path. It
> should never be gettng called with interrupts off, and if it is we need
> to know what the path is. Otherwise that code change would imply a bug
> in the core code for the platform which seems less likely.

Here is the back trace:

root@arago:~# ------------[ cut here ]------------
WARNING: at drivers/tty/serial/pruss_suart.c:295 
uart_carrier_raised+0x2c/0x74()
Modules linked in: pruss_uart
[<c002e888>] (unwind_backtrace+0x0/0xec) from [<c003e400>] 
(warn_slowpath_common+0x4c/0x64)
[<c003e400>] (warn_slowpath_common+0x4c/0x64) from [<c003e430>] 
(warn_slowpath_null+0x18/0x1c)
[<c003e430>] (warn_slowpath_null+0x18/0x1c) from [<c0190744>] 
(uart_carrier_raised+0x2c/0x74)
[<c0190744>] (uart_carrier_raised+0x2c/0x74) from [<c0182b84>] 
(tty_port_carrier_raised+0x1c/0x20)
[<c0182b84>] (tty_port_carrier_raised+0x1c/0x20) from [<c0183174>] 
(tty_port_block_til_ready+0x254/0x328)
[<c0183174>] (tty_port_block_til_ready+0x254/0x328) from [<c017d3ac>] 
(tty_open+0x310/0x478)
[<c017d3ac>] (tty_open+0x310/0x478) from [<c009f5d8>] 
(chrdev_open+0x1b4/0x1d0)
[<c009f5d8>] (chrdev_open+0x1b4/0x1d0) from [<c009ae34>] 
(__dentry_open+0x170/0x27c)
[<c009ae34>] (__dentry_open+0x170/0x27c) from [<c009b008>] 
(nameidata_to_filp+0x50/0x5c)
[<c009b008>] (nameidata_to_filp+0x50/0x5c) from [<c00a70e0>] 
(finish_open+0x90/0x17c)
[<c00a70e0>] (finish_open+0x90/0x17c) from [<c00a8fa4>] 
(do_filp_open+0x23c/0x520)
[<c00a8fa4>] (do_filp_open+0x23c/0x520) from [<c009ac0c>] 
(do_sys_open+0x58/0xe4)
[<c009ac0c>] (do_sys_open+0x58/0xe4) from [<c0029fa0>] 
(ret_fast_syscall+0x0/0x2c)

flags ---> 0xA0000013


This is how I generated the trace:

static void pruss_suart_enable_ms(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;

        WARN_ON(1);
        dev_dbg(dev, "modem control timer not supported\n");
} 


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-10  6:17             ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-10  6:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Alan,

>> >> I then modified this function to as follows and the error is not 
>> >> observed
>> >> anymore.
>> >
>> > That looks like you are somehow calling uart_carrier_raised somewhere
>> > with interrupts disabled ?
>> >
>> I am not calling this function in my driver atall, this is getting called 
>> by
>> tty_port.c
>
> Can you verify the status of the interrupt flags at the point that
> routine is called in your code and get a backtrace of the path. It
> should never be gettng called with interrupts off, and if it is we need
> to know what the path is. Otherwise that code change would imply a bug
> in the core code for the platform which seems less likely.

Here is the back trace:

root at arago:~# ------------[ cut here ]------------
WARNING: at drivers/tty/serial/pruss_suart.c:295 
uart_carrier_raised+0x2c/0x74()
Modules linked in: pruss_uart
[<c002e888>] (unwind_backtrace+0x0/0xec) from [<c003e400>] 
(warn_slowpath_common+0x4c/0x64)
[<c003e400>] (warn_slowpath_common+0x4c/0x64) from [<c003e430>] 
(warn_slowpath_null+0x18/0x1c)
[<c003e430>] (warn_slowpath_null+0x18/0x1c) from [<c0190744>] 
(uart_carrier_raised+0x2c/0x74)
[<c0190744>] (uart_carrier_raised+0x2c/0x74) from [<c0182b84>] 
(tty_port_carrier_raised+0x1c/0x20)
[<c0182b84>] (tty_port_carrier_raised+0x1c/0x20) from [<c0183174>] 
(tty_port_block_til_ready+0x254/0x328)
[<c0183174>] (tty_port_block_til_ready+0x254/0x328) from [<c017d3ac>] 
(tty_open+0x310/0x478)
[<c017d3ac>] (tty_open+0x310/0x478) from [<c009f5d8>] 
(chrdev_open+0x1b4/0x1d0)
[<c009f5d8>] (chrdev_open+0x1b4/0x1d0) from [<c009ae34>] 
(__dentry_open+0x170/0x27c)
[<c009ae34>] (__dentry_open+0x170/0x27c) from [<c009b008>] 
(nameidata_to_filp+0x50/0x5c)
[<c009b008>] (nameidata_to_filp+0x50/0x5c) from [<c00a70e0>] 
(finish_open+0x90/0x17c)
[<c00a70e0>] (finish_open+0x90/0x17c) from [<c00a8fa4>] 
(do_filp_open+0x23c/0x520)
[<c00a8fa4>] (do_filp_open+0x23c/0x520) from [<c009ac0c>] 
(do_sys_open+0x58/0xe4)
[<c009ac0c>] (do_sys_open+0x58/0xe4) from [<c0029fa0>] 
(ret_fast_syscall+0x0/0x2c)

flags ---> 0xA0000013


This is how I generated the trace:

static void pruss_suart_enable_ms(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;

        WARN_ON(1);
        dev_dbg(dev, "modem control timer not supported\n");
} 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-05 14:12                     ` Arnd Bergmann
@ 2011-05-10  9:53                       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-10  9:53 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

> Instead of passing a configuration file into the MFD driver and
> calling it a firmware, I can see three other options that I believe
> would be nicer:
> 
> 1. have a single firmware blob that describes the child devices
> and the code that is to be loaded into both units. If they are
> acting as one device, either make sure you only create one
> child node, or create one with a name that no driver binds to.
> 
> 2. Call request_firmware separately for the two child devices,
> and configure them separately based on the information in the
> firmware files. In the case where they should act as a single
> device, call the children e.g. "pruss-uart-a" and "pruss-uart-b",
> then bind to both names in the pruss-uart drivers and only
> start using the device when you have both nodes for the same
> parent.
> 
> 3. Do the configuration through sysfs files in the MFD device node,
> which then cause the creation of the child devices. This means you
> need extra user space scripts to write the addititonal files, but
> is also the most flexible way.
> 

Are you suggesting something like:

/sys..../pruss/pru0/id
/sys..../pruss/pru0/fw_name
/sys..../pruss/pru0/load

/sys..../pruss/pru1/id
/sys..../pruss/pru1/fw_name
/sys..../pruss/pru1/load

I can program these configs and store them in the pru private.
Then write something into load.
This can load the PRU based upon the configs.
But, I am not sure how to do this effectively using sysfs,
I mean I don't want to end up writing six write and six read
handlers. 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-10  9:53                       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-10  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

> Instead of passing a configuration file into the MFD driver and
> calling it a firmware, I can see three other options that I believe
> would be nicer:
> 
> 1. have a single firmware blob that describes the child devices
> and the code that is to be loaded into both units. If they are
> acting as one device, either make sure you only create one
> child node, or create one with a name that no driver binds to.
> 
> 2. Call request_firmware separately for the two child devices,
> and configure them separately based on the information in the
> firmware files. In the case where they should act as a single
> device, call the children e.g. "pruss-uart-a" and "pruss-uart-b",
> then bind to both names in the pruss-uart drivers and only
> start using the device when you have both nodes for the same
> parent.
> 
> 3. Do the configuration through sysfs files in the MFD device node,
> which then cause the creation of the child devices. This means you
> need extra user space scripts to write the addititonal files, but
> is also the most flexible way.
> 

Are you suggesting something like:

/sys..../pruss/pru0/id
/sys..../pruss/pru0/fw_name
/sys..../pruss/pru0/load

/sys..../pruss/pru1/id
/sys..../pruss/pru1/fw_name
/sys..../pruss/pru1/load

I can program these configs and store them in the pru private.
Then write something into load.
This can load the PRU based upon the configs.
But, I am not sure how to do this effectively using sysfs,
I mean I don't want to end up writing six write and six read
handlers. 

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-04-27 11:19             ` Nori, Sekhar
@ 2011-05-10 10:54               ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-10 10:54 UTC (permalink / raw)
  To: Nori, Sekhar, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

>> 
>> >>The driver should probably just get sram
>> >> space through platform data so that it doesn't depend on the
>> >> platform specific sram allocation function.
>> 
>> Are you suggesting that I go back to that implementation.
> 
> No, the platform code should use the SRAM allocator and
> pass on the allocated memory to the driver.
> 

Say, if the driver is loaded as a module.
If I allocate the sram in the platform code, how to I
free it when the driver is unloaded. 

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-10 10:54               ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-10 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

>> 
>> >>The driver should probably just get sram
>> >> space through platform data so that it doesn't depend on the
>> >> platform specific sram allocation function.
>> 
>> Are you suggesting that I go back to that implementation.
> 
> No, the platform code should use the SRAM allocator and
> pass on the allocated memory to the driver.
> 

Say, if the driver is loaded as a module.
If I allocate the sram in the platform code, how to I
free it when the driver is unloaded. 

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

* RE: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-10 10:54               ` Subhasish Ghosh
@ 2011-05-10 13:13                 ` Nori, Sekhar
  -1 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-10 13:13 UTC (permalink / raw)
  To: Subhasish Ghosh, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

On Tue, May 10, 2011 at 16:24:35, Subhasish Ghosh wrote:
> >> 
> >> >>The driver should probably just get sram
> >> >> space through platform data so that it doesn't depend on the
> >> >> platform specific sram allocation function.
> >> 
> >> Are you suggesting that I go back to that implementation.
> > 
> > No, the platform code should use the SRAM allocator and
> > pass on the allocated memory to the driver.
> > 
> 
> Say, if the driver is loaded as a module.
> If I allocate the sram in the platform code, how to I
> free it when the driver is unloaded. 

This is what I said in my last e-mail. What is
the issue you see with this approach?

| Thanks for the clarification. In this case, the driver
| should use platform callbacks to get/put fast fifo
| space. In case this callback is not populated by the
| platform or returns an error, the driver should fall
| back to allocating from DDR.

Thanks,
Sekhar




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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-10 13:13                 ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-10 13:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2011 at 16:24:35, Subhasish Ghosh wrote:
> >> 
> >> >>The driver should probably just get sram
> >> >> space through platform data so that it doesn't depend on the
> >> >> platform specific sram allocation function.
> >> 
> >> Are you suggesting that I go back to that implementation.
> > 
> > No, the platform code should use the SRAM allocator and
> > pass on the allocated memory to the driver.
> > 
> 
> Say, if the driver is loaded as a module.
> If I allocate the sram in the platform code, how to I
> free it when the driver is unloaded. 

This is what I said in my last e-mail. What is
the issue you see with this approach?

| Thanks for the clarification. In this case, the driver
| should use platform callbacks to get/put fast fifo
| space. In case this callback is not populated by the
| platform or returns an error, the driver should fall
| back to allocating from DDR.

Thanks,
Sekhar

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-10  6:17             ` Subhasish Ghosh
@ 2011-05-10 13:32               ` Alan Cox
  -1 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-10 13:32 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

Trace all looks fine. I can't see anything else taking the lock so you'll
need to do a bit more debugging and find out why the spin lock change
makes the difference and what the real root cause is.



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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-10 13:32               ` Alan Cox
  0 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-10 13:32 UTC (permalink / raw)
  To: linux-arm-kernel

Trace all looks fine. I can't see anything else taking the lock so you'll
need to do a bit more debugging and find out why the spin lock change
makes the difference and what the real root cause is.

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-10  9:53                       ` Subhasish Ghosh
@ 2011-05-10 21:44                         ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-10 21:44 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

On Tuesday 10 May 2011, Subhasish Ghosh wrote:
> > Instead of passing a configuration file into the MFD driver and
> > calling it a firmware, I can see three other options that I believe
> > would be nicer:
> > 
> > 1. have a single firmware blob that describes the child devices
> > and the code that is to be loaded into both units. If they are
> > acting as one device, either make sure you only create one
> > child node, or create one with a name that no driver binds to.
> > 
> > 2. Call request_firmware separately for the two child devices,
> > and configure them separately based on the information in the
> > firmware files. In the case where they should act as a single
> > device, call the children e.g. "pruss-uart-a" and "pruss-uart-b",
> > then bind to both names in the pruss-uart drivers and only
> > start using the device when you have both nodes for the same
> > parent.
> > 
> > 3. Do the configuration through sysfs files in the MFD device node,
> > which then cause the creation of the child devices. This means you
> > need extra user space scripts to write the addititonal files, but
> > is also the most flexible way.
> > 
> 
> Are you suggesting something like:
> 
> /sys..../pruss/pru0/id
> /sys..../pruss/pru0/fw_name
> /sys..../pruss/pru0/load
> 
> /sys..../pruss/pru1/id
> /sys..../pruss/pru1/fw_name
> /sys..../pruss/pru1/load

No, that is none of the three I suggested.

> I can program these configs and store them in the pru private.
> Then write something into load.
> This can load the PRU based upon the configs.
> But, I am not sure how to do this effectively using sysfs,
> I mean I don't want to end up writing six write and six read
> handlers. 

Please look into implementing one of the three I suggested before
you go off in another direction. In case of the third one, the idea
was to configure the name of the device for each pru using sysfs,
which then gets bound to the driver, which loads its own firmware
as you do today. Only in the first two suggestions, the mfd driver
would be responsible for loading the firmware.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-10 21:44                         ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-10 21:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 10 May 2011, Subhasish Ghosh wrote:
> > Instead of passing a configuration file into the MFD driver and
> > calling it a firmware, I can see three other options that I believe
> > would be nicer:
> > 
> > 1. have a single firmware blob that describes the child devices
> > and the code that is to be loaded into both units. If they are
> > acting as one device, either make sure you only create one
> > child node, or create one with a name that no driver binds to.
> > 
> > 2. Call request_firmware separately for the two child devices,
> > and configure them separately based on the information in the
> > firmware files. In the case where they should act as a single
> > device, call the children e.g. "pruss-uart-a" and "pruss-uart-b",
> > then bind to both names in the pruss-uart drivers and only
> > start using the device when you have both nodes for the same
> > parent.
> > 
> > 3. Do the configuration through sysfs files in the MFD device node,
> > which then cause the creation of the child devices. This means you
> > need extra user space scripts to write the addititonal files, but
> > is also the most flexible way.
> > 
> 
> Are you suggesting something like:
> 
> /sys..../pruss/pru0/id
> /sys..../pruss/pru0/fw_name
> /sys..../pruss/pru0/load
> 
> /sys..../pruss/pru1/id
> /sys..../pruss/pru1/fw_name
> /sys..../pruss/pru1/load

No, that is none of the three I suggested.

> I can program these configs and store them in the pru private.
> Then write something into load.
> This can load the PRU based upon the configs.
> But, I am not sure how to do this effectively using sysfs,
> I mean I don't want to end up writing six write and six read
> handlers. 

Please look into implementing one of the three I suggested before
you go off in another direction. In case of the third one, the idea
was to configure the name of the device for each pru using sysfs,
which then gets bound to the driver, which loads its own firmware
as you do today. Only in the first two suggestions, the mfd driver
would be responsible for loading the firmware.

	Arnd

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-10 13:32               ` Alan Cox
@ 2011-05-11  7:01                 ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-11  7:01 UTC (permalink / raw)
  To: Alan Cox
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

> Trace all looks fine. I can't see anything else taking the lock so you'll
> need to do a bit more debugging and find out why the spin lock change
> makes the difference and what the real root cause is.

We do not support Modem control signals. So, I use -clocal with stty,
but I observe that still enable_ms and get_mctrl handlers get called.
Is that normal, how can I disable these functions from getting called.

Actually, this same driver works perfectly with 2.6.33 kernel.
With this Kernel I do not observe that these handlers getting called.
So, basically the code path is different.

Further, I only use the port->lock to disable interrupts, so its never 
possible that
while interrupts are disabled by my driver, the TTY is executing anything.

There is another lock in the MFD driver, but that only uses spin_lock/unlock
variant. 


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-11  7:01                 ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-11  7:01 UTC (permalink / raw)
  To: linux-arm-kernel

> Trace all looks fine. I can't see anything else taking the lock so you'll
> need to do a bit more debugging and find out why the spin lock change
> makes the difference and what the real root cause is.

We do not support Modem control signals. So, I use -clocal with stty,
but I observe that still enable_ms and get_mctrl handlers get called.
Is that normal, how can I disable these functions from getting called.

Actually, this same driver works perfectly with 2.6.33 kernel.
With this Kernel I do not observe that these handlers getting called.
So, basically the code path is different.

Further, I only use the port->lock to disable interrupts, so its never 
possible that
while interrupts are disabled by my driver, the TTY is executing anything.

There is another lock in the MFD driver, but that only uses spin_lock/unlock
variant. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-10 21:44                         ` Arnd Bergmann
@ 2011-05-11  9:28                           ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-11  9:28 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

> Please look into implementing one of the three I suggested before
> you go off in another direction. In case of the third one, the idea
> was to configure the name of the device for each pru using sysfs,
> which then gets bound to the driver, which loads its own firmware
> as you do today. Only in the first two suggestions, the mfd driver
> would be responsible for loading the firmware.

Ok, thanks for the clarification.
Instead of passing the device name, will it be ok to pass the mfd_id.
The benefit will be that I can use the ID directly as an array
index for the mfd_cell entries.

Just to verify my understanding, all that's needs to be done is add
a sysfs entry at 
/sys/devices/platform/pruss_mfd/mfd_id

Writing to this entry would create the respective device.
Rewriting would unload the old (mfd_remove_device)
and reload the new device.
Reading may return the various devices and their name
aliases.
 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-11  9:28                           ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-11  9:28 UTC (permalink / raw)
  To: linux-arm-kernel

> Please look into implementing one of the three I suggested before
> you go off in another direction. In case of the third one, the idea
> was to configure the name of the device for each pru using sysfs,
> which then gets bound to the driver, which loads its own firmware
> as you do today. Only in the first two suggestions, the mfd driver
> would be responsible for loading the firmware.

Ok, thanks for the clarification.
Instead of passing the device name, will it be ok to pass the mfd_id.
The benefit will be that I can use the ID directly as an array
index for the mfd_cell entries.

Just to verify my understanding, all that's needs to be done is add
a sysfs entry at 
/sys/devices/platform/pruss_mfd/mfd_id

Writing to this entry would create the respective device.
Rewriting would unload the old (mfd_remove_device)
and reload the new device.
Reading may return the various devices and their name
aliases.
 

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-11  7:01                 ` Subhasish Ghosh
@ 2011-05-11 10:35                   ` Alan Cox
  -1 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-11 10:35 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: davinci-linux-open-source, Greg Kroah-Hartman, linux-arm-kernel,
	m-watkins, nsekhar, sachi, Andrew Morton (commit_signer:1/4=25%),
	Randy Dunlap (commit_signer:1/4=25%),
	open list

> We do not support Modem control signals. So, I use -clocal with stty,
> but I observe that still enable_ms and get_mctrl handlers get called.
> Is that normal, how can I disable these functions from getting called.

It is normal.

> Actually, this same driver works perfectly with 2.6.33 kernel.
> With this Kernel I do not observe that these handlers getting called.
> So, basically the code path is different.

Quite possibly - but you'll need to trace down and understand *why* the
problem exists. Finding which kernel introduces it might be a step in the
right direction.

Alan

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-11 10:35                   ` Alan Cox
  0 siblings, 0 replies; 166+ messages in thread
From: Alan Cox @ 2011-05-11 10:35 UTC (permalink / raw)
  To: linux-arm-kernel

> We do not support Modem control signals. So, I use -clocal with stty,
> but I observe that still enable_ms and get_mctrl handlers get called.
> Is that normal, how can I disable these functions from getting called.

It is normal.

> Actually, this same driver works perfectly with 2.6.33 kernel.
> With this Kernel I do not observe that these handlers getting called.
> So, basically the code path is different.

Quite possibly - but you'll need to trace down and understand *why* the
problem exists. Finding which kernel introduces it might be a step in the
right direction.

Alan

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-11  9:28                           ` Subhasish Ghosh
@ 2011-05-11 20:03                             ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-11 20:03 UTC (permalink / raw)
  To: Subhasish Ghosh, Mark Brown
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

On Wednesday 11 May 2011, Subhasish Ghosh wrote:
> > Please look into implementing one of the three I suggested before
> > you go off in another direction. In case of the third one, the idea
> > was to configure the name of the device for each pru using sysfs,
> > which then gets bound to the driver, which loads its own firmware
> > as you do today. Only in the first two suggestions, the mfd driver
> > would be responsible for loading the firmware.
> 
> Ok, thanks for the clarification.
> Instead of passing the device name, will it be ok to pass the mfd_id.
> The benefit will be that I can use the ID directly as an array
> index for the mfd_cell entries.

I think a device name would be clearer here, especially in order
to avoid conflicts when the list gets extended in different ways
depending on which kernel runs.

We had a little discussion at the Linaro Developer Summit about your
driver and mfd drivers in general. There was a general feeling among
some people (including me) that by the point you dynamically create
the subdevices, MFD is probably not the right abstraction any more,
as it does not provide any service that you need.

Instead, maybe you can simply call platform_device_register
at that stage to create the children and not use MFD at all.

Samuel, can you comment on this as well? Do you still see pruss
as an MFD driver when the uses are completely dynamic and determined
by the firmware loaded into it?

> Just to verify my understanding, all that's needs to be done is add
> a sysfs entry at 
> /sys/devices/platform/pruss_mfd/mfd_id
> 
> Writing to this entry would create the respective device.
> Rewriting would unload the old (mfd_remove_device)
> and reload the new device.

Yes

> Reading may return the various devices and their name
> aliases.

I would just return the current value. You might want to have two
files in sysfs, one per PRU, so you can set them individually.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-11 20:03                             ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-11 20:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 11 May 2011, Subhasish Ghosh wrote:
> > Please look into implementing one of the three I suggested before
> > you go off in another direction. In case of the third one, the idea
> > was to configure the name of the device for each pru using sysfs,
> > which then gets bound to the driver, which loads its own firmware
> > as you do today. Only in the first two suggestions, the mfd driver
> > would be responsible for loading the firmware.
> 
> Ok, thanks for the clarification.
> Instead of passing the device name, will it be ok to pass the mfd_id.
> The benefit will be that I can use the ID directly as an array
> index for the mfd_cell entries.

I think a device name would be clearer here, especially in order
to avoid conflicts when the list gets extended in different ways
depending on which kernel runs.

We had a little discussion at the Linaro Developer Summit about your
driver and mfd drivers in general. There was a general feeling among
some people (including me) that by the point you dynamically create
the subdevices, MFD is probably not the right abstraction any more,
as it does not provide any service that you need.

Instead, maybe you can simply call platform_device_register
at that stage to create the children and not use MFD at all.

Samuel, can you comment on this as well? Do you still see pruss
as an MFD driver when the uses are completely dynamic and determined
by the firmware loaded into it?

> Just to verify my understanding, all that's needs to be done is add
> a sysfs entry at 
> /sys/devices/platform/pruss_mfd/mfd_id
> 
> Writing to this entry would create the respective device.
> Rewriting would unload the old (mfd_remove_device)
> and reload the new device.

Yes

> Reading may return the various devices and their name
> aliases.

I would just return the current value. You might want to have two
files in sysfs, one per PRU, so you can set them individually.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-11 20:03                             ` Arnd Bergmann
@ 2011-05-13 10:55                               ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-13 10:55 UTC (permalink / raw)
  To: Arnd Bergmann, Mark Brown
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

>>
>> Ok, thanks for the clarification.
>> Instead of passing the device name, will it be ok to pass the mfd_id.
>> The benefit will be that I can use the ID directly as an array
>> index for the mfd_cell entries.
>
> I think a device name would be clearer here, especially in order
> to avoid conflicts when the list gets extended in different ways
> depending on which kernel runs.
>
> We had a little discussion at the Linaro Developer Summit about your
> driver and mfd drivers in general. There was a general feeling among
> some people (including me) that by the point you dynamically create
> the subdevices, MFD is probably not the right abstraction any more,
> as it does not provide any service that you need.
>
> Instead, maybe you can simply call platform_device_register
> at that stage to create the children and not use MFD at all.
>
> Samuel, can you comment on this as well? Do you still see pruss
> as an MFD driver when the uses are completely dynamic and determined
> by the firmware loaded into it?
>

Hi Arnd,

But in that case, where do I fit my driver.
It's a microcontroller inside of a processor, guess that's unique for Linux.
Will a misc device be a better choice.

In that case I can remove the MFD cell from the board_file and add an array
of platform_device for the UART & CAN.

Regarding device register, I will have to implement something similar to
mfd_add_devices and mark the dev->parent.

Did I miss something or will that be fine.



 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-13 10:55                               ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-13 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

>>
>> Ok, thanks for the clarification.
>> Instead of passing the device name, will it be ok to pass the mfd_id.
>> The benefit will be that I can use the ID directly as an array
>> index for the mfd_cell entries.
>
> I think a device name would be clearer here, especially in order
> to avoid conflicts when the list gets extended in different ways
> depending on which kernel runs.
>
> We had a little discussion at the Linaro Developer Summit about your
> driver and mfd drivers in general. There was a general feeling among
> some people (including me) that by the point you dynamically create
> the subdevices, MFD is probably not the right abstraction any more,
> as it does not provide any service that you need.
>
> Instead, maybe you can simply call platform_device_register
> at that stage to create the children and not use MFD at all.
>
> Samuel, can you comment on this as well? Do you still see pruss
> as an MFD driver when the uses are completely dynamic and determined
> by the firmware loaded into it?
>

Hi Arnd,

But in that case, where do I fit my driver.
It's a microcontroller inside of a processor, guess that's unique for Linux.
Will a misc device be a better choice.

In that case I can remove the MFD cell from the board_file and add an array
of platform_device for the UART & CAN.

Regarding device register, I will have to implement something similar to
mfd_add_devices and mark the dev->parent.

Did I miss something or will that be fine.



 

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-10 13:13                 ` Nori, Sekhar
@ 2011-05-13 12:10                   ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-13 12:10 UTC (permalink / raw)
  To: Nori, Sekhar, Greg KH
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

>> 
>> Say, if the driver is loaded as a module.
>> If I allocate the sram in the platform code, how to I
>> free it when the driver is unloaded. 
> 
> This is what I said in my last e-mail. What is
> the issue you see with this approach?
> 
> | Thanks for the clarification. In this case, the driver
> | should use platform callbacks to get/put fast fifo
> | space. In case this callback is not populated by the
> | platform or returns an error, the driver should fall
> | back to allocating from DDR.
> 

ok, so what you are suggesting is that I implement some
callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
memory using sram_alloc.
My doubt is, if already such API's are there (by Russel) or you
are suggesting to implement them.
 

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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-13 12:10                   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-13 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

>> 
>> Say, if the driver is loaded as a module.
>> If I allocate the sram in the platform code, how to I
>> free it when the driver is unloaded. 
> 
> This is what I said in my last e-mail. What is
> the issue you see with this approach?
> 
> | Thanks for the clarification. In this case, the driver
> | should use platform callbacks to get/put fast fifo
> | space. In case this callback is not populated by the
> | platform or returns an error, the driver should fall
> | back to allocating from DDR.
> 

ok, so what you are suggesting is that I implement some
callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
memory using sram_alloc.
My doubt is, if already such API's are there (by Russel) or you
are suggesting to implement them.
 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-13 10:55                               ` Subhasish Ghosh
@ 2011-05-14 16:01                                 ` Mark Brown
  -1 siblings, 0 replies; 166+ messages in thread
From: Mark Brown @ 2011-05-14 16:01 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Arnd Bergmann, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Fri, May 13, 2011 at 04:25:56PM +0530, Subhasish Ghosh wrote:

> >Instead, maybe you can simply call platform_device_register
> >at that stage to create the children and not use MFD at all.

> >Samuel, can you comment on this as well? Do you still see pruss
> >as an MFD driver when the uses are completely dynamic and determined
> >by the firmware loaded into it?

> But in that case, where do I fit my driver.
> It's a microcontroller inside of a processor, guess that's unique for Linux.

It's not that unusual in hardware terms, really.  There's an awful lot
of this going on in the audio area especially at the minute so there's
going to be some effort around providing some framework support for this
which should have some general usability but that's not there yet.

> Will a misc device be a better choice.

> In that case I can remove the MFD cell from the board_file and add an array
> of platform_device for the UART & CAN.

I think that for me so long as it can simultaneously do two unrelated
functions which need to be arbitrated between there's probably a place
for it in MFD, certainly at the minute.

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-14 16:01                                 ` Mark Brown
  0 siblings, 0 replies; 166+ messages in thread
From: Mark Brown @ 2011-05-14 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 13, 2011 at 04:25:56PM +0530, Subhasish Ghosh wrote:

> >Instead, maybe you can simply call platform_device_register
> >at that stage to create the children and not use MFD at all.

> >Samuel, can you comment on this as well? Do you still see pruss
> >as an MFD driver when the uses are completely dynamic and determined
> >by the firmware loaded into it?

> But in that case, where do I fit my driver.
> It's a microcontroller inside of a processor, guess that's unique for Linux.

It's not that unusual in hardware terms, really.  There's an awful lot
of this going on in the audio area especially at the minute so there's
going to be some effort around providing some framework support for this
which should have some general usability but that's not there yet.

> Will a misc device be a better choice.

> In that case I can remove the MFD cell from the board_file and add an array
> of platform_device for the UART & CAN.

I think that for me so long as it can simultaneously do two unrelated
functions which need to be arbitrated between there's probably a place
for it in MFD, certainly at the minute.

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-14 16:01                                 ` Mark Brown
@ 2011-05-14 20:33                                   ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-14 20:33 UTC (permalink / raw)
  To: Mark Brown
  Cc: Subhasish Ghosh, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Saturday 14 May 2011, Mark Brown wrote:
> > Will a misc device be a better choice.
> 
> > In that case I can remove the MFD cell from the board_file and add an array
> > of platform_device for the UART & CAN.
> 
> I think that for me so long as it can simultaneously do two unrelated
> functions which need to be arbitrated between there's probably a place
> for it in MFD, certainly at the minute.

I guess drivers/mfd would be a better place than drivers/misc, but it might not
need to be an mfd driver in the sense that it registers mfd cells.

The more important point is to remove the device registration from the board
file. You definitely should not have the cells in the board file, but replacing
them with platform devices in the board file makes it no better.

My whole point has been that you register them from the main pruss driver
based on run-time data instead of compile-time pre-configured stuff in the
board file.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-14 20:33                                   ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-14 20:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Saturday 14 May 2011, Mark Brown wrote:
> > Will a misc device be a better choice.
> 
> > In that case I can remove the MFD cell from the board_file and add an array
> > of platform_device for the UART & CAN.
> 
> I think that for me so long as it can simultaneously do two unrelated
> functions which need to be arbitrated between there's probably a place
> for it in MFD, certainly at the minute.

I guess drivers/mfd would be a better place than drivers/misc, but it might not
need to be an mfd driver in the sense that it registers mfd cells.

The more important point is to remove the device registration from the board
file. You definitely should not have the cells in the board file, but replacing
them with platform devices in the board file makes it no better.

My whole point has been that you register them from the main pruss driver
based on run-time data instead of compile-time pre-configured stuff in the
board file.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-14 20:33                                   ` Arnd Bergmann
@ 2011-05-14 22:14                                     ` Mark Brown
  -1 siblings, 0 replies; 166+ messages in thread
From: Mark Brown @ 2011-05-14 22:14 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Subhasish Ghosh, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Sat, May 14, 2011 at 10:33:53PM +0200, Arnd Bergmann wrote:

> I guess drivers/mfd would be a better place than drivers/misc, but it might not
> need to be an mfd driver in the sense that it registers mfd cells.

Yes, it might be more sensible to just open code.  OTOH mfd_cell is
marginally easier to use.

> The more important point is to remove the device registration from the board
> file. You definitely should not have the cells in the board file, but replacing
> them with platform devices in the board file makes it no better.

Agreed entirely, it should be something higher level than that.

> My whole point has been that you register them from the main pruss driver
> based on run-time data instead of compile-time pre-configured stuff in the
> board file.

I'm not so sure - if the usage is fixed as a result of the pins on the
device being wired a CAN bus then it seems reasonable to tell the system
about that so it'll stop the user trying to run SPI or something against
it at runtime.

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-14 22:14                                     ` Mark Brown
  0 siblings, 0 replies; 166+ messages in thread
From: Mark Brown @ 2011-05-14 22:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 14, 2011 at 10:33:53PM +0200, Arnd Bergmann wrote:

> I guess drivers/mfd would be a better place than drivers/misc, but it might not
> need to be an mfd driver in the sense that it registers mfd cells.

Yes, it might be more sensible to just open code.  OTOH mfd_cell is
marginally easier to use.

> The more important point is to remove the device registration from the board
> file. You definitely should not have the cells in the board file, but replacing
> them with platform devices in the board file makes it no better.

Agreed entirely, it should be something higher level than that.

> My whole point has been that you register them from the main pruss driver
> based on run-time data instead of compile-time pre-configured stuff in the
> board file.

I'm not so sure - if the usage is fixed as a result of the pins on the
device being wired a CAN bus then it seems reasonable to tell the system
about that so it'll stop the user trying to run SPI or something against
it at runtime.

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-14 22:14                                     ` Mark Brown
@ 2011-05-15  9:33                                       ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-15  9:33 UTC (permalink / raw)
  To: Mark Brown
  Cc: Subhasish Ghosh, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Sunday 15 May 2011, Mark Brown wrote:
> > My whole point has been that you register them from the main pruss driver
> > based on run-time data instead of compile-time pre-configured stuff in the
> > board file.
> 
> I'm not so sure - if the usage is fixed as a result of the pins on the
> device being wired a CAN bus then it seems reasonable to tell the system
> about that so it'll stop the user trying to run SPI or something against
> it at runtime.

I'm mostly worried about the case where the pins are not hardwired for
some specific function -- Subhasish was mentioning that these may be
implemented using a pluggable extension board and I want to make sure
that you are not required to recompile the kernel when changing the
extension board.

However, you made a good point that in many cases it will be hardwired
so it may be valuable to preconfigure this in a way that does not require
scripts to set up variables in sysfs when you already know what is there.

Note that my suggestion to put the device name into the firmware file
covers this case, because you can then simply ship a firmware blob that
matches the hardware configuration. Thinking about the future device
tree setup, you can even put the firmware blob itself into a property
in the device tree file.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-15  9:33                                       ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-15  9:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 15 May 2011, Mark Brown wrote:
> > My whole point has been that you register them from the main pruss driver
> > based on run-time data instead of compile-time pre-configured stuff in the
> > board file.
> 
> I'm not so sure - if the usage is fixed as a result of the pins on the
> device being wired a CAN bus then it seems reasonable to tell the system
> about that so it'll stop the user trying to run SPI or something against
> it at runtime.

I'm mostly worried about the case where the pins are not hardwired for
some specific function -- Subhasish was mentioning that these may be
implemented using a pluggable extension board and I want to make sure
that you are not required to recompile the kernel when changing the
extension board.

However, you made a good point that in many cases it will be hardwired
so it may be valuable to preconfigure this in a way that does not require
scripts to set up variables in sysfs when you already know what is there.

Note that my suggestion to put the device name into the firmware file
covers this case, because you can then simply ship a firmware blob that
matches the hardware configuration. Thinking about the future device
tree setup, you can even put the firmware blob itself into a property
in the device tree file.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-15  9:33                                       ` Arnd Bergmann
@ 2011-05-16  6:06                                         ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-16  6:06 UTC (permalink / raw)
  To: Arnd Bergmann, Mark Brown
  Cc: Nori, Sekhar, linux-arm-kernel, davinci-linux-open-source, sachi,
	Samuel Ortiz, open list, Watkins, Melissa

Hi!,

>> > My whole point has been that you register them from the main pruss 
>> > driver
>> > based on run-time data instead of compile-time pre-configured stuff in 
>> > the
>> > board file.
>>
>> I'm not so sure - if the usage is fixed as a result of the pins on the
>> device being wired a CAN bus then it seems reasonable to tell the system
>> about that so it'll stop the user trying to run SPI or something against
>> it at runtime.
>
> I'm mostly worried about the case where the pins are not hardwired for
> some specific function -- Subhasish was mentioning that these may be
> implemented using a pluggable extension board and I want to make sure
> that you are not required to recompile the kernel when changing the
> extension board.
>
> However, you made a good point that in many cases it will be hardwired
> so it may be valuable to preconfigure this in a way that does not require
> scripts to set up variables in sysfs when you already know what is there.
>
> Note that my suggestion to put the device name into the firmware file
> covers this case, because you can then simply ship a firmware blob that
> matches the hardware configuration. Thinking about the future device
> tree setup, you can even put the firmware blob itself into a property
> in the device tree file.
>

I earlier had an implementation where I used a pruss_devices structure
in the board file.

http://linux.omap.com/pipermail/davinci-linux-open-source/
2011-March/022339.html.

We can use this implementation along with the sysfs to load the devices
runtime. The configs that I have in the board_file for the devices 
structure,
are fixed for a board. To swap the boards, we do not need to re-compile
the kernel.

 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-16  6:06                                         ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-16  6:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi!,

>> > My whole point has been that you register them from the main pruss 
>> > driver
>> > based on run-time data instead of compile-time pre-configured stuff in 
>> > the
>> > board file.
>>
>> I'm not so sure - if the usage is fixed as a result of the pins on the
>> device being wired a CAN bus then it seems reasonable to tell the system
>> about that so it'll stop the user trying to run SPI or something against
>> it at runtime.
>
> I'm mostly worried about the case where the pins are not hardwired for
> some specific function -- Subhasish was mentioning that these may be
> implemented using a pluggable extension board and I want to make sure
> that you are not required to recompile the kernel when changing the
> extension board.
>
> However, you made a good point that in many cases it will be hardwired
> so it may be valuable to preconfigure this in a way that does not require
> scripts to set up variables in sysfs when you already know what is there.
>
> Note that my suggestion to put the device name into the firmware file
> covers this case, because you can then simply ship a firmware blob that
> matches the hardware configuration. Thinking about the future device
> tree setup, you can even put the firmware blob itself into a property
> in the device tree file.
>

I earlier had an implementation where I used a pruss_devices structure
in the board file.

http://linux.omap.com/pipermail/davinci-linux-open-source/
2011-March/022339.html.

We can use this implementation along with the sysfs to load the devices
runtime. The configs that I have in the board_file for the devices 
structure,
are fixed for a board. To swap the boards, we do not need to re-compile
the kernel.

 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-11 20:03                             ` Arnd Bergmann
@ 2011-05-22 20:21                               ` Samuel Ortiz
  -1 siblings, 0 replies; 166+ messages in thread
From: Samuel Ortiz @ 2011-05-22 20:21 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Subhasish Ghosh, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, open list, Watkins, Melissa

Hi Arnd,

On Wed, May 11, 2011 at 10:03:54PM +0200, Arnd Bergmann wrote:
> On Wednesday 11 May 2011, Subhasish Ghosh wrote:
> > > Please look into implementing one of the three I suggested before
> > > you go off in another direction. In case of the third one, the idea
> > > was to configure the name of the device for each pru using sysfs,
> > > which then gets bound to the driver, which loads its own firmware
> > > as you do today. Only in the first two suggestions, the mfd driver
> > > would be responsible for loading the firmware.
> > 
> > Ok, thanks for the clarification.
> > Instead of passing the device name, will it be ok to pass the mfd_id.
> > The benefit will be that I can use the ID directly as an array
> > index for the mfd_cell entries.
> 
> I think a device name would be clearer here, especially in order
> to avoid conflicts when the list gets extended in different ways
> depending on which kernel runs.
> 
> We had a little discussion at the Linaro Developer Summit about your
> driver and mfd drivers in general. There was a general feeling among
> some people (including me) that by the point you dynamically create
> the subdevices, MFD is probably not the right abstraction any more,
> as it does not provide any service that you need.
I agree it's not what it's been designed for.


> Instead, maybe you can simply call platform_device_register
> at that stage to create the children and not use MFD at all.
The MFD APIs are slightly easier to use though, imho.


> Samuel, can you comment on this as well? Do you still see pruss
> as an MFD driver when the uses are completely dynamic and determined
> by the firmware loaded into it?
Even though that is definitely not a typical MFD use case, I wouldn't object
strongly against it. Right now mfd is probably the least worst choice for this
kind of drivers, which still doesn't make it an ideal situation.

Cheers,
Samuel.

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

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-22 20:21                               ` Samuel Ortiz
  0 siblings, 0 replies; 166+ messages in thread
From: Samuel Ortiz @ 2011-05-22 20:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

On Wed, May 11, 2011 at 10:03:54PM +0200, Arnd Bergmann wrote:
> On Wednesday 11 May 2011, Subhasish Ghosh wrote:
> > > Please look into implementing one of the three I suggested before
> > > you go off in another direction. In case of the third one, the idea
> > > was to configure the name of the device for each pru using sysfs,
> > > which then gets bound to the driver, which loads its own firmware
> > > as you do today. Only in the first two suggestions, the mfd driver
> > > would be responsible for loading the firmware.
> > 
> > Ok, thanks for the clarification.
> > Instead of passing the device name, will it be ok to pass the mfd_id.
> > The benefit will be that I can use the ID directly as an array
> > index for the mfd_cell entries.
> 
> I think a device name would be clearer here, especially in order
> to avoid conflicts when the list gets extended in different ways
> depending on which kernel runs.
> 
> We had a little discussion at the Linaro Developer Summit about your
> driver and mfd drivers in general. There was a general feeling among
> some people (including me) that by the point you dynamically create
> the subdevices, MFD is probably not the right abstraction any more,
> as it does not provide any service that you need.
I agree it's not what it's been designed for.


> Instead, maybe you can simply call platform_device_register
> at that stage to create the children and not use MFD at all.
The MFD APIs are slightly easier to use though, imho.


> Samuel, can you comment on this as well? Do you still see pruss
> as an MFD driver when the uses are completely dynamic and determined
> by the firmware loaded into it?
Even though that is definitely not a typical MFD use case, I wouldn't object
strongly against it. Right now mfd is probably the least worst choice for this
kind of drivers, which still doesn't make it an ideal situation.

Cheers,
Samuel.

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

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-14 20:33                                   ` Arnd Bergmann
@ 2011-05-22 20:24                                     ` Samuel Ortiz
  -1 siblings, 0 replies; 166+ messages in thread
From: Samuel Ortiz @ 2011-05-22 20:24 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Brown, Subhasish Ghosh, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, open list, Watkins, Melissa

Hi Arnd,

On Sat, May 14, 2011 at 10:33:53PM +0200, Arnd Bergmann wrote:
> On Saturday 14 May 2011, Mark Brown wrote:
> > > Will a misc device be a better choice.
> > 
> > > In that case I can remove the MFD cell from the board_file and add an array
> > > of platform_device for the UART & CAN.
> > 
> > I think that for me so long as it can simultaneously do two unrelated
> > functions which need to be arbitrated between there's probably a place
> > for it in MFD, certainly at the minute.
> 
> I guess drivers/mfd would be a better place than drivers/misc, but it might not
> need to be an mfd driver in the sense that it registers mfd cells.
> 
I agree with that. Although if it makes it to drivers/mfd/, I'd prefer to see
it using the MF API.


> The more important point is to remove the device registration from the board
> file. You definitely should not have the cells in the board file, but replacing
> them with platform devices in the board file makes it no better.
> 
> My whole point has been that you register them from the main pruss driver
> based on run-time data instead of compile-time pre-configured stuff in the
> board file.
That's certainly right.

Cheers,
Samuel.

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

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-22 20:24                                     ` Samuel Ortiz
  0 siblings, 0 replies; 166+ messages in thread
From: Samuel Ortiz @ 2011-05-22 20:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

On Sat, May 14, 2011 at 10:33:53PM +0200, Arnd Bergmann wrote:
> On Saturday 14 May 2011, Mark Brown wrote:
> > > Will a misc device be a better choice.
> > 
> > > In that case I can remove the MFD cell from the board_file and add an array
> > > of platform_device for the UART & CAN.
> > 
> > I think that for me so long as it can simultaneously do two unrelated
> > functions which need to be arbitrated between there's probably a place
> > for it in MFD, certainly at the minute.
> 
> I guess drivers/mfd would be a better place than drivers/misc, but it might not
> need to be an mfd driver in the sense that it registers mfd cells.
> 
I agree with that. Although if it makes it to drivers/mfd/, I'd prefer to see
it using the MF API.


> The more important point is to remove the device registration from the board
> file. You definitely should not have the cells in the board file, but replacing
> them with platform devices in the board file makes it no better.
> 
> My whole point has been that you register them from the main pruss driver
> based on run-time data instead of compile-time pre-configured stuff in the
> board file.
That's certainly right.

Cheers,
Samuel.

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

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-22 20:21                               ` Samuel Ortiz
@ 2011-05-23 15:13                                 ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-23 15:13 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Subhasish Ghosh, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, open list, Watkins, Melissa

Hi Samuel,

On Sunday 22 May 2011, Samuel Ortiz wrote:
> On Wed, May 11, 2011 at 10:03:54PM +0200, Arnd Bergmann wrote:
> > On Wednesday 11 May 2011, Subhasish Ghosh wrote:
> > We had a little discussion at the Linaro Developer Summit about your
> > driver and mfd drivers in general. There was a general feeling among
> > some people (including me) that by the point you dynamically create
> > the subdevices, MFD is probably not the right abstraction any more,
> > as it does not provide any service that you need.
> I agree it's not what it's been designed for.
> 
> 
> > Instead, maybe you can simply call platform_device_register
> > at that stage to create the children and not use MFD at all.
> The MFD APIs are slightly easier to use though, imho.
> 
> 
> > Samuel, can you comment on this as well? Do you still see pruss
> > as an MFD driver when the uses are completely dynamic and determined
> > by the firmware loaded into it?
> Even though that is definitely not a typical MFD use case, I wouldn't object
> strongly against it. Right now mfd is probably the least worst choice for this
> kind of drivers, which still doesn't make it an ideal situation.

Thanks for your input! When you say that MFD APIs are easier to use than
platform_device APIs, is that something we should fix with platform devices
to make them easier to use?

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-23 15:13                                 ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-23 15:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Samuel,

On Sunday 22 May 2011, Samuel Ortiz wrote:
> On Wed, May 11, 2011 at 10:03:54PM +0200, Arnd Bergmann wrote:
> > On Wednesday 11 May 2011, Subhasish Ghosh wrote:
> > We had a little discussion at the Linaro Developer Summit about your
> > driver and mfd drivers in general. There was a general feeling among
> > some people (including me) that by the point you dynamically create
> > the subdevices, MFD is probably not the right abstraction any more,
> > as it does not provide any service that you need.
> I agree it's not what it's been designed for.
> 
> 
> > Instead, maybe you can simply call platform_device_register
> > at that stage to create the children and not use MFD at all.
> The MFD APIs are slightly easier to use though, imho.
> 
> 
> > Samuel, can you comment on this as well? Do you still see pruss
> > as an MFD driver when the uses are completely dynamic and determined
> > by the firmware loaded into it?
> Even though that is definitely not a typical MFD use case, I wouldn't object
> strongly against it. Right now mfd is probably the least worst choice for this
> kind of drivers, which still doesn't make it an ideal situation.

Thanks for your input! When you say that MFD APIs are easier to use than
platform_device APIs, is that something we should fix with platform devices
to make them easier to use?

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-16  6:06                                         ` Subhasish Ghosh
@ 2011-05-23 15:30                                           ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-23 15:30 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Monday 16 May 2011, Subhasish Ghosh wrote:
> I earlier had an implementation where I used a pruss_devices structure
> in the board file.
> 
> http://linux.omap.com/pipermail/davinci-linux-open-source/
> 2011-March/022339.html.
> 
> We can use this implementation along with the sysfs to load the devices
> runtime. 

Possibly, but the actual data structures might end up differently
when they are built around a sysfs interface. If you have a sysfs
interface, it is more important to have that in a clean way than
the board file, so we should first discuss the set of sysfs
attributes that you are going to need, and then see how to
represent that in platform data for predefined boards.

> The configs that I have in the board_file for the devices 
> structure, are fixed for a board. To swap the boards, we do not need to re-compile
> the kernel.

The other point to consider is that we are definitely moving
towards the flattened device tree for these definitions now.
It's probably good to make the sysfs attributes directly correspond
to fdt device properties. I'm not sure if we also need to allow platform
data. The easiest way could be to just require the use of device tree
for predefined pruss devices.

I'm sorry that this is moving in a different direction now, you
had an unfortunate timing here.

Let's first discuss the exact properties that are really required
to define the differences between PRU backends, as those will
be required in any case. What do you need for PRU specific
data besides the firmware and the name of the device?

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-23 15:30                                           ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-23 15:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 16 May 2011, Subhasish Ghosh wrote:
> I earlier had an implementation where I used a pruss_devices structure
> in the board file.
> 
> http://linux.omap.com/pipermail/davinci-linux-open-source/
> 2011-March/022339.html.
> 
> We can use this implementation along with the sysfs to load the devices
> runtime. 

Possibly, but the actual data structures might end up differently
when they are built around a sysfs interface. If you have a sysfs
interface, it is more important to have that in a clean way than
the board file, so we should first discuss the set of sysfs
attributes that you are going to need, and then see how to
represent that in platform data for predefined boards.

> The configs that I have in the board_file for the devices 
> structure, are fixed for a board. To swap the boards, we do not need to re-compile
> the kernel.

The other point to consider is that we are definitely moving
towards the flattened device tree for these definitions now.
It's probably good to make the sysfs attributes directly correspond
to fdt device properties. I'm not sure if we also need to allow platform
data. The easiest way could be to just require the use of device tree
for predefined pruss devices.

I'm sorry that this is moving in a different direction now, you
had an unfortunate timing here.

Let's first discuss the exact properties that are really required
to define the differences between PRU backends, as those will
be required in any case. What do you need for PRU specific
data besides the firmware and the name of the device?

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver.
  2011-05-23 15:30                                           ` Arnd Bergmann
@ 2011-05-24 12:17                                             ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-24 12:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

Hi Arnd,

>> http://linux.omap.com/pipermail/davinci-linux-open-source/
>> 2011-March/022339.html.
>>
>> We can use this implementation along with the sysfs to load the devices
>> runtime.
>
> Possibly, but the actual data structures might end up differently
> when they are built around a sysfs interface. If you have a sysfs
> interface, it is more important to have that in a clean way than
> the board file, so we should first discuss the set of sysfs
> attributes that you are going to need, and then see how to
> represent that in platform data for predefined boards.
>
>> The configs that I have in the board_file for the devices
>> structure, are fixed for a board. To swap the boards, we do not need to 
>> re-compile
>> the kernel.
>
> The other point to consider is that we are definitely moving
> towards the flattened device tree for these definitions now.
> It's probably good to make the sysfs attributes directly correspond
> to fdt device properties. I'm not sure if we also need to allow platform
> data. The easiest way could be to just require the use of device tree
> for predefined pruss devices.
>
> I'm sorry that this is moving in a different direction now, you
> had an unfortunate timing here.
>
> Let's first discuss the exact properties that are really required
> to define the differences between PRU backends, as those will
> be required in any case. What do you need for PRU specific
> data besides the firmware and the name of the device?

Would it be a good approach to first get a basic sensible
driver into the tree and then work towards improving and
adjusting for future compatibilities.
That way we can gradually build towards the perfect driver
in steps, rather than digressing far too off suddenly.
That would be some source of motivation for me too.
 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver.
@ 2011-05-24 12:17                                             ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-24 12:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

>> http://linux.omap.com/pipermail/davinci-linux-open-source/
>> 2011-March/022339.html.
>>
>> We can use this implementation along with the sysfs to load the devices
>> runtime.
>
> Possibly, but the actual data structures might end up differently
> when they are built around a sysfs interface. If you have a sysfs
> interface, it is more important to have that in a clean way than
> the board file, so we should first discuss the set of sysfs
> attributes that you are going to need, and then see how to
> represent that in platform data for predefined boards.
>
>> The configs that I have in the board_file for the devices
>> structure, are fixed for a board. To swap the boards, we do not need to 
>> re-compile
>> the kernel.
>
> The other point to consider is that we are definitely moving
> towards the flattened device tree for these definitions now.
> It's probably good to make the sysfs attributes directly correspond
> to fdt device properties. I'm not sure if we also need to allow platform
> data. The easiest way could be to just require the use of device tree
> for predefined pruss devices.
>
> I'm sorry that this is moving in a different direction now, you
> had an unfortunate timing here.
>
> Let's first discuss the exact properties that are really required
> to define the differences between PRU backends, as those will
> be required in any case. What do you need for PRU specific
> data besides the firmware and the name of the device?

Would it be a good approach to first get a basic sensible
driver into the tree and then work towards improving and
adjusting for future compatibilities.
That way we can gradually build towards the perfect driver
in steps, rather than digressing far too off suddenly.
That would be some source of motivation for me too.
 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-24 12:17                                             ` Subhasish Ghosh
@ 2011-05-24 12:40                                               ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-24 12:40 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa, Greg KH

On Tuesday 24 May 2011, Subhasish Ghosh wrote:
> Would it be a good approach to first get a basic sensible
> driver into the tree and then work towards improving and
> adjusting for future compatibilities.

The main problem with that is that you cannot really change
user-visible interfaces after the driver is merged. Anything
regarding sysfs attributes and firmware file contents needs
to be fixed. You can however still change in-kernel interfaces
at a later point without problems.

> That way we can gradually build towards the perfect driver
> in steps, rather than digressing far too off suddenly.
> That would be some source of motivation for me too.

You can definitely add the driver to drivers/staging/pruss/,
as the rules for staging drivers are different. I think that
would indeed be helpful at this point. As soon as all
interfaces have stabilized, you can then move the individual
parts to their final location.

Greg maintains the staging drivers, and he can surely point
you to a document describing what is required for a driver.
Mainly, this includes having a patch that adds a single
directory with all the driver files under drivers/staging.
The driver must be able to compile without errors and you need
a TODO file listing the remaining issues that prevent you
from having a non-staging driver.

I think the list will be relatively short, given that you
have made a lot of progress and the driver is now essentially
ready, aside from a few details and the big question of
how the firmware should be configured and loaded.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-24 12:40                                               ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-24 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 24 May 2011, Subhasish Ghosh wrote:
> Would it be a good approach to first get a basic sensible
> driver into the tree and then work towards improving and
> adjusting for future compatibilities.

The main problem with that is that you cannot really change
user-visible interfaces after the driver is merged. Anything
regarding sysfs attributes and firmware file contents needs
to be fixed. You can however still change in-kernel interfaces
at a later point without problems.

> That way we can gradually build towards the perfect driver
> in steps, rather than digressing far too off suddenly.
> That would be some source of motivation for me too.

You can definitely add the driver to drivers/staging/pruss/,
as the rules for staging drivers are different. I think that
would indeed be helpful at this point. As soon as all
interfaces have stabilized, you can then move the individual
parts to their final location.

Greg maintains the staging drivers, and he can surely point
you to a document describing what is required for a driver.
Mainly, this includes having a patch that adds a single
directory with all the driver files under drivers/staging.
The driver must be able to compile without errors and you need
a TODO file listing the remaining issues that prevent you
from having a non-staging driver.

I think the list will be relatively short, given that you
have made a lot of progress and the driver is now essentially
ready, aside from a few details and the big question of
how the firmware should be configured and loaded.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-24 12:40                                               ` Arnd Bergmann
@ 2011-05-24 13:43                                                 ` Greg KH
  -1 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-05-24 13:43 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Subhasish Ghosh, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Tue, May 24, 2011 at 02:40:34PM +0200, Arnd Bergmann wrote:
> On Tuesday 24 May 2011, Subhasish Ghosh wrote:
> > Would it be a good approach to first get a basic sensible
> > driver into the tree and then work towards improving and
> > adjusting for future compatibilities.
> 
> The main problem with that is that you cannot really change
> user-visible interfaces after the driver is merged. Anything
> regarding sysfs attributes and firmware file contents needs
> to be fixed. You can however still change in-kernel interfaces
> at a later point without problems.
> 
> > That way we can gradually build towards the perfect driver
> > in steps, rather than digressing far too off suddenly.
> > That would be some source of motivation for me too.
> 
> You can definitely add the driver to drivers/staging/pruss/,
> as the rules for staging drivers are different. I think that
> would indeed be helpful at this point. As soon as all
> interfaces have stabilized, you can then move the individual
> parts to their final location.
> 
> Greg maintains the staging drivers, and he can surely point
> you to a document describing what is required for a driver.

There really are only 3 rules:
	- proper license
	- self-contained in a drivers/staging/DRIVER_NAME/ directory
	- must properly build

> Mainly, this includes having a patch that adds a single
> directory with all the driver files under drivers/staging.
> The driver must be able to compile without errors and you need
> a TODO file listing the remaining issues that prevent you
> from having a non-staging driver.

Ah, forgot the TODO on the list of rules, I'll have to add that next
time.

Someone feel free to send me a patch :)

thanks,

greg k-h

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-24 13:43                                                 ` Greg KH
  0 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-05-24 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 24, 2011 at 02:40:34PM +0200, Arnd Bergmann wrote:
> On Tuesday 24 May 2011, Subhasish Ghosh wrote:
> > Would it be a good approach to first get a basic sensible
> > driver into the tree and then work towards improving and
> > adjusting for future compatibilities.
> 
> The main problem with that is that you cannot really change
> user-visible interfaces after the driver is merged. Anything
> regarding sysfs attributes and firmware file contents needs
> to be fixed. You can however still change in-kernel interfaces
> at a later point without problems.
> 
> > That way we can gradually build towards the perfect driver
> > in steps, rather than digressing far too off suddenly.
> > That would be some source of motivation for me too.
> 
> You can definitely add the driver to drivers/staging/pruss/,
> as the rules for staging drivers are different. I think that
> would indeed be helpful at this point. As soon as all
> interfaces have stabilized, you can then move the individual
> parts to their final location.
> 
> Greg maintains the staging drivers, and he can surely point
> you to a document describing what is required for a driver.

There really are only 3 rules:
	- proper license
	- self-contained in a drivers/staging/DRIVER_NAME/ directory
	- must properly build

> Mainly, this includes having a patch that adds a single
> directory with all the driver files under drivers/staging.
> The driver must be able to compile without errors and you need
> a TODO file listing the remaining issues that prevent you
> from having a non-staging driver.

Ah, forgot the TODO on the list of rules, I'll have to add that next
time.

Someone feel free to send me a patch :)

thanks,

greg k-h

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-24 13:43                                                 ` Greg KH
@ 2011-05-30 13:25                                                   ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 13:25 UTC (permalink / raw)
  To: Greg KH, Arnd Bergmann
  Cc: Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

Greg,

> There really are only 3 rules:
> - proper license
> - self-contained in a drivers/staging/DRIVER_NAME/ directory
> - must properly build
> 
>> Mainly, this includes having a patch that adds a single
>> directory with all the driver files under drivers/staging.
>> The driver must be able to compile without errors and you need
>> a TODO file listing the remaining issues that prevent you
>> from having a non-staging driver.
> 
> Ah, forgot the TODO on the list of rules, I'll have to add that next
> time.
> 
How do I handle the headers. I have two header files in the
include/linux/mfd.

Should I submit them as a separate patch into mfd.

These headers are also used by pruss uart implementation. 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 13:25                                                   ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 13:25 UTC (permalink / raw)
  To: linux-arm-kernel

Greg,

> There really are only 3 rules:
> - proper license
> - self-contained in a drivers/staging/DRIVER_NAME/ directory
> - must properly build
> 
>> Mainly, this includes having a patch that adds a single
>> directory with all the driver files under drivers/staging.
>> The driver must be able to compile without errors and you need
>> a TODO file listing the remaining issues that prevent you
>> from having a non-staging driver.
> 
> Ah, forgot the TODO on the list of rules, I'll have to add that next
> time.
> 
How do I handle the headers. I have two header files in the
include/linux/mfd.

Should I submit them as a separate patch into mfd.

These headers are also used by pruss uart implementation. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-30 13:25                                                   ` Subhasish Ghosh
@ 2011-05-30 14:02                                                     ` Greg KH
  -1 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-05-30 14:02 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Arnd Bergmann, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Mon, May 30, 2011 at 06:55:12PM +0530, Subhasish Ghosh wrote:
> Greg,
> 
> >There really are only 3 rules:
> >- proper license
> >- self-contained in a drivers/staging/DRIVER_NAME/ directory
> >- must properly build
> >
> >>Mainly, this includes having a patch that adds a single
> >>directory with all the driver files under drivers/staging.
> >>The driver must be able to compile without errors and you need
> >>a TODO file listing the remaining issues that prevent you
> >>from having a non-staging driver.
> >
> >Ah, forgot the TODO on the list of rules, I'll have to add that next
> >time.
> >
> How do I handle the headers. I have two header files in the
> include/linux/mfd.

Why would they be in there for a single driver?

> Should I submit them as a separate patch into mfd.
> 
> These headers are also used by pruss uart implementation.

Then put them in the staging directory for your driver, why would
anything outside of your driver need a .h file?

thanks,

greg k-h

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 14:02                                                     ` Greg KH
  0 siblings, 0 replies; 166+ messages in thread
From: Greg KH @ 2011-05-30 14:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 30, 2011 at 06:55:12PM +0530, Subhasish Ghosh wrote:
> Greg,
> 
> >There really are only 3 rules:
> >- proper license
> >- self-contained in a drivers/staging/DRIVER_NAME/ directory
> >- must properly build
> >
> >>Mainly, this includes having a patch that adds a single
> >>directory with all the driver files under drivers/staging.
> >>The driver must be able to compile without errors and you need
> >>a TODO file listing the remaining issues that prevent you
> >>from having a non-staging driver.
> >
> >Ah, forgot the TODO on the list of rules, I'll have to add that next
> >time.
> >
> How do I handle the headers. I have two header files in the
> include/linux/mfd.

Why would they be in there for a single driver?

> Should I submit them as a separate patch into mfd.
> 
> These headers are also used by pruss uart implementation.

Then put them in the staging directory for your driver, why would
anything outside of your driver need a .h file?

thanks,

greg k-h

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-30 13:25                                                   ` Subhasish Ghosh
@ 2011-05-30 14:04                                                     ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-30 14:04 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Greg KH, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Monday 30 May 2011, Subhasish Ghosh wrote:
> > Ah, forgot the TODO on the list of rules, I'll have to add that next
> > time.
> > 
> How do I handle the headers. I have two header files in the
> include/linux/mfd.
> 
> Should I submit them as a separate patch into mfd.
> 
> These headers are also used by pruss uart implementation. 

During the time when the drivers are in staging, all files need to
be in the same directory, including the header and the drivers using it.
They can get moved at the time when the driver gets turned into
a regular non-staging driver.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 14:04                                                     ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-30 14:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 30 May 2011, Subhasish Ghosh wrote:
> > Ah, forgot the TODO on the list of rules, I'll have to add that next
> > time.
> > 
> How do I handle the headers. I have two header files in the
> include/linux/mfd.
> 
> Should I submit them as a separate patch into mfd.
> 
> These headers are also used by pruss uart implementation. 

During the time when the drivers are in staging, all files need to
be in the same directory, including the header and the drivers using it.
They can get moved at the time when the driver gets turned into
a regular non-staging driver.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-30 14:04                                                     ` Arnd Bergmann
@ 2011-05-30 14:13                                                       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 14:13 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Greg KH, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

> On Monday 30 May 2011, Subhasish Ghosh wrote:
>> > Ah, forgot the TODO on the list of rules, I'll have to add that next
>> > time.
>> >
>> How do I handle the headers. I have two header files in the
>> include/linux/mfd.
>>
>> Should I submit them as a separate patch into mfd.
>>
>> These headers are also used by pruss uart implementation.
>
> During the time when the drivers are in staging, all files need to
> be in the same directory, including the header and the drivers using it.
> They can get moved at the time when the driver gets turned into
> a regular non-staging driver.

OK, so the UART implementation needs to be moved into staging as well ?

And what about the boardfile changes, array of mfd_cells implementation etc. 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 14:13                                                       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

> On Monday 30 May 2011, Subhasish Ghosh wrote:
>> > Ah, forgot the TODO on the list of rules, I'll have to add that next
>> > time.
>> >
>> How do I handle the headers. I have two header files in the
>> include/linux/mfd.
>>
>> Should I submit them as a separate patch into mfd.
>>
>> These headers are also used by pruss uart implementation.
>
> During the time when the drivers are in staging, all files need to
> be in the same directory, including the header and the drivers using it.
> They can get moved at the time when the driver gets turned into
> a regular non-staging driver.

OK, so the UART implementation needs to be moved into staging as well ?

And what about the boardfile changes, array of mfd_cells implementation etc. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-30 14:02                                                     ` Greg KH
@ 2011-05-30 14:38                                                       ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 14:38 UTC (permalink / raw)
  To: Greg KH
  Cc: Arnd Bergmann, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

Greg,

>> >
>> How do I handle the headers. I have two header files in the
>> include/linux/mfd.
> 
> Why would they be in there for a single driver?
> 
>> Should I submit them as a separate patch into mfd.
>> 
>> These headers are also used by pruss uart implementation.
> 
> Then put them in the staging directory for your driver, why would
> anything outside of your driver need a .h file?
> 
There are two header files in the include/linux/mfd/pruss.h & pruss_core.h

the file pruss.h is included by the pruss_suart_api.c (tty uart driver) for
some data structures, defines and function prototypes. 

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 14:38                                                       ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

Greg,

>> >
>> How do I handle the headers. I have two header files in the
>> include/linux/mfd.
> 
> Why would they be in there for a single driver?
> 
>> Should I submit them as a separate patch into mfd.
>> 
>> These headers are also used by pruss uart implementation.
> 
> Then put them in the staging directory for your driver, why would
> anything outside of your driver need a .h file?
> 
There are two header files in the include/linux/mfd/pruss.h & pruss_core.h

the file pruss.h is included by the pruss_suart_api.c (tty uart driver) for
some data structures, defines and function prototypes. 

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-30 14:13                                                       ` Subhasish Ghosh
@ 2011-05-30 14:43                                                         ` Arnd Bergmann
  -1 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-30 14:43 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Greg KH, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

On Monday 30 May 2011, Subhasish Ghosh wrote:
> >
> > During the time when the drivers are in staging, all files need to
> > be in the same directory, including the header and the drivers using it.
> > They can get moved at the time when the driver gets turned into
> > a regular non-staging driver.
> 
> OK, so the UART implementation needs to be moved into staging as well ?
> 
> And what about the boardfile changes, array of mfd_cells implementation etc. 

All of that, too.

Note that you are citing exactly the points that are the reason for the
discussion we are having. The mfd_cells are the main concern for the cases
where the information is not static.

	Arnd

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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 14:43                                                         ` Arnd Bergmann
  0 siblings, 0 replies; 166+ messages in thread
From: Arnd Bergmann @ 2011-05-30 14:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 30 May 2011, Subhasish Ghosh wrote:
> >
> > During the time when the drivers are in staging, all files need to
> > be in the same directory, including the header and the drivers using it.
> > They can get moved at the time when the driver gets turned into
> > a regular non-staging driver.
> 
> OK, so the UART implementation needs to be moved into staging as well ?
> 
> And what about the boardfile changes, array of mfd_cells implementation etc. 

All of that, too.

Note that you are citing exactly the points that are the reason for the
discussion we are having. The mfd_cells are the main concern for the cases
where the information is not static.

	Arnd

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

* Re: [PATCH v4 01/11] mfd: add pruss mfd driver
  2011-05-30 14:43                                                         ` Arnd Bergmann
@ 2011-05-30 15:28                                                           ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 15:28 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Greg KH, Mark Brown, Nori, Sekhar, linux-arm-kernel,
	davinci-linux-open-source, sachi, Samuel Ortiz, open list,
	Watkins, Melissa

> On Monday 30 May 2011, Subhasish Ghosh wrote:
>> >
>> > During the time when the drivers are in staging, all files need to
>> > be in the same directory, including the header and the drivers using 
>> > it.
>> > They can get moved at the time when the driver gets turned into
>> > a regular non-staging driver.
>>
>> OK, so the UART implementation needs to be moved into staging as well ?
>>
>> And what about the boardfile changes, array of mfd_cells implementation 
>> etc.
>
> All of that, too.
>
> Note that you are citing exactly the points that are the reason for the
> discussion we are having. The mfd_cells are the main concern for the cases
> where the information is not static.

Yes, but by destroying the structure that I have currently in the platform 
files,
I will be basically going backwards.

If only the platform_data is what is going to change with some additions
of sysfs attributes, then will it be correct to have the platform data
as an empty pointer and keep the rest as is ?

That way, I can keep the platform changes untouched and move just
the drivers into staging.

I cannot destroy the complete platform code as there are other drivers
(PRUSS UIO) depending on them. 


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

* [PATCH v4 01/11] mfd: add pruss mfd driver
@ 2011-05-30 15:28                                                           ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-30 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

> On Monday 30 May 2011, Subhasish Ghosh wrote:
>> >
>> > During the time when the drivers are in staging, all files need to
>> > be in the same directory, including the header and the drivers using 
>> > it.
>> > They can get moved at the time when the driver gets turned into
>> > a regular non-staging driver.
>>
>> OK, so the UART implementation needs to be moved into staging as well ?
>>
>> And what about the boardfile changes, array of mfd_cells implementation 
>> etc.
>
> All of that, too.
>
> Note that you are citing exactly the points that are the reason for the
> discussion we are having. The mfd_cells are the main concern for the cases
> where the information is not static.

Yes, but by destroying the structure that I have currently in the platform 
files,
I will be basically going backwards.

If only the platform_data is what is going to change with some additions
of sysfs attributes, then will it be correct to have the platform data
as an empty pointer and keep the rest as is ?

That way, I can keep the platform changes untouched and move just
the drivers into staging.

I cannot destroy the complete platform code as there are other drivers
(PRUSS UIO) depending on them. 

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-17 18:32   ` Nori, Sekhar
@ 2011-05-20  7:14     ` Subhasish Ghosh
  -1 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-20  7:14 UTC (permalink / raw)
  To: Nori, Sekhar
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

Hi Sekhar,

>> > ok, so what you are suggesting is that I implement some
>> > callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
>> > memory using sram_alloc.
>> > My doubt is, if already such API's are there (by Russel) or you
>> > are suggesting to implement them.
>>
>> I can add the fifo_alloc/dealloc as part of the suart platform_data,
>> Is that's what you are suggesting. If you may please point me out
>> to any example. I am just not clear with this.
>
> Yes, that's what I am suggesting. I don't have an exact example
> for you, but for an example of how function pointers can be passed
> along in platform data you can look at the platform data for
> DA8x FB driver in include/video/da8xx-fb.h.
>

Does this look ok.
This code snippet is in the driver file.

        if (soft_uart->use_sram) {
                soft_uart->suart_iomap.p_fifo_buff_virt_base =
                pdata->fifo_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) {
                        soft_uart->suart_iomap.p_fifo_buff_virt_base =
                        dma_alloc_coherent(&pdev->dev,
                        SUART_CNTX_SZ * NR_SUART * 2,
                        (dma_addr_t *) &soft_uart->suart_iomap.
                        p_fifo_buff_phys_base, GFP_KERNEL);
                        soft_uart->use_sram = false;
                        if (!soft_uart->suart_iomap.p_fifo_buff_virt_base)
                                goto probe_exit_iounmap;
                }
        } else {
                soft_uart->suart_iomap.p_fifo_buff_virt_base =
                dma_alloc_coherent(&pdev->dev,
                SUART_CNTX_SZ * NR_SUART * 2,
                (dma_addr_t *) &soft_uart->suart_iomap.
                p_fifo_buff_phys_base, GFP_KERNEL);
                if (!soft_uart->suart_iomap.p_fifo_buff_virt_base)
                        goto probe_exit_iounmap;
        }

I added the fifo_alloc into the suart_data of the board file.

static struct da850_evm_pruss_suart_data suart_data = {
        .version        = 1,
        .setup          = da850_evm_pruss_suart_setup,
        .fifo_alloc     = sram_alloc,
        .fifo_free      = sram_free,
};

Best Regards,
Subhasish Ghosh
 


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-20  7:14     ` Subhasish Ghosh
  0 siblings, 0 replies; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-20  7:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sekhar,

>> > ok, so what you are suggesting is that I implement some
>> > callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
>> > memory using sram_alloc.
>> > My doubt is, if already such API's are there (by Russel) or you
>> > are suggesting to implement them.
>>
>> I can add the fifo_alloc/dealloc as part of the suart platform_data,
>> Is that's what you are suggesting. If you may please point me out
>> to any example. I am just not clear with this.
>
> Yes, that's what I am suggesting. I don't have an exact example
> for you, but for an example of how function pointers can be passed
> along in platform data you can look at the platform data for
> DA8x FB driver in include/video/da8xx-fb.h.
>

Does this look ok.
This code snippet is in the driver file.

        if (soft_uart->use_sram) {
                soft_uart->suart_iomap.p_fifo_buff_virt_base =
                pdata->fifo_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) {
                        soft_uart->suart_iomap.p_fifo_buff_virt_base =
                        dma_alloc_coherent(&pdev->dev,
                        SUART_CNTX_SZ * NR_SUART * 2,
                        (dma_addr_t *) &soft_uart->suart_iomap.
                        p_fifo_buff_phys_base, GFP_KERNEL);
                        soft_uart->use_sram = false;
                        if (!soft_uart->suart_iomap.p_fifo_buff_virt_base)
                                goto probe_exit_iounmap;
                }
        } else {
                soft_uart->suart_iomap.p_fifo_buff_virt_base =
                dma_alloc_coherent(&pdev->dev,
                SUART_CNTX_SZ * NR_SUART * 2,
                (dma_addr_t *) &soft_uart->suart_iomap.
                p_fifo_buff_phys_base, GFP_KERNEL);
                if (!soft_uart->suart_iomap.p_fifo_buff_virt_base)
                        goto probe_exit_iounmap;
        }

I added the fifo_alloc into the suart_data of the board file.

static struct da850_evm_pruss_suart_data suart_data = {
        .version        = 1,
        .setup          = da850_evm_pruss_suart_setup,
        .fifo_alloc     = sram_alloc,
        .fifo_free      = sram_free,
};

Best Regards,
Subhasish Ghosh
 

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

* RE: [PATCH v4 08/11] tty: add pruss SUART driver
  2011-05-16  5:17 [PATCH v4 08/11] tty: add pruss SUART driver Subhasish Ghosh
@ 2011-05-17 18:32   ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-17 18:32 UTC (permalink / raw)
  To: Subhasish Ghosh
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

On Mon, May 16, 2011 at 10:47:18, Subhasish Ghosh wrote:
> Hi Sekhar,
> 
> >>> Say, if the driver is loaded as a module.
> >>> If I allocate the sram in the platform code, how to I
> >>> free it when the driver is unloaded. 
> >> 
> >> This is what I said in my last e-mail. What is
> >> the issue you see with this approach?
> >> 
> >> | Thanks for the clarification. In this case, the driver
> >> | should use platform callbacks to get/put fast fifo
> >> | space. In case this callback is not populated by the
> >> | platform or returns an error, the driver should fall
> >> | back to allocating from DDR.
> >> 
> > 
> > ok, so what you are suggesting is that I implement some
> > callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
> > memory using sram_alloc.
> > My doubt is, if already such API's are there (by Russel) or you
> > are suggesting to implement them.
> 
> I can add the fifo_alloc/dealloc as part of the suart platform_data,
> Is that's what you are suggesting. If you may please point me out 
> to any example. I am just not clear with this. 

Yes, that's what I am suggesting. I don't have an exact example
for you, but for an example of how function pointers can be passed
along in platform data you can look at the platform data for
DA8x FB driver in include/video/da8xx-fb.h.

Hope that helps.

Thanks,
Sekhar


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

* [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-17 18:32   ` Nori, Sekhar
  0 siblings, 0 replies; 166+ messages in thread
From: Nori, Sekhar @ 2011-05-17 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 16, 2011 at 10:47:18, Subhasish Ghosh wrote:
> Hi Sekhar,
> 
> >>> Say, if the driver is loaded as a module.
> >>> If I allocate the sram in the platform code, how to I
> >>> free it when the driver is unloaded. 
> >> 
> >> This is what I said in my last e-mail. What is
> >> the issue you see with this approach?
> >> 
> >> | Thanks for the clarification. In this case, the driver
> >> | should use platform callbacks to get/put fast fifo
> >> | space. In case this callback is not populated by the
> >> | platform or returns an error, the driver should fall
> >> | back to allocating from DDR.
> >> 
> > 
> > ok, so what you are suggesting is that I implement some
> > callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
> > memory using sram_alloc.
> > My doubt is, if already such API's are there (by Russel) or you
> > are suggesting to implement them.
> 
> I can add the fifo_alloc/dealloc as part of the suart platform_data,
> Is that's what you are suggesting. If you may please point me out 
> to any example. I am just not clear with this. 

Yes, that's what I am suggesting. I don't have an exact example
for you, but for an example of how function pointers can be passed
along in platform data you can look at the platform data for
DA8x FB driver in include/video/da8xx-fb.h.

Hope that helps.

Thanks,
Sekhar

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

* Re: [PATCH v4 08/11] tty: add pruss SUART driver
@ 2011-05-16  5:17 Subhasish Ghosh
  2011-05-17 18:32   ` Nori, Sekhar
  0 siblings, 1 reply; 166+ messages in thread
From: Subhasish Ghosh @ 2011-05-16  5:17 UTC (permalink / raw)
  To: Nori, Sekhar
  Cc: Greg KH, davinci-linux-open-source, linux-arm-kernel, Watkins,
	Melissa, sachi, Andrew Morton, Randy Dunlap, open list

Hi Sekhar,

>>> Say, if the driver is loaded as a module.
>>> If I allocate the sram in the platform code, how to I
>>> free it when the driver is unloaded. 
>> 
>> This is what I said in my last e-mail. What is
>> the issue you see with this approach?
>> 
>> | Thanks for the clarification. In this case, the driver
>> | should use platform callbacks to get/put fast fifo
>> | space. In case this callback is not populated by the
>> | platform or returns an error, the driver should fall
>> | back to allocating from DDR.
>> 
> 
> ok, so what you are suggesting is that I implement some
> callbacks (like .fifo_alloc, .fifo_dealloc) which can allocate
> memory using sram_alloc.
> My doubt is, if already such API's are there (by Russel) or you
> are suggesting to implement them.

I can add the fifo_alloc/dealloc as part of the suart platform_data,
Is that's what you are suggesting. If you may please point me out 
to any example. I am just not clear with this. 

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

end of thread, other threads:[~2011-05-30 15:28 UTC | newest]

Thread overview: 166+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-22 12:08 [PATCH v4 00/11] pruss mfd drivers Subhasish Ghosh
2011-04-22 11:50 ` [PATCH v4 08/11] tty: add pruss SUART driver Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-25 21:20   ` Greg KH
2011-04-25 21:20     ` Greg KH
2011-04-26  6:51     ` Nori, Sekhar
2011-04-26  6:51       ` Nori, Sekhar
2011-04-26 12:45       ` Greg KH
2011-04-26 12:45         ` Greg KH
2011-04-27  5:23         ` Subhasish Ghosh
2011-04-27  5:23           ` Subhasish Ghosh
2011-04-27 11:19           ` Nori, Sekhar
2011-04-27 11:19             ` Nori, Sekhar
2011-04-27 13:15             ` Subhasish Ghosh
2011-04-27 13:15               ` Subhasish Ghosh
2011-04-27 17:50               ` Nori, Sekhar
2011-04-27 17:50                 ` Nori, Sekhar
2011-05-02  8:34                 ` Subhasish Ghosh
2011-05-02  8:34                   ` Subhasish Ghosh
2011-05-02 17:15                   ` Nori, Sekhar
2011-05-02 17:15                     ` Nori, Sekhar
2011-05-10 10:54             ` Subhasish Ghosh
2011-05-10 10:54               ` Subhasish Ghosh
2011-05-10 13:13               ` Nori, Sekhar
2011-05-10 13:13                 ` Nori, Sekhar
2011-05-13 12:10                 ` Subhasish Ghosh
2011-05-13 12:10                   ` Subhasish Ghosh
2011-05-09 13:39   ` Subhasish Ghosh
2011-05-09 13:39     ` Subhasish Ghosh
2011-05-09 13:46     ` Alan Cox
2011-05-09 13:46       ` Alan Cox
2011-05-09 13:50       ` Subhasish Ghosh
2011-05-09 13:50         ` Subhasish Ghosh
2011-05-09 13:55         ` Alan Cox
2011-05-09 13:55           ` Alan Cox
2011-05-10  6:17           ` Subhasish Ghosh
2011-05-10  6:17             ` Subhasish Ghosh
2011-05-10 13:32             ` Alan Cox
2011-05-10 13:32               ` Alan Cox
2011-05-11  7:01               ` Subhasish Ghosh
2011-05-11  7:01                 ` Subhasish Ghosh
2011-05-11 10:35                 ` Alan Cox
2011-05-11 10:35                   ` Alan Cox
2011-04-22 12:08 ` [PATCH v4 01/11] mfd: add pruss mfd driver Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 16:00   ` Marc Kleine-Budde
2011-04-22 16:00     ` Marc Kleine-Budde
2011-04-27  6:39     ` Subhasish Ghosh
2011-04-27  6:39       ` Subhasish Ghosh
2011-04-27  7:29       ` Marc Kleine-Budde
2011-04-27  7:29         ` Marc Kleine-Budde
2011-04-27  9:12         ` Russell King - ARM Linux
2011-04-27  9:12           ` Russell King - ARM Linux
2011-04-27 13:18           ` Subhasish Ghosh
2011-04-27 13:18             ` Subhasish Ghosh
2011-04-27 13:35             ` Marc Kleine-Budde
2011-04-27 13:35               ` Marc Kleine-Budde
2011-04-28  7:22               ` Subhasish Ghosh
2011-04-28  7:22                 ` Subhasish Ghosh
2011-04-28  7:46                 ` Arnd Bergmann
2011-04-28  7:46                   ` Arnd Bergmann
2011-04-27 13:16   ` Arnd Bergmann
2011-04-27 13:16     ` Arnd Bergmann
2011-04-27 13:38     ` Subhasish Ghosh
2011-04-27 13:38       ` Subhasish Ghosh
2011-04-27 14:05       ` Arnd Bergmann
2011-04-27 14:05         ` Arnd Bergmann
2011-04-28  7:17         ` Subhasish Ghosh
2011-04-28  7:17           ` Subhasish Ghosh
2011-04-28  7:35           ` Arnd Bergmann
2011-04-28  7:35             ` Arnd Bergmann
2011-05-04  7:18             ` Subhasish Ghosh
2011-05-04  7:18               ` Subhasish Ghosh
2011-05-04 13:44               ` Arnd Bergmann
2011-05-04 13:44                 ` Arnd Bergmann
2011-05-04 14:38               ` Nori, Sekhar
2011-05-04 14:38                 ` Nori, Sekhar
2011-05-05 13:25                 ` Subhasish Ghosh
2011-05-05 13:25                   ` Subhasish Ghosh
2011-05-05 14:12                   ` Arnd Bergmann
2011-05-05 14:12                     ` Arnd Bergmann
2011-05-10  9:53                     ` Subhasish Ghosh
2011-05-10  9:53                       ` Subhasish Ghosh
2011-05-10 21:44                       ` Arnd Bergmann
2011-05-10 21:44                         ` Arnd Bergmann
2011-05-11  9:28                         ` Subhasish Ghosh
2011-05-11  9:28                           ` Subhasish Ghosh
2011-05-11 20:03                           ` Arnd Bergmann
2011-05-11 20:03                             ` Arnd Bergmann
2011-05-13 10:55                             ` Subhasish Ghosh
2011-05-13 10:55                               ` Subhasish Ghosh
2011-05-14 16:01                               ` Mark Brown
2011-05-14 16:01                                 ` Mark Brown
2011-05-14 20:33                                 ` Arnd Bergmann
2011-05-14 20:33                                   ` Arnd Bergmann
2011-05-14 22:14                                   ` Mark Brown
2011-05-14 22:14                                     ` Mark Brown
2011-05-15  9:33                                     ` Arnd Bergmann
2011-05-15  9:33                                       ` Arnd Bergmann
2011-05-16  6:06                                       ` Subhasish Ghosh
2011-05-16  6:06                                         ` Subhasish Ghosh
2011-05-23 15:30                                         ` Arnd Bergmann
2011-05-23 15:30                                           ` Arnd Bergmann
2011-05-24 12:17                                           ` Subhasish Ghosh
2011-05-24 12:17                                             ` Subhasish Ghosh
2011-05-24 12:40                                             ` Arnd Bergmann
2011-05-24 12:40                                               ` Arnd Bergmann
2011-05-24 13:43                                               ` Greg KH
2011-05-24 13:43                                                 ` Greg KH
2011-05-30 13:25                                                 ` Subhasish Ghosh
2011-05-30 13:25                                                   ` Subhasish Ghosh
2011-05-30 14:02                                                   ` Greg KH
2011-05-30 14:02                                                     ` Greg KH
2011-05-30 14:38                                                     ` Subhasish Ghosh
2011-05-30 14:38                                                       ` Subhasish Ghosh
2011-05-30 14:04                                                   ` Arnd Bergmann
2011-05-30 14:04                                                     ` Arnd Bergmann
2011-05-30 14:13                                                     ` Subhasish Ghosh
2011-05-30 14:13                                                       ` Subhasish Ghosh
2011-05-30 14:43                                                       ` Arnd Bergmann
2011-05-30 14:43                                                         ` Arnd Bergmann
2011-05-30 15:28                                                         ` Subhasish Ghosh
2011-05-30 15:28                                                           ` Subhasish Ghosh
2011-05-22 20:24                                   ` Samuel Ortiz
2011-05-22 20:24                                     ` Samuel Ortiz
2011-05-22 20:21                             ` Samuel Ortiz
2011-05-22 20:21                               ` Samuel Ortiz
2011-05-23 15:13                               ` Arnd Bergmann
2011-05-23 15:13                                 ` Arnd Bergmann
2011-04-22 12:08 ` [PATCH v4 02/11] da850: add pruss clock Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 03/11] da850: pruss platform specific additions Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-26 11:06   ` Sergei Shtylyov
2011-04-26 11:06     ` Sergei Shtylyov
2011-04-27  6:43     ` Subhasish Ghosh
2011-04-27  6:43       ` Subhasish Ghosh
2011-04-27 10:05       ` Sergei Shtylyov
2011-04-27 10:05         ` Sergei Shtylyov
2011-04-27 10:19         ` Subhasish Ghosh
2011-04-27 10:19           ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 04/11] da850: pruss board " Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 05/11] mfd: pruss SUART private data Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 06/11] da850: pruss SUART board specific additions Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 07/11] da850: pruss SUART platform " Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 09/11] mfd: pruss CAN private data Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 10/11] da850: pruss CAN platform specific additions Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 12:08 ` [PATCH v4 11/11] da850: pruss CAN board " Subhasish Ghosh
2011-04-22 12:08   ` Subhasish Ghosh
2011-04-22 16:03   ` Marc Kleine-Budde
2011-04-22 16:03     ` Marc Kleine-Budde
2011-04-26 10:57   ` Sergei Shtylyov
2011-04-26 10:57     ` Sergei Shtylyov
2011-04-27  7:03     ` Subhasish Ghosh
2011-04-27  7:03       ` Subhasish Ghosh
2011-05-16  5:17 [PATCH v4 08/11] tty: add pruss SUART driver Subhasish Ghosh
2011-05-17 18:32 ` Nori, Sekhar
2011-05-17 18:32   ` Nori, Sekhar
2011-05-20  7:14   ` Subhasish Ghosh
2011-05-20  7:14     ` Subhasish Ghosh

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.