Linux Serial subsystem development
 help / color / mirror / Atom feed
* [PATCH 1/2] serial: sh-sci: Fix probe error paths
From: Laurent Pinchart @ 2012-06-12 22:28 UTC (permalink / raw)
  To: Paul Mundt; +Cc: linux-serial, linux-sh

When probing fails, the driver must not try to cleanup resources that
have not been initialized. Fix this.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/tty/serial/sh-sci.c |   36 +++++++++++++++++++++++-------------
 1 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3158e17..a779663 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2140,6 +2140,16 @@ static int __devinit sci_init_single(struct platform_device *dev,
 	return 0;
 }
 
+static void sci_cleanup_single(struct sci_port *port)
+{
+	sci_free_gpios(port);
+
+	clk_put(port->iclk);
+	clk_put(port->fclk);
+
+	pm_runtime_disable(port->port.dev);
+}
+
 #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
 static void serial_console_putchar(struct uart_port *port, int ch)
 {
@@ -2321,14 +2331,10 @@ static int sci_remove(struct platform_device *dev)
 	cpufreq_unregister_notifier(&port->freq_transition,
 				    CPUFREQ_TRANSITION_NOTIFIER);
 
-	sci_free_gpios(port);
-
 	uart_remove_one_port(&sci_uart_driver, &port->port);
 
-	clk_put(port->iclk);
-	clk_put(port->fclk);
+	sci_cleanup_single(port);
 
-	pm_runtime_disable(&dev->dev);
 	return 0;
 }
 
@@ -2353,7 +2359,13 @@ static int __devinit sci_probe_single(struct platform_device *dev,
 	if (ret)
 		return ret;
 
-	return uart_add_one_port(&sci_uart_driver, &sciport->port);
+	ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
+	if (ret) {
+		sci_cleanup_single(sciport);
+		return ret;
+	}
+
+	return 0;
 }
 
 static int __devinit sci_probe(struct platform_device *dev)
@@ -2374,24 +2386,22 @@ static int __devinit sci_probe(struct platform_device *dev)
 
 	ret = sci_probe_single(dev, dev->id, p, sp);
 	if (ret)
-		goto err_unreg;
+		return ret;
 
 	sp->freq_transition.notifier_call = sci_notifier;
 
 	ret = cpufreq_register_notifier(&sp->freq_transition,
 					CPUFREQ_TRANSITION_NOTIFIER);
-	if (unlikely(ret < 0))
-		goto err_unreg;
+	if (unlikely(ret < 0)) {
+		sci_cleanup_single(sp);
+		return ret;
+	}
 
 #ifdef CONFIG_SH_STANDARD_BIOS
 	sh_bios_gdb_detach();
 #endif
 
 	return 0;
-
-err_unreg:
-	sci_remove(dev);
-	return ret;
 }
 
 static int sci_suspend(struct device *dev)
-- 
1.7.3.4


^ permalink raw reply related

* [PATCH 2/2] serial: sh-sci: Make probe fail for ports that exceed the maximum count
From: Laurent Pinchart @ 2012-06-12 22:28 UTC (permalink / raw)
  To: Paul Mundt; +Cc: linux-serial, linux-sh
In-Reply-To: <1339540104-25003-1-git-send-email-laurent.pinchart@ideasonboard.com>

The driver supports a maximum number of ports configurable at compile
time. Make sure the probe() method fails when registering a port that
exceeds the maximum instead of returning success without registering the
port.

This fixes a crash at system suspend time, when the driver tried to
suspend a non-registered port using the UART core.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/tty/serial/sh-sci.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index a779663..55dada3 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2352,7 +2352,7 @@ static int __devinit sci_probe_single(struct platform_device *dev,
 			   index+1, SCI_NPORTS);
 		dev_notice(&dev->dev, "Consider bumping "
 			   "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
-		return 0;
+		return -EINVAL;
 	}
 
 	ret = sci_init_single(dev, sciport, index, p);
-- 
1.7.3.4


^ permalink raw reply related

* Re: [PATCH] serial/amba-pl011: move custom pin control to driver
From: Linus Walleij @ 2012-06-12 18:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-serial, linux-arm-kernel, Lee Jones, Shawn Guo,
	Russell King
In-Reply-To: <1337800726-4076-1-git-send-email-linus.walleij@stericsson.com>

On Wed, May 23, 2012 at 9:18 PM, Linus Walleij
<linus.walleij@stericsson.com> wrote:

> From: Linus Walleij <linus.walleij@linaro.org>
>
> We had a boot regression in Ux500 in the merge window because
> two orthogonal pin control schemes for the PL011 were merged
> at the same time:
>
> - One using the .init() and .exit() hooks into the platform
>  for Ux500 putting the pins into default vs sleep state
>  respectively as the port was started/stopped.
>  commit a09806607fd20bed2f8c41fe22793386790a14aa
>  "ARM: ux500: switch to using pinctrl for uart0"
>
> - One hogging the default setting at PL011 probe()
>  commit 258e055111d3cde2607e0d04eb91da2f7a59b591
>  "serial: amba-pl011: adopt pinctrl support"
>
> To get a solution that works for both let's scrap the stuff
> in the platform callbacks, instead have the driver itself
> select default and sleep states when the port is
> started/stopped. Hopefully this works for all clients.
> Platform callbacks are bad for device tree migration anyway,
> so this rids us of another problem in Ux500.
>
> Cc: linux-serial@vger.kernel.org
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Russell King <rmk+kernel@arm.linux.org.uk>
> Reported-by: Lee Jones <lee.jones@linaro.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

A friendly poke at Greg to push this for the -rc series whenever
time permits (if OK) as it's regressing Ux500 for the moment.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH RESEND v2] serial: Add driver for LPC32xx High Speed UARTs
From: Roland Stigge @ 2012-06-11 20:04 UTC (permalink / raw)
  To: alan, gregkh, linux-serial, linux-kernel, kevin.wells,
	srinivas.bakki, linux-arm-kernel
  Cc: Roland Stigge

This patch adds a driver for the 3 High Speed UARTs of the LPC32xx SoC that
support up to 921600bps. These UARTs are different from the 4 "Standard" UARTs
of the LPC32xx.

Signed-off-by: Roland Stigge <stigge@antcom.de>

---
Applies to v3.5-rc2

Changes since v1:
* Remove reference to MAJOR/MINOR numbers, dynamically allocate now
* Removed tty_schedule_flip() for framing error case
* Added tty_flip_buffer_push() for rx
* Use tty_port_tty_get() and tty_kref_put() in case tty is NULL
* Updated commit description
* Fixed locking in interrupt handler
* Write baudrate change (set_termios) back to termios

Thanks to Alan Cox for reviewing!

 Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt |   14 
 drivers/tty/serial/Kconfig                                          |   19 
 drivers/tty/serial/Makefile                                         |    1 
 drivers/tty/serial/lpc32xx_hs.c                                     |  823 ++++++++++
 4 files changed, 857 insertions(+)

--- /dev/null
+++ linux-2.6/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
@@ -0,0 +1,14 @@
+* NXP LPC32xx SoC High Speed UART
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-hsuart"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Example:
+
+	uart1: serial@40014000 {
+		compatible = "nxp,lpc3220-hsuart";
+		reg = <0x40014000 0x1000>;
+		interrupts = <26 0>;
+	};
--- linux-2.6.orig/drivers/tty/serial/Kconfig
+++ linux-2.6/drivers/tty/serial/Kconfig
@@ -704,6 +704,25 @@ config SERIAL_PNX8XXX_CONSOLE
 	  If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
 	  and you want to use serial console, say Y. Otherwise, say N.
 
+config SERIAL_HS_LPC32XX
+	tristate "LPC32XX high speed serial port support"
+	depends on ARCH_LPC32XX && OF
+	select SERIAL_CORE
+	help
+	  Support for the LPC32XX high speed serial ports (up to 900kbps).
+	  Those are UARTs completely different from the Standard UARTs on the
+	  LPC32XX SoC.
+	  Choose M or Y here to build this driver.
+
+config SERIAL_HS_LPC32XX_CONSOLE
+	bool "Enable LPC32XX high speed UART serial console"
+	depends on SERIAL_HS_LPC32XX
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you would like to be able to use one of the high speed serial
+	  ports on the LPC32XX as the console, you can do so by answering
+	  Y to this option.
+
 config SERIAL_CORE
 	tristate
 
--- linux-2.6.orig/drivers/tty/serial/Makefile
+++ linux-2.6/drivers/tty/serial/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
--- /dev/null
+++ linux-2.6/drivers/tty/serial/lpc32xx_hs.c
@@ -0,0 +1,823 @@
+/*
+ * High Speed Serial Ports on NXP LPC32xx SoC
+ *
+ * Authors: Kevin Wells <kevin.wells@nxp.com>
+ *          Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/*
+ * High Speed UART register offsets
+ */
+#define LPC32XX_HSUART_FIFO(x)			((x) + 0x00)
+#define LPC32XX_HSUART_LEVEL(x)			((x) + 0x04)
+#define LPC32XX_HSUART_IIR(x)			((x) + 0x08)
+#define LPC32XX_HSUART_CTRL(x)			((x) + 0x0C)
+#define LPC32XX_HSUART_RATE(x)			((x) + 0x10)
+
+#define LPC32XX_HSU_BREAK_DATA			(1 << 10)
+#define LPC32XX_HSU_ERROR_DATA			(1 << 9)
+#define LPC32XX_HSU_RX_EMPTY			(1 << 8)
+
+#define LPC32XX_HSU_TX_LEV(n)			(((n) >> 8) & 0xFF)
+#define LPC32XX_HSU_RX_LEV(n)			((n) & 0xFF)
+
+#define LPC32XX_HSU_TX_INT_SET			(1 << 6)
+#define LPC32XX_HSU_RX_OE_INT			(1 << 5)
+#define LPC32XX_HSU_BRK_INT			(1 << 4)
+#define LPC32XX_HSU_FE_INT			(1 << 3)
+#define LPC32XX_HSU_RX_TIMEOUT_INT		(1 << 2)
+#define LPC32XX_HSU_RX_TRIG_INT			(1 << 1)
+#define LPC32XX_HSU_TX_INT			(1 << 0)
+
+#define LPC32XX_HSU_HRTS_INV			(1 << 21)
+#define LPC32XX_HSU_HRTS_TRIG_8B		(0x0 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_16B		(0x1 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_32B		(0x2 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_48B		(0x3 << 19)
+#define LPC32XX_HSU_HRTS_EN			(1 << 18)
+#define LPC32XX_HSU_TMO_DISABLED		(0x0 << 16)
+#define LPC32XX_HSU_TMO_INACT_4B		(0x1 << 16)
+#define LPC32XX_HSU_TMO_INACT_8B		(0x2 << 16)
+#define LPC32XX_HSU_TMO_INACT_16B		(0x3 << 16)
+#define LPC32XX_HSU_HCTS_INV			(1 << 15)
+#define LPC32XX_HSU_HCTS_EN			(1 << 14)
+#define LPC32XX_HSU_OFFSET(n)			((n) << 9)
+#define LPC32XX_HSU_BREAK			(1 << 8)
+#define LPC32XX_HSU_ERR_INT_EN			(1 << 7)
+#define LPC32XX_HSU_RX_INT_EN			(1 << 6)
+#define LPC32XX_HSU_TX_INT_EN			(1 << 5)
+#define LPC32XX_HSU_RX_TL1B			(0x0 << 2)
+#define LPC32XX_HSU_RX_TL4B			(0x1 << 2)
+#define LPC32XX_HSU_RX_TL8B			(0x2 << 2)
+#define LPC32XX_HSU_RX_TL16B			(0x3 << 2)
+#define LPC32XX_HSU_RX_TL32B			(0x4 << 2)
+#define LPC32XX_HSU_RX_TL48B			(0x5 << 2)
+#define LPC32XX_HSU_TX_TLEMPTY			(0x0 << 0)
+#define LPC32XX_HSU_TX_TL0B			(0x0 << 0)
+#define LPC32XX_HSU_TX_TL4B			(0x1 << 0)
+#define LPC32XX_HSU_TX_TL8B			(0x2 << 0)
+#define LPC32XX_HSU_TX_TL16B			(0x3 << 0)
+
+#define MODNAME "lpc32xx_hsuart"
+
+struct lpc32xx_hsuart_port {
+	struct uart_port port;
+};
+
+#define FIFO_READ_LIMIT 128
+#define MAX_PORTS 3
+#define LPC32XX_TTY_NAME "ttyTX"
+static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
+static void wait_for_xmit_empty(struct uart_port *port)
+{
+	unsigned int timeout = 10000;
+
+	do {
+		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+							port->membase))) == 0)
+			break;
+		if (--timeout == 0)
+			break;
+		udelay(1);
+	} while (1);
+}
+
+static void wait_for_xmit_ready(struct uart_port *port)
+{
+	unsigned int timeout = 10000;
+
+	while (1) {
+		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+							port->membase))) < 32)
+			break;
+		if (--timeout == 0)
+			break;
+		udelay(1);
+	}
+}
+
+static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
+{
+	wait_for_xmit_ready(port);
+	writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
+					 unsigned int count)
+{
+	struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
+	unsigned long flags;
+	int locked = 1;
+
+	touch_nmi_watchdog();
+	local_irq_save(flags);
+	if (up->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&up->port.lock);
+	else
+		spin_lock(&up->port.lock);
+
+	uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
+	wait_for_xmit_empty(&up->port);
+
+	if (locked)
+		spin_unlock(&up->port.lock);
+	local_irq_restore(flags);
+}
+
+static int __init lpc32xx_hsuart_console_setup(struct console *co,
+					       char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= MAX_PORTS)
+		co->index = 0;
+
+	port = &lpc32xx_hs_ports[co->index].port;
+	if (!port->membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lpc32xx_hsuart_reg;
+static struct console lpc32xx_hsuart_console = {
+	.name		= LPC32XX_TTY_NAME,
+	.write		= lpc32xx_hsuart_console_write,
+	.device		= uart_console_device,
+	.setup		= lpc32xx_hsuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &lpc32xx_hsuart_reg,
+};
+
+static int __init lpc32xx_hsuart_console_init(void)
+{
+	register_console(&lpc32xx_hsuart_console);
+	return 0;
+}
+console_initcall(lpc32xx_hsuart_console_init);
+
+#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
+#else
+#define LPC32XX_HSUART_CONSOLE NULL
+#endif
+
+static struct uart_driver lpc32xx_hs_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= MODNAME,
+	.dev_name	= LPC32XX_TTY_NAME,
+	.nr		= MAX_PORTS,
+	.cons		= LPC32XX_HSUART_CONSOLE,
+};
+static int uarts_registered;
+
+static unsigned int __serial_get_clock_div(unsigned long uartclk,
+					   unsigned long rate)
+{
+	u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
+	u32 rate_diff;
+
+	/* Find the closest divider to get the desired clock rate */
+	div = uartclk / rate;
+	goodrate = hsu_rate = (div / 14) - 1;
+	if (hsu_rate != 0)
+		hsu_rate--;
+
+	/* Tweak divider */
+	l_hsu_rate = hsu_rate + 3;
+	rate_diff = 0xFFFFFFFF;
+
+	while (hsu_rate < l_hsu_rate) {
+		comprate = uartclk / ((hsu_rate + 1) * 14);
+		if (abs(comprate - rate) < rate_diff) {
+			goodrate = hsu_rate;
+			rate_diff = abs(comprate - rate);
+		}
+
+		hsu_rate++;
+	}
+	if (hsu_rate > 0xFF)
+		hsu_rate = 0xFF;
+
+	return goodrate;
+}
+
+static void __serial_uart_flush(struct uart_port *port)
+{
+	u32 tmp;
+	int cnt = 0;
+
+	while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
+	       (cnt++ < FIFO_READ_LIMIT))
+		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void __serial_lpc32xx_rx(struct uart_port *port)
+{
+	unsigned int tmp, flag;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+	if (!tty) {
+		/* Discard data: no tty available */
+		while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
+			 LPC32XX_HSU_RX_EMPTY))
+			;
+
+		return;
+	}
+
+	/* Read data from FIFO and push into terminal */
+	tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+	while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (tmp & LPC32XX_HSU_ERROR_DATA) {
+			/* Framing error */
+			writel(LPC32XX_HSU_FE_INT,
+			       LPC32XX_HSUART_IIR(port->membase));
+			port->icount.frame++;
+			flag = TTY_FRAME;
+			tty_insert_flip_char(tty, 0, TTY_FRAME);
+		}
+
+		tty_insert_flip_char(tty, (tmp & 0xFF), flag);
+
+		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+	}
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static void __serial_lpc32xx_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned int tmp;
+
+	if (port->x_char) {
+		writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+		goto exit_tx;
+
+	/* Transfer data */
+	while (LPC32XX_HSU_TX_LEV(readl(
+		LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
+		writel((u32) xmit->buf[xmit->tail],
+		       LPC32XX_HSUART_FIFO(port->membase));
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+exit_tx:
+	if (uart_circ_empty(xmit)) {
+		tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+		tmp &= ~LPC32XX_HSU_TX_INT_EN;
+		writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+	}
+}
+
+static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+	u32 status;
+
+	spin_lock(&port->lock);
+
+	/* Read UART status and clear latched interrupts */
+	status = readl(LPC32XX_HSUART_IIR(port->membase));
+
+	if (status & LPC32XX_HSU_BRK_INT) {
+		/* Break received */
+		writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
+		port->icount.brk++;
+		uart_handle_break(port);
+	}
+
+	/* Framing error */
+	if (status & LPC32XX_HSU_FE_INT)
+		writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
+
+	if (status & LPC32XX_HSU_RX_OE_INT) {
+		/* Receive FIFO overrun */
+		writel(LPC32XX_HSU_RX_OE_INT,
+		       LPC32XX_HSUART_IIR(port->membase));
+		port->icount.overrun++;
+		if (tty) {
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+			tty_schedule_flip(tty);
+		}
+	}
+
+	/* Data received? */
+	if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+		__serial_lpc32xx_rx(port);
+		if (tty)
+			tty_flip_buffer_push(tty);
+	}
+
+	/* Transmit data request? */
+	if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
+		writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
+		__serial_lpc32xx_tx(port);
+	}
+
+	spin_unlock(&port->lock);
+	tty_kref_put(tty);
+
+	return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
+{
+	unsigned int ret = 0;
+
+	if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
+		ret = TIOCSER_TEMT;
+
+	return ret;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_set_mctrl(struct uart_port *port,
+				     unsigned int mctrl)
+{
+	/* No signals are supported on HS UARTs */
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
+{
+	/* No signals are supported on HS UARTs */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_tx(struct uart_port *port)
+{
+	u32 tmp;
+
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp &= ~LPC32XX_HSU_TX_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_start_tx(struct uart_port *port)
+{
+	u32 tmp;
+
+	__serial_lpc32xx_tx(port);
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp |= LPC32XX_HSU_TX_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_rx(struct uart_port *port)
+{
+	u32 tmp;
+
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
+		LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_enable_ms(struct uart_port *port)
+{
+	/* Modem status is not supported */
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_break_ctl(struct uart_port *port,
+				     int break_state)
+{
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&port->lock, flags);
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	if (break_state != 0)
+		tmp |= LPC32XX_HSU_BREAK;
+	else
+		tmp &= ~LPC32XX_HSU_BREAK;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state)
+{
+	int bit;
+	u32 tmp;
+
+	switch (mapbase) {
+	case LPC32XX_HS_UART1_BASE:
+		bit = 0;
+		break;
+	case LPC32XX_HS_UART2_BASE:
+		bit = 1;
+		break;
+	case LPC32XX_HS_UART7_BASE:
+		bit = 6;
+		break;
+	default:
+		WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
+		return;
+	}
+
+	tmp = readl(LPC32XX_UARTCTL_CLOOP);
+	if (state)
+		tmp |= (1 << bit);
+	else
+		tmp &= ~(1 << bit);
+	writel(tmp, LPC32XX_UARTCTL_CLOOP);
+}
+
+/* port->lock is not held.  */
+static int serial_lpc32xx_startup(struct uart_port *port)
+{
+	int retval;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	__serial_uart_flush(port);
+
+	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+	       LPC32XX_HSUART_IIR(port->membase));
+
+	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+	/*
+	 * Set receiver timeout, HSU offset of 20, no break, no interrupts,
+	 * and default FIFO trigger levels
+	 */
+	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	retval = request_irq(port->irq, serial_lpc32xx_interrupt,
+			     0, MODNAME, port);
+	if (!retval)
+		writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
+		       LPC32XX_HSUART_CTRL(port->membase));
+
+	return retval;
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_shutdown(struct uart_port *port)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	free_irq(port->irq, port);
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_set_termios(struct uart_port *port,
+				       struct ktermios *termios,
+				       struct ktermios *old)
+{
+	unsigned long flags;
+	unsigned int baud, quot;
+	u32 tmp;
+
+	/* Always 8-bit, no parity, 1 stop bit */
+	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+	termios->c_cflag |= CS8;
+
+	termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
+
+	baud = uart_get_baud_rate(port, termios, old, 0,
+				  port->uartclk / 14);
+
+	quot = __serial_get_clock_div(port->uartclk, baud);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Ignore characters? */
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	if ((termios->c_cflag & CREAD) == 0)
+		tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+	else
+		tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	writel(quot, LPC32XX_HSUART_RATE(port->membase));
+
+	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);
+}
+
+static const char *serial_lpc32xx_type(struct uart_port *port)
+{
+	return MODNAME;
+}
+
+static void serial_lpc32xx_release_port(struct uart_port *port)
+{
+	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+		if (port->flags & UPF_IOREMAP) {
+			iounmap(port->membase);
+			port->membase = NULL;
+		}
+
+		release_mem_region(port->mapbase, SZ_4K);
+	}
+}
+
+static int serial_lpc32xx_request_port(struct uart_port *port)
+{
+	int ret = -ENODEV;
+
+	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+		ret = 0;
+
+		if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
+			ret = -EBUSY;
+		else if (port->flags & UPF_IOREMAP) {
+			port->membase = ioremap(port->mapbase, SZ_4K);
+			if (!port->membase) {
+				release_mem_region(port->mapbase, SZ_4K);
+				ret = -ENOMEM;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
+{
+	int ret;
+
+	ret = serial_lpc32xx_request_port(port);
+	if (ret < 0)
+		return;
+	port->type = PORT_UART00;
+	port->fifosize = 64;
+
+	__serial_uart_flush(port);
+
+	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+	       LPC32XX_HSUART_IIR(port->membase));
+
+	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+	/* Set receiver timeout, HSU offset of 20, no break, no interrupts,
+	   and default FIFO trigger levels */
+	writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+	       LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
+	       LPC32XX_HSUART_CTRL(port->membase));
+}
+
+static int serial_lpc32xx_verify_port(struct uart_port *port,
+				      struct serial_struct *ser)
+{
+	int ret = 0;
+
+	if (ser->type != PORT_UART00)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static struct uart_ops serial_lpc32xx_pops = {
+	.tx_empty	= serial_lpc32xx_tx_empty,
+	.set_mctrl	= serial_lpc32xx_set_mctrl,
+	.get_mctrl	= serial_lpc32xx_get_mctrl,
+	.stop_tx	= serial_lpc32xx_stop_tx,
+	.start_tx	= serial_lpc32xx_start_tx,
+	.stop_rx	= serial_lpc32xx_stop_rx,
+	.enable_ms	= serial_lpc32xx_enable_ms,
+	.break_ctl	= serial_lpc32xx_break_ctl,
+	.startup	= serial_lpc32xx_startup,
+	.shutdown	= serial_lpc32xx_shutdown,
+	.set_termios	= serial_lpc32xx_set_termios,
+	.type		= serial_lpc32xx_type,
+	.release_port	= serial_lpc32xx_release_port,
+	.request_port	= serial_lpc32xx_request_port,
+	.config_port	= serial_lpc32xx_config_port,
+	.verify_port	= serial_lpc32xx_verify_port,
+};
+
+/*
+ * Register a set of serial devices attached to a platform device
+ */
+static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
+	int ret = 0;
+	struct resource *res;
+
+	if (uarts_registered >= MAX_PORTS) {
+		dev_err(&pdev->dev,
+			"Error: Number of possible ports exceeded (%d)!\n",
+			uarts_registered + 1);
+		return -ENXIO;
+	}
+
+	memset(p, 0, sizeof(*p));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Error getting mem resource for HS UART port %d\n",
+			uarts_registered);
+		return -ENXIO;
+	}
+	p->port.mapbase = res->start;
+	p->port.membase = NULL;
+
+	p->port.irq = platform_get_irq(pdev, 0);
+	if (p->port.irq < 0) {
+		dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
+			uarts_registered);
+		return p->port.irq;
+	}
+
+	p->port.iotype = UPIO_MEM32;
+	p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
+	p->port.regshift = 2;
+	p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+	p->port.dev = &pdev->dev;
+	p->port.ops = &serial_lpc32xx_pops;
+	p->port.line = uarts_registered++;
+	spin_lock_init(&p->port.lock);
+
+	/* send port to loopback mode by default */
+	lpc32xx_loopback_set(p->port.mapbase, 1);
+
+	ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
+
+	platform_set_drvdata(pdev, p);
+
+	return ret;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
+				     pm_message_t state)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_suspend_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+
+static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_resume_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+#else
+#define serial_hs_lpc32xx_suspend	NULL
+#define serial_hs_lpc32xx_resume	NULL
+#endif
+
+static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
+	{ .compatible = "nxp,lpc3220-hsuart" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
+
+static struct platform_driver serial_hs_lpc32xx_driver = {
+	.probe		= serial_hs_lpc32xx_probe,
+	.remove		= __devexit_p(serial_hs_lpc32xx_remove),
+	.suspend	= serial_hs_lpc32xx_suspend,
+	.resume		= serial_hs_lpc32xx_resume,
+	.driver		= {
+		.name	= MODNAME,
+		.owner	= THIS_MODULE,
+		.of_match_table	= serial_hs_lpc32xx_dt_ids,
+	},
+};
+
+static int __init lpc32xx_hsuart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&lpc32xx_hs_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&serial_hs_lpc32xx_driver);
+	if (ret)
+		uart_unregister_driver(&lpc32xx_hs_reg);
+
+	return ret;
+}
+
+static void __exit lpc32xx_hsuart_exit(void)
+{
+	platform_driver_unregister(&serial_hs_lpc32xx_driver);
+	uart_unregister_driver(&lpc32xx_hs_reg);
+}
+
+module_init(lpc32xx_hsuart_init);
+module_exit(lpc32xx_hsuart_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply

* [PATCH RESEND 1/2] serial/8250: Add LPC3220 standard UART type
From: Roland Stigge @ 2012-06-11 19:57 UTC (permalink / raw)
  To: alan, gregkh, linux-serial, linux-kernel, kevin.wells,
	srinivas.bakki, linux-arm-kernel, arnd, linux
  Cc: Roland Stigge

LPC32xx has "Standard" UARTs that are actually 16550A compatible but have
bigger FIFOs. Since the already supported 16X50 line still doesn't match here,
we agreed on adding a new type.

Signed-off-by: Roland Stigge <stigge@antcom.de>
Acked-by: Alan Cox <alan@linux.intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>

---
Applies to v3.5-rc2

 drivers/tty/serial/8250/8250.c |    8 ++++++++
 include/linux/serial_core.h    |    3 ++-
 2 files changed, 10 insertions(+), 1 deletion(-)

--- linux-2.6.orig/drivers/tty/serial/8250/8250.c
+++ linux-2.6/drivers/tty/serial/8250/8250.c
@@ -282,6 +282,14 @@ static const struct serial8250_config ua
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
 	},
+	[PORT_LPC3220] = {
+		.name		= "LPC3220",
+		.fifo_size	= 64,
+		.tx_loadsz	= 32,
+		.fcr		= UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO |
+				  UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
--- linux-2.6.orig/include/linux/serial_core.h
+++ linux-2.6/include/linux/serial_core.h
@@ -47,7 +47,8 @@
 #define PORT_U6_16550A	19	/* ST-Ericsson U6xxx internal UART */
 #define PORT_TEGRA	20	/* NVIDIA Tegra internal UART */
 #define PORT_XR17D15X	21	/* Exar XR17D15x UART */
-#define PORT_MAX_8250	21	/* max port ID */
+#define PORT_LPC3220	22	/* NXP LPC32xx SoC "Standard" UART */
+#define PORT_MAX_8250	22	/* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed

^ permalink raw reply

* [PATCH RESEND 2/2] serial/of-serial: Add LPC3220 standard UART compatible string
From: Roland Stigge @ 2012-06-11 19:57 UTC (permalink / raw)
  To: alan, gregkh, linux-serial, linux-kernel, kevin.wells,
	srinivas.bakki, linux-arm-kernel, arnd, linux
  Cc: Roland Stigge
In-Reply-To: <1339444634-15475-1-git-send-email-stigge@antcom.de>

This patch adds a "compatible" string for the new 8250 UART type PORT_LPC3220.
This is necessary for initializing LPC32xx UARTs via DT.

Signed-off-by: Roland Stigge <stigge@antcom.de>

---
Applies to v3.5-rc2

 Documentation/devicetree/bindings/tty/serial/of-serial.txt |    1 +
 drivers/tty/serial/of_serial.c                             |    1 +
 2 files changed, 2 insertions(+)

--- linux-2.6.orig/Documentation/devicetree/bindings/tty/serial/of-serial.txt
+++ linux-2.6/Documentation/devicetree/bindings/tty/serial/of-serial.txt
@@ -9,6 +9,7 @@ Required properties:
 	- "ns16750"
 	- "ns16850"
 	- "nvidia,tegra20-uart"
+	- "nxp,lpc3220-uart"
 	- "ibm,qpace-nwp-serial"
 	- "serial" if the port type is unknown.
 - reg : offset and length of the register set for the device.
--- linux-2.6.orig/drivers/tty/serial/of_serial.c
+++ linux-2.6/drivers/tty/serial/of_serial.c
@@ -208,6 +208,7 @@ static struct of_device_id __devinitdata
 	{ .compatible = "ns16750",  .data = (void *)PORT_16750, },
 	{ .compatible = "ns16850",  .data = (void *)PORT_16850, },
 	{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
+	{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
 #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
 	{ .compatible = "ibm,qpace-nwp-serial",
 		.data = (void *)PORT_NWPSERIAL, },

^ permalink raw reply

* Re: [PATCH V2 0/6] Bridging PCI to amba
From: Arnd Bergmann @ 2012-06-11 15:28 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alessandro Rubini, linux-kernel, Giancarlo Asnaghi, Alan Cox,
	Russell King, x86, Greg Kroah-Hartman, linux-arm-kernel,
	linux-serial, linux-arch
In-Reply-To: <CACRpkdbPtR5MDjd1YZ5GhOdp61HQe2PJusudNPOhDQHUAt1kJA@mail.gmail.com>

On Sunday 10 June 2012, Linus Walleij wrote:
> On Mon, May 28, 2012 at 6:36 PM, Alessandro Rubini <rubini@gnudd.com> wrote:
> 
> > V2: accepted comments I got on V1; rewritten the driver to be generic;
> >    made it tristate instead of boolean. Rebased on new next.
> 
> This looks good to me.
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> 
> I think this patch set could go through Arnd as arch maintainer?
> It's fun with these cross-arch things. You'll need an ACK from
> Russell first.

I don't think it has much to do with code I maintain. Russell
as the Primecell maintainer is the right person to take it through
his tree.

	Arnd

^ permalink raw reply

* Re: [PATCH 11/15] serial: mxs-auart: Use clk_prepare_enable/clk_disable_unprepare
From: Shawn Guo @ 2012-06-11  2:36 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: kernel, Fabio Estevam, Alan Cox, Greg Kroah-Hartman, linux-serial
In-Reply-To: <1337987696-31728-11-git-send-email-festevam@gmail.com>

On Fri, May 25, 2012 at 08:14:52PM -0300, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
> 
> Prepare the clock before enabling it.
> 
> Cc: Alan Cox <alan@linux.intel.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: <linux-serial@vger.kernel.org>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> ---
>  drivers/tty/serial/mxs-auart.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index ec56d83..c109642 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -552,7 +552,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
>  	s = auart_port[co->index];
>  	port = &s->port;
>  
> -	clk_enable(s->clk);
> +	clk_prepare_enable(s->clk);
>  
>  	/* First save the CR then disable the interrupts */
>  	old_ctrl2 = readl(port->membase + AUART_CTRL2);
> @@ -578,7 +578,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
>  	writel(old_ctrl0, port->membase + AUART_CTRL0);
>  	writel(old_ctrl2, port->membase + AUART_CTRL2);
>  
> -	clk_disable(s->clk);
> +	clk_disable_unprepare(s->clk);
>  }
>  
>  static void __init
> -- 
> 1.7.1
> 
No, clk_prepare() should not be called in auart_console_write() which
is an atomic context.  However it reminds me that auart_console_setup()
needs a fix as below.

Regards,
Shawn

--8<---

diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index ec56d83..a3bb06b 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -638,18 +638,16 @@ auart_console_setup(struct console *co, char *options)
        if (!s)
                return -ENODEV;

-       clk_prepare_enable(s->clk);
+       clk_prepare(s->clk);
+       if (ret)
+               return ret;

        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
        else
                auart_console_get_options(&s->port, &baud, &parity, &bits);

-       ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
-
-       clk_disable_unprepare(s->clk);
-
-       return ret;
+       return uart_set_options(&s->port, co, baud, parity, bits, flow);
 }

 static struct console auart_console = {



^ permalink raw reply related

* Re: [PATCH] serial/imx: enable the clock when we really use the uart port
From: Huang Shijie @ 2012-06-11  2:13 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Sascha Hauer, gregkh, shawn.guo, linux-arm-kernel, linux-serial,
	alan
In-Reply-To: <CAOMZO5DtC3yK7RgtbjefepQXk2jE+tODmivw+CC_hd5TCCe-oA@mail.gmail.com>

于 2012年06月11日 01:31, Fabio Estevam 写道:
> Huang,
>
> On Wed, May 2, 2012 at 5:19 AM, Sascha Hauer<s.hauer@pengutronix.de>  wrote:
>> On Wed, May 02, 2012 at 04:19:30PM +0800, Huang Shijie wrote:
>>> The current code keeps the clock enabled even when we do not really
>>> use the uart port. But keep the clock enabled will consume some power.
>>>
>>> In order to save more power, disable the clock when we do not use
>>> the uart, and enable the clock when we really use the uart port.
>>>
>>> Signed-off-by: Huang Shijie<b32955@freescale.com>
>> This conflicts with my series converting i.MX to the common clock
>> framework. Please lets delay this until this has been merged.
> I think it is OK to resubmit this patch now.
>
ok, thanks.

Huang Shijie

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] serial/imx: enable the clock when we really use the uart port
From: Fabio Estevam @ 2012-06-10 17:31 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Huang Shijie, gregkh, shawn.guo, linux-arm-kernel, linux-serial,
	alan
In-Reply-To: <20120502081902.GT4141@pengutronix.de>

Huang,

On Wed, May 2, 2012 at 5:19 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> On Wed, May 02, 2012 at 04:19:30PM +0800, Huang Shijie wrote:
>> The current code keeps the clock enabled even when we do not really
>> use the uart port. But keep the clock enabled will consume some power.
>>
>> In order to save more power, disable the clock when we do not use
>> the uart, and enable the clock when we really use the uart port.
>>
>> Signed-off-by: Huang Shijie <b32955@freescale.com>
>
> This conflicts with my series converting i.MX to the common clock
> framework. Please lets delay this until this has been merged.

I think it is OK to resubmit this patch now.

^ permalink raw reply

* Re: [PATCH V2 0/6] Bridging PCI to amba
From: Linus Walleij @ 2012-06-10 16:36 UTC (permalink / raw)
  To: Alessandro Rubini
  Cc: linux-arch, Giancarlo Asnaghi, Russell King, Arnd Bergmann,
	Greg Kroah-Hartman, x86, linux-kernel, linux-serial,
	linux-arm-kernel, Alan Cox
In-Reply-To: <cover.1338220457.git.rubini@gnudd.com>

On Mon, May 28, 2012 at 6:36 PM, Alessandro Rubini <rubini@gnudd.com> wrote:

> V2: accepted comments I got on V1; rewritten the driver to be generic;
>    made it tristate instead of boolean. Rebased on new next.

This looks good to me.
Acked-by: Linus Walleij <linus.walleij@linaro.org>

I think this patch set could go through Arnd as arch maintainer?
It's fun with these cross-arch things. You'll need an ACK from
Russell first.

Yours,
Linus Walleij

^ permalink raw reply

* [For..2-6]箳膃 [EndFor]...
From: Lashell Fouche @ 2012-06-10  2:58 UTC (permalink / raw)
  To: smbuchan@optonline.net

翑瑂靜靐醟 烒銗篝 亖鄎浆娺 楲樱蠳 暝 癮墀廎駑婃 瞱霔狠钥磘 抔峈拪 礡 搈 幓訪 裾俥礌殁覰 婽偌胜亱謇!
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] serial: fix kernel-doc warnings in 8250.c
From: Alan Cox @ 2012-06-09 10:59 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: LKML, linux-serial, Greg Kroah-Hartman
In-Reply-To: <4FD2AC1B.6070500@xenotime.net>

On Fri, 08 Jun 2012 18:51:23 -0700
Randy Dunlap <rdunlap@xenotime.net> wrote:

> From: Randy Dunlap <rdunlap@xenotime.net>
> 
> Fix kernel-doc warnings in drivers/tty/serial/8250/8250.c:
> 
> Warning(drivers/tty/serial/8250/8250.c:3128): No description found
> for parameter 'up' Warning(drivers/tty/serial/8250/8250.c:3128):
> Excess function parameter 'port' description in
> 'serial8250_register_8250_port'
> 
> Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>

Acked-by: Alan Cox <alan@linux.intel.com>

^ permalink raw reply

* [PATCH] serial: fix kernel-doc warnings in 8250.c
From: Randy Dunlap @ 2012-06-09  1:51 UTC (permalink / raw)
  To: LKML, linux-serial; +Cc: Alan Cox, Greg Kroah-Hartman

From: Randy Dunlap <rdunlap@xenotime.net>

Fix kernel-doc warnings in drivers/tty/serial/8250/8250.c:

Warning(drivers/tty/serial/8250/8250.c:3128): No description found for parameter 'up'
Warning(drivers/tty/serial/8250/8250.c:3128): Excess function parameter 'port' description in 'serial8250_register_8250_port'

Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
---
 drivers/tty/serial/8250/8250.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- lnx-35-rc1.orig/drivers/tty/serial/8250/8250.c
+++ lnx-35-rc1/drivers/tty/serial/8250/8250.c
@@ -3113,7 +3113,7 @@ static struct uart_8250_port *serial8250
 
 /**
  *	serial8250_register_8250_port - register a serial port
- *	@port: serial port template
+ *	@up: serial port template
  *
  *	Configure the serial port specified by the request. If the
  *	port exists and is in use, it is hung up and unregistered

^ permalink raw reply

* BUSINESS CO-OPERATION!
From: Mr Kirsten Nematandani @ 2012-06-08 14:34 UTC (permalink / raw)

In-Reply-To: <20120607163138.CF42D3F2@centrum.cz>


 
Hello!

My name is Mr Kirsten Nematandani, I'm the President of South African Football Association and we hosted 2010 world cup here in South Africa as you may be aware.
 
I’m consulting you for my personal investment plan which I would like to discuss with you and know the possibility of how we can co-operate and  work together to carry it out without jeopardizing my position, which I  believe will be beneficial to both parties if handled with honesty.
 
There is some fund I realized as a result of my position from the award  of contracts to prospective contractors building stadiums and other  projects which I would like to transfer abroad for investment purposes in your country. The total sum is USD $11 Million Dollars and it is securely deposited  abroad.
 
If you can assist me to receive the fund and further invest it for me in  any kind of profitable business in your country, kindly contact me (businessinvestment@contractor.net), in other for us to discuss on how to achieve this effectively.
 
As soon as  your reply, I will then call you and discuss with  you on further steps to be taken to achieve this. I'm willing to offer  you 20% of the total fund for your kind assistance.
 
Kindly include your full names, mobile/Office telephone numbers while replying to enable me give you a call as soon as I've received your e-mail.
 
Thanks as I await for your urgent and swift response.
 
Regards,
Mr Kirsten Nematandani.
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2] serial: Add driver for LPC32xx High Speed UARTs
From: Roland Stigge @ 2012-06-07 13:49 UTC (permalink / raw)
  To: alan, gregkh, linux-serial, linux-kernel, kevin.wells,
	srinivas.bakki, linux-arm-kernel
  Cc: Roland Stigge

This patch adds a driver for the 3 High Speed UARTs of the LPC32xx SoC that
support up to 921600bps. These UARTs are different from the 4 "Standard" UARTs
of the LPC32xx.

Signed-off-by: Roland Stigge <stigge@antcom.de>

---
Applies to v3.5-rc1

Changes since v1:
* Remove reference to MAJOR/MINOR numbers, dynamically allocate now
* Removed tty_schedule_flip() for framing error case
* Added tty_flip_buffer_push() for rx
* Use tty_port_tty_get() and tty_kref_put() in case tty is NULL
* Updated commit description
* Fixed locking in interrupt handler
* Write baudrate change (set_termios) back to termios

Thanks to Alan Cox for reviewing!

 Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt |   14 
 drivers/tty/serial/Kconfig                                          |   19 
 drivers/tty/serial/Makefile                                         |    1 
 drivers/tty/serial/lpc32xx_hs.c                                     |  823 ++++++++++
 4 files changed, 857 insertions(+)

--- /dev/null
+++ linux-2.6/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
@@ -0,0 +1,14 @@
+* NXP LPC32xx SoC High Speed UART
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-hsuart"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Example:
+
+	uart1: serial@40014000 {
+		compatible = "nxp,lpc3220-hsuart";
+		reg = <0x40014000 0x1000>;
+		interrupts = <26 0>;
+	};
--- linux-2.6.orig/drivers/tty/serial/Kconfig
+++ linux-2.6/drivers/tty/serial/Kconfig
@@ -704,6 +704,25 @@ config SERIAL_PNX8XXX_CONSOLE
 	  If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
 	  and you want to use serial console, say Y. Otherwise, say N.
 
+config SERIAL_HS_LPC32XX
+	tristate "LPC32XX high speed serial port support"
+	depends on ARCH_LPC32XX && OF
+	select SERIAL_CORE
+	help
+	  Support for the LPC32XX high speed serial ports (up to 900kbps).
+	  Those are UARTs completely different from the Standard UARTs on the
+	  LPC32XX SoC.
+	  Choose M or Y here to build this driver.
+
+config SERIAL_HS_LPC32XX_CONSOLE
+	bool "Enable LPC32XX high speed UART serial console"
+	depends on SERIAL_HS_LPC32XX
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you would like to be able to use one of the high speed serial
+	  ports on the LPC32XX as the console, you can do so by answering
+	  Y to this option.
+
 config SERIAL_CORE
 	tristate
 
--- linux-2.6.orig/drivers/tty/serial/Makefile
+++ linux-2.6/drivers/tty/serial/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
--- /dev/null
+++ linux-2.6/drivers/tty/serial/lpc32xx_hs.c
@@ -0,0 +1,823 @@
+/*
+ * High Speed Serial Ports on NXP LPC32xx SoC
+ *
+ * Authors: Kevin Wells <kevin.wells@nxp.com>
+ *          Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/*
+ * High Speed UART register offsets
+ */
+#define LPC32XX_HSUART_FIFO(x)			((x) + 0x00)
+#define LPC32XX_HSUART_LEVEL(x)			((x) + 0x04)
+#define LPC32XX_HSUART_IIR(x)			((x) + 0x08)
+#define LPC32XX_HSUART_CTRL(x)			((x) + 0x0C)
+#define LPC32XX_HSUART_RATE(x)			((x) + 0x10)
+
+#define LPC32XX_HSU_BREAK_DATA			(1 << 10)
+#define LPC32XX_HSU_ERROR_DATA			(1 << 9)
+#define LPC32XX_HSU_RX_EMPTY			(1 << 8)
+
+#define LPC32XX_HSU_TX_LEV(n)			(((n) >> 8) & 0xFF)
+#define LPC32XX_HSU_RX_LEV(n)			((n) & 0xFF)
+
+#define LPC32XX_HSU_TX_INT_SET			(1 << 6)
+#define LPC32XX_HSU_RX_OE_INT			(1 << 5)
+#define LPC32XX_HSU_BRK_INT			(1 << 4)
+#define LPC32XX_HSU_FE_INT			(1 << 3)
+#define LPC32XX_HSU_RX_TIMEOUT_INT		(1 << 2)
+#define LPC32XX_HSU_RX_TRIG_INT			(1 << 1)
+#define LPC32XX_HSU_TX_INT			(1 << 0)
+
+#define LPC32XX_HSU_HRTS_INV			(1 << 21)
+#define LPC32XX_HSU_HRTS_TRIG_8B		(0x0 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_16B		(0x1 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_32B		(0x2 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_48B		(0x3 << 19)
+#define LPC32XX_HSU_HRTS_EN			(1 << 18)
+#define LPC32XX_HSU_TMO_DISABLED		(0x0 << 16)
+#define LPC32XX_HSU_TMO_INACT_4B		(0x1 << 16)
+#define LPC32XX_HSU_TMO_INACT_8B		(0x2 << 16)
+#define LPC32XX_HSU_TMO_INACT_16B		(0x3 << 16)
+#define LPC32XX_HSU_HCTS_INV			(1 << 15)
+#define LPC32XX_HSU_HCTS_EN			(1 << 14)
+#define LPC32XX_HSU_OFFSET(n)			((n) << 9)
+#define LPC32XX_HSU_BREAK			(1 << 8)
+#define LPC32XX_HSU_ERR_INT_EN			(1 << 7)
+#define LPC32XX_HSU_RX_INT_EN			(1 << 6)
+#define LPC32XX_HSU_TX_INT_EN			(1 << 5)
+#define LPC32XX_HSU_RX_TL1B			(0x0 << 2)
+#define LPC32XX_HSU_RX_TL4B			(0x1 << 2)
+#define LPC32XX_HSU_RX_TL8B			(0x2 << 2)
+#define LPC32XX_HSU_RX_TL16B			(0x3 << 2)
+#define LPC32XX_HSU_RX_TL32B			(0x4 << 2)
+#define LPC32XX_HSU_RX_TL48B			(0x5 << 2)
+#define LPC32XX_HSU_TX_TLEMPTY			(0x0 << 0)
+#define LPC32XX_HSU_TX_TL0B			(0x0 << 0)
+#define LPC32XX_HSU_TX_TL4B			(0x1 << 0)
+#define LPC32XX_HSU_TX_TL8B			(0x2 << 0)
+#define LPC32XX_HSU_TX_TL16B			(0x3 << 0)
+
+#define MODNAME "lpc32xx_hsuart"
+
+struct lpc32xx_hsuart_port {
+	struct uart_port port;
+};
+
+#define FIFO_READ_LIMIT 128
+#define MAX_PORTS 3
+#define LPC32XX_TTY_NAME "ttyTX"
+static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
+static void wait_for_xmit_empty(struct uart_port *port)
+{
+	unsigned int timeout = 10000;
+
+	do {
+		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+							port->membase))) == 0)
+			break;
+		if (--timeout == 0)
+			break;
+		udelay(1);
+	} while (1);
+}
+
+static void wait_for_xmit_ready(struct uart_port *port)
+{
+	unsigned int timeout = 10000;
+
+	while (1) {
+		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+							port->membase))) < 32)
+			break;
+		if (--timeout == 0)
+			break;
+		udelay(1);
+	}
+}
+
+static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
+{
+	wait_for_xmit_ready(port);
+	writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
+					 unsigned int count)
+{
+	struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
+	unsigned long flags;
+	int locked = 1;
+
+	touch_nmi_watchdog();
+	local_irq_save(flags);
+	if (up->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&up->port.lock);
+	else
+		spin_lock(&up->port.lock);
+
+	uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
+	wait_for_xmit_empty(&up->port);
+
+	if (locked)
+		spin_unlock(&up->port.lock);
+	local_irq_restore(flags);
+}
+
+static int __init lpc32xx_hsuart_console_setup(struct console *co,
+					       char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= MAX_PORTS)
+		co->index = 0;
+
+	port = &lpc32xx_hs_ports[co->index].port;
+	if (!port->membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lpc32xx_hsuart_reg;
+static struct console lpc32xx_hsuart_console = {
+	.name		= LPC32XX_TTY_NAME,
+	.write		= lpc32xx_hsuart_console_write,
+	.device		= uart_console_device,
+	.setup		= lpc32xx_hsuart_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &lpc32xx_hsuart_reg,
+};
+
+static int __init lpc32xx_hsuart_console_init(void)
+{
+	register_console(&lpc32xx_hsuart_console);
+	return 0;
+}
+console_initcall(lpc32xx_hsuart_console_init);
+
+#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
+#else
+#define LPC32XX_HSUART_CONSOLE NULL
+#endif
+
+static struct uart_driver lpc32xx_hs_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= MODNAME,
+	.dev_name	= LPC32XX_TTY_NAME,
+	.nr		= MAX_PORTS,
+	.cons		= LPC32XX_HSUART_CONSOLE,
+};
+static int uarts_registered;
+
+static unsigned int __serial_get_clock_div(unsigned long uartclk,
+					   unsigned long rate)
+{
+	u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
+	u32 rate_diff;
+
+	/* Find the closest divider to get the desired clock rate */
+	div = uartclk / rate;
+	goodrate = hsu_rate = (div / 14) - 1;
+	if (hsu_rate != 0)
+		hsu_rate--;
+
+	/* Tweak divider */
+	l_hsu_rate = hsu_rate + 3;
+	rate_diff = 0xFFFFFFFF;
+
+	while (hsu_rate < l_hsu_rate) {
+		comprate = uartclk / ((hsu_rate + 1) * 14);
+		if (abs(comprate - rate) < rate_diff) {
+			goodrate = hsu_rate;
+			rate_diff = abs(comprate - rate);
+		}
+
+		hsu_rate++;
+	}
+	if (hsu_rate > 0xFF)
+		hsu_rate = 0xFF;
+
+	return goodrate;
+}
+
+static void __serial_uart_flush(struct uart_port *port)
+{
+	u32 tmp;
+	int cnt = 0;
+
+	while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
+	       (cnt++ < FIFO_READ_LIMIT))
+		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void __serial_lpc32xx_rx(struct uart_port *port)
+{
+	unsigned int tmp, flag;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+	if (!tty) {
+		/* Discard data: no tty available */
+		while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
+			 LPC32XX_HSU_RX_EMPTY))
+			;
+
+		return;
+	}
+
+	/* Read data from FIFO and push into terminal */
+	tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+	while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (tmp & LPC32XX_HSU_ERROR_DATA) {
+			/* Framing error */
+			writel(LPC32XX_HSU_FE_INT,
+			       LPC32XX_HSUART_IIR(port->membase));
+			port->icount.frame++;
+			flag = TTY_FRAME;
+			tty_insert_flip_char(tty, 0, TTY_FRAME);
+		}
+
+		tty_insert_flip_char(tty, (tmp & 0xFF), flag);
+
+		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+	}
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static void __serial_lpc32xx_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned int tmp;
+
+	if (port->x_char) {
+		writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+		goto exit_tx;
+
+	/* Transfer data */
+	while (LPC32XX_HSU_TX_LEV(readl(
+		LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
+		writel((u32) xmit->buf[xmit->tail],
+		       LPC32XX_HSUART_FIFO(port->membase));
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+exit_tx:
+	if (uart_circ_empty(xmit)) {
+		tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+		tmp &= ~LPC32XX_HSU_TX_INT_EN;
+		writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+	}
+}
+
+static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+	u32 status;
+
+	spin_lock(&port->lock);
+
+	/* Read UART status and clear latched interrupts */
+	status = readl(LPC32XX_HSUART_IIR(port->membase));
+
+	if (status & LPC32XX_HSU_BRK_INT) {
+		/* Break received */
+		writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
+		port->icount.brk++;
+		uart_handle_break(port);
+	}
+
+	/* Framing error */
+	if (status & LPC32XX_HSU_FE_INT)
+		writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
+
+	if (status & LPC32XX_HSU_RX_OE_INT) {
+		/* Receive FIFO overrun */
+		writel(LPC32XX_HSU_RX_OE_INT,
+		       LPC32XX_HSUART_IIR(port->membase));
+		port->icount.overrun++;
+		if (tty) {
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+			tty_schedule_flip(tty);
+		}
+	}
+
+	/* Data received? */
+	if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+		__serial_lpc32xx_rx(port);
+		if (tty)
+			tty_flip_buffer_push(tty);
+	}
+
+	/* Transmit data request? */
+	if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
+		writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
+		__serial_lpc32xx_tx(port);
+	}
+
+	spin_unlock(&port->lock);
+	tty_kref_put(tty);
+
+	return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
+{
+	unsigned int ret = 0;
+
+	if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
+		ret = TIOCSER_TEMT;
+
+	return ret;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_set_mctrl(struct uart_port *port,
+				     unsigned int mctrl)
+{
+	/* No signals are supported on HS UARTs */
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
+{
+	/* No signals are supported on HS UARTs */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_tx(struct uart_port *port)
+{
+	u32 tmp;
+
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp &= ~LPC32XX_HSU_TX_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_start_tx(struct uart_port *port)
+{
+	u32 tmp;
+
+	__serial_lpc32xx_tx(port);
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp |= LPC32XX_HSU_TX_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_rx(struct uart_port *port)
+{
+	u32 tmp;
+
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
+		LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_enable_ms(struct uart_port *port)
+{
+	/* Modem status is not supported */
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_break_ctl(struct uart_port *port,
+				     int break_state)
+{
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&port->lock, flags);
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	if (break_state != 0)
+		tmp |= LPC32XX_HSU_BREAK;
+	else
+		tmp &= ~LPC32XX_HSU_BREAK;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state)
+{
+	int bit;
+	u32 tmp;
+
+	switch (mapbase) {
+	case LPC32XX_HS_UART1_BASE:
+		bit = 0;
+		break;
+	case LPC32XX_HS_UART2_BASE:
+		bit = 1;
+		break;
+	case LPC32XX_HS_UART7_BASE:
+		bit = 6;
+		break;
+	default:
+		WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
+		return;
+	}
+
+	tmp = readl(LPC32XX_UARTCTL_CLOOP);
+	if (state)
+		tmp |= (1 << bit);
+	else
+		tmp &= ~(1 << bit);
+	writel(tmp, LPC32XX_UARTCTL_CLOOP);
+}
+
+/* port->lock is not held.  */
+static int serial_lpc32xx_startup(struct uart_port *port)
+{
+	int retval;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	__serial_uart_flush(port);
+
+	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+	       LPC32XX_HSUART_IIR(port->membase));
+
+	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+	/*
+	 * Set receiver timeout, HSU offset of 20, no break, no interrupts,
+	 * and default FIFO trigger levels
+	 */
+	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	retval = request_irq(port->irq, serial_lpc32xx_interrupt,
+			     0, MODNAME, port);
+	if (!retval)
+		writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
+		       LPC32XX_HSUART_CTRL(port->membase));
+
+	return retval;
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_shutdown(struct uart_port *port)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	free_irq(port->irq, port);
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_set_termios(struct uart_port *port,
+				       struct ktermios *termios,
+				       struct ktermios *old)
+{
+	unsigned long flags;
+	unsigned int baud, quot;
+	u32 tmp;
+
+	/* Always 8-bit, no parity, 1 stop bit */
+	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+	termios->c_cflag |= CS8;
+
+	termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
+
+	baud = uart_get_baud_rate(port, termios, old, 0,
+				  port->uartclk / 14);
+
+	quot = __serial_get_clock_div(port->uartclk, baud);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Ignore characters? */
+	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+	if ((termios->c_cflag & CREAD) == 0)
+		tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+	else
+		tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
+	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+	writel(quot, LPC32XX_HSUART_RATE(port->membase));
+
+	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);
+}
+
+static const char *serial_lpc32xx_type(struct uart_port *port)
+{
+	return MODNAME;
+}
+
+static void serial_lpc32xx_release_port(struct uart_port *port)
+{
+	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+		if (port->flags & UPF_IOREMAP) {
+			iounmap(port->membase);
+			port->membase = NULL;
+		}
+
+		release_mem_region(port->mapbase, SZ_4K);
+	}
+}
+
+static int serial_lpc32xx_request_port(struct uart_port *port)
+{
+	int ret = -ENODEV;
+
+	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+		ret = 0;
+
+		if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
+			ret = -EBUSY;
+		else if (port->flags & UPF_IOREMAP) {
+			port->membase = ioremap(port->mapbase, SZ_4K);
+			if (!port->membase) {
+				release_mem_region(port->mapbase, SZ_4K);
+				ret = -ENOMEM;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
+{
+	int ret;
+
+	ret = serial_lpc32xx_request_port(port);
+	if (ret < 0)
+		return;
+	port->type = PORT_UART00;
+	port->fifosize = 64;
+
+	__serial_uart_flush(port);
+
+	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+	       LPC32XX_HSUART_IIR(port->membase));
+
+	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+	/* Set receiver timeout, HSU offset of 20, no break, no interrupts,
+	   and default FIFO trigger levels */
+	writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+	       LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
+	       LPC32XX_HSUART_CTRL(port->membase));
+}
+
+static int serial_lpc32xx_verify_port(struct uart_port *port,
+				      struct serial_struct *ser)
+{
+	int ret = 0;
+
+	if (ser->type != PORT_UART00)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static struct uart_ops serial_lpc32xx_pops = {
+	.tx_empty	= serial_lpc32xx_tx_empty,
+	.set_mctrl	= serial_lpc32xx_set_mctrl,
+	.get_mctrl	= serial_lpc32xx_get_mctrl,
+	.stop_tx	= serial_lpc32xx_stop_tx,
+	.start_tx	= serial_lpc32xx_start_tx,
+	.stop_rx	= serial_lpc32xx_stop_rx,
+	.enable_ms	= serial_lpc32xx_enable_ms,
+	.break_ctl	= serial_lpc32xx_break_ctl,
+	.startup	= serial_lpc32xx_startup,
+	.shutdown	= serial_lpc32xx_shutdown,
+	.set_termios	= serial_lpc32xx_set_termios,
+	.type		= serial_lpc32xx_type,
+	.release_port	= serial_lpc32xx_release_port,
+	.request_port	= serial_lpc32xx_request_port,
+	.config_port	= serial_lpc32xx_config_port,
+	.verify_port	= serial_lpc32xx_verify_port,
+};
+
+/*
+ * Register a set of serial devices attached to a platform device
+ */
+static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
+	int ret = 0;
+	struct resource *res;
+
+	if (uarts_registered >= MAX_PORTS) {
+		dev_err(&pdev->dev,
+			"Error: Number of possible ports exceeded (%d)!\n",
+			uarts_registered + 1);
+		return -ENXIO;
+	}
+
+	memset(p, 0, sizeof(*p));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Error getting mem resource for HS UART port %d\n",
+			uarts_registered);
+		return -ENXIO;
+	}
+	p->port.mapbase = res->start;
+	p->port.membase = NULL;
+
+	p->port.irq = platform_get_irq(pdev, 0);
+	if (p->port.irq < 0) {
+		dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
+			uarts_registered);
+		return p->port.irq;
+	}
+
+	p->port.iotype = UPIO_MEM32;
+	p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
+	p->port.regshift = 2;
+	p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+	p->port.dev = &pdev->dev;
+	p->port.ops = &serial_lpc32xx_pops;
+	p->port.line = uarts_registered++;
+	spin_lock_init(&p->port.lock);
+
+	/* send port to loopback mode by default */
+	lpc32xx_loopback_set(p->port.mapbase, 1);
+
+	ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
+
+	platform_set_drvdata(pdev, p);
+
+	return ret;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
+				     pm_message_t state)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_suspend_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+
+static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
+{
+	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+	uart_resume_port(&lpc32xx_hs_reg, &p->port);
+
+	return 0;
+}
+#else
+#define serial_hs_lpc32xx_suspend	NULL
+#define serial_hs_lpc32xx_resume	NULL
+#endif
+
+static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
+	{ .compatible = "nxp,lpc3220-hsuart" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
+
+static struct platform_driver serial_hs_lpc32xx_driver = {
+	.probe		= serial_hs_lpc32xx_probe,
+	.remove		= __devexit_p(serial_hs_lpc32xx_remove),
+	.suspend	= serial_hs_lpc32xx_suspend,
+	.resume		= serial_hs_lpc32xx_resume,
+	.driver		= {
+		.name	= MODNAME,
+		.owner	= THIS_MODULE,
+		.of_match_table	= serial_hs_lpc32xx_dt_ids,
+	},
+};
+
+static int __init lpc32xx_hsuart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&lpc32xx_hs_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&serial_hs_lpc32xx_driver);
+	if (ret)
+		uart_unregister_driver(&lpc32xx_hs_reg);
+
+	return ret;
+}
+
+static void __exit lpc32xx_hsuart_exit(void)
+{
+	platform_driver_unregister(&serial_hs_lpc32xx_driver);
+	uart_unregister_driver(&lpc32xx_hs_reg);
+}
+
+module_init(lpc32xx_hsuart_init);
+module_exit(lpc32xx_hsuart_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply

* Re: [PATCH 1/1] serial_core: Update buffer overrun statistics.
From: Alan Cox @ 2012-06-06 22:50 UTC (permalink / raw)
  To: Corbin
  Cc: Jiri Slaby, Jason Smith, Alan Cox, Corbin Atkinson,
	Greg Kroah-Hartman, linux-serial
In-Reply-To: <CAA0x6__yZNkaTgTkGLdESwSHcUwAfcKsQEoZU=gfNwASAYDPUA@mail.gmail.com>

On Wed, 6 Jun 2012 17:34:45 -0500
Corbin <corbinat@gmail.com> wrote:

> Has anyone been able to give this any more thought? If no one has any
> objection I would still like to see this get added.

Nobody seems to care too much so I'm ok on that basis.

^ permalink raw reply

* Re: [PATCH 1/1] serial_core: Update buffer overrun statistics.
From: Corbin @ 2012-06-06 22:34 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Jason Smith, Alan Cox, Corbin Atkinson, Greg Kroah-Hartman,
	linux-serial
In-Reply-To: <CAA0x6_-aq2CZzz1dU7Re-GwyW2jeE-frCC38mHY6o4AG6vrvMw@mail.gmail.com>

Has anyone been able to give this any more thought? If no one has any
objection I would still like to see this get added.

Thanks,
Corbin

^ permalink raw reply

* Re: [RFC PATCH] pch_uart: Add eg20t_port lock field, avoid recursive spinlocks
From: Tomoya MORINAGA @ 2012-06-05 23:48 UTC (permalink / raw)
  To: Darren Hart
  Cc: Linux Kernel Mailing List, Feng Tang, Alexander Stein,
	Greg Kroah-Hartman, Alan Cox, linux-serial
In-Reply-To: <4FCE8307.3050901@linux.intel.com>

On Wed, Jun 6, 2012 at 7:07 AM, Darren Hart <dvhart@linux.intel.com> wrote:
> Are there still concerns about the additional lock? I'll resend V2
> tomorrow with the single whitespace fix if I don't hear anything back today.

I understand your saying. Looks good.
However, I am not expert of linux-uart core system.
So, I'd like UART maintainer to give us your opinion.

thanks.
tomoya

^ permalink raw reply

* Re: [RFC PATCH] pch_uart: Add eg20t_port lock field, avoid recursive spinlocks
From: Darren Hart @ 2012-06-05 22:07 UTC (permalink / raw)
  To: Tomoya MORINAGA
  Cc: Linux Kernel Mailing List, Feng Tang, Alexander Stein,
	Greg Kroah-Hartman, Alan Cox, linux-serial
In-Reply-To: <4FC90BAD.3080606@linux.intel.com>



On 06/01/2012 11:36 AM, Darren Hart wrote:
> 
> 
> On 06/01/2012 01:30 AM, Tomoya MORINAGA wrote:
>> On Thu, May 31, 2012 at 5:54 PM, Darren Hart <dvhart@linux.intel.com> wrote:
>>> @@ -1376,7 +1379,8 @@ static void pch_uart_set_termios(struct uart_port *port,
>>>
>>>        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>>
>>> -       spin_lock_irqsave(&port->lock, flags);
>>> +       spin_lock_irqsave(&priv->lock, flags);
>>> +       spin_lock(&port->lock);
>>>
>>>        uart_update_timeout(port, termios->c_cflag, baud);
>>>        rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
>>> @@ -1389,7 +1393,8 @@ static void pch_uart_set_termios(struct uart_port *port,
>>>                tty_termios_encode_baud_rate(termios, baud, baud);
>>>
>>>  out:
>>> -       spin_unlock_irqrestore(&port->lock, flags);
>>> +       spin_unlock(&port->lock);
>>> +       spin_unlock_irqrestore(&priv->lock, flags);
>>>  }
>>
>> Are both port->lock and priv->lock really necessary ?
> 
> The priv lock protects the pch_uart_hal* calls and the io access.
> 
> The port lock protects the uart_update_timeout call. I'm assuming the
> 8250.c driver is correct in holding the port lock before making this
> call and making other modifcations to the port struct.
> 
> So yes, I believe both are required. The port->lock was used as the lock
> to protect the private data in the interrupt handler,
> pch_uart_interrupt. If we could avoid holding that lock across the
> entire function, limiting it to just around the pch_uart_hal calls
> (perhaps by adding it to the hal calls and adding lockless __pch_uart*
> calls) we could avoid the recursive lock that occurs with handle_rx. I
> still think a priv-lock is a good idea though, even if just to clarify
> what is being protected.
> 
> Thoughts?

Are there still concerns about the additional lock? I'll resend V2
tomorrow with the single whitespace fix if I don't hear anything back today.

Thanks,

Darren

> 
>>
>>
>>> @@ -1572,7 +1578,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
>>>
>>>        if (locked)
>>>                spin_unlock(&priv->port.lock);
>>> +       spin_unlock(&priv->lock);
>>>        local_irq_restore(flags);
>>> +
>>>  }
>>
>> Looks spare blank line.
> 
> Thanks, will fix for V2 after this discussion wraps up.
> 
>>
>> thanks.
> 

-- 
Darren Hart
Intel Open Source Technology Center
Yocto Project - Linux Kernel

^ permalink raw reply

* serial: fix serial_txx9.c build warning/typo
From: Randy Dunlap @ 2012-06-05 16:46 UTC (permalink / raw)
  To: LKML, linux-serial; +Cc: Alan Cox, Greg Kroah-Hartman, Geert Uytterhoeven

From: Randy Dunlap <rdunlap@xenotime.net>

Fix kconfig symbol test to use "defined":

drivers/tty/serial/serial_txx9.c: warning: "CONFIG_CONSOLE_POLL" is not defined [-Wundef]

Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
---
 drivers/tty/serial/serial_txx9.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- lnx-35-rc1.orig/drivers/tty/serial/serial_txx9.c
+++ lnx-35-rc1/drivers/tty/serial/serial_txx9.c
@@ -466,7 +466,7 @@ static void serial_txx9_break_ctl(struct
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
-#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
 /*
  *	Wait for transmitter & holding register to empty
  */

^ permalink raw reply

* [PATCH RESEND 1/2] serial/8250: Add LPC3220 standard UART type
From: Roland Stigge @ 2012-06-04 19:02 UTC (permalink / raw)
  To: alan, gregkh, linux-serial, linux-kernel, kevin.wells,
	srinivas.bakki, linux-arm-kernel, arnd, linux
  Cc: Roland Stigge

LPC32xx has "Standard" UARTs that are actually 16550A compatible but have
bigger FIFOs. Since the already supported 16X50 line still doesn't match here,
we agreed on adding a new type.

Signed-off-by: Roland Stigge <stigge@antcom.de>
Acked-by: Alan Cox <alan@linux.intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>

---
Applies to v3.5-rc1

 drivers/tty/serial/8250/8250.c |    8 ++++++++
 include/linux/serial_core.h    |    3 ++-
 2 files changed, 10 insertions(+), 1 deletion(-)

--- linux-2.6.orig/drivers/tty/serial/8250/8250.c
+++ linux-2.6/drivers/tty/serial/8250/8250.c
@@ -282,6 +282,14 @@ static const struct serial8250_config ua
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
 	},
+	[PORT_LPC3220] = {
+		.name		= "LPC3220",
+		.fifo_size	= 64,
+		.tx_loadsz	= 32,
+		.fcr		= UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO |
+				  UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
--- linux-2.6.orig/include/linux/serial_core.h
+++ linux-2.6/include/linux/serial_core.h
@@ -47,7 +47,8 @@
 #define PORT_U6_16550A	19	/* ST-Ericsson U6xxx internal UART */
 #define PORT_TEGRA	20	/* NVIDIA Tegra internal UART */
 #define PORT_XR17D15X	21	/* Exar XR17D15x UART */
-#define PORT_MAX_8250	21	/* max port ID */
+#define PORT_LPC3220	22	/* NXP LPC32xx SoC "Standard" UART */
+#define PORT_MAX_8250	22	/* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed

^ permalink raw reply

* [PATCH RESEND 2/2] serial/of-serial: Add LPC3220 standard UART compatible string
From: Roland Stigge @ 2012-06-04 19:02 UTC (permalink / raw)
  To: alan, gregkh, linux-serial, linux-kernel, kevin.wells,
	srinivas.bakki, linux-arm-kernel, arnd, linux
  Cc: Roland Stigge
In-Reply-To: <1338836575-21738-1-git-send-email-stigge@antcom.de>

This patch adds a "compatible" string for the new 8250 UART type PORT_LPC3220.
This is a precondition for initializing LPC32xx UARTs via DT.

Signed-off-by: Roland Stigge <stigge@antcom.de>

---
Applies to v3.5-rc1

 Documentation/devicetree/bindings/tty/serial/of-serial.txt |    1 +
 drivers/tty/serial/of_serial.c                             |    1 +
 2 files changed, 2 insertions(+)

--- linux-2.6.orig/Documentation/devicetree/bindings/tty/serial/of-serial.txt
+++ linux-2.6/Documentation/devicetree/bindings/tty/serial/of-serial.txt
@@ -9,6 +9,7 @@ Required properties:
 	- "ns16750"
 	- "ns16850"
 	- "nvidia,tegra20-uart"
+	- "nxp,lpc3220-uart"
 	- "ibm,qpace-nwp-serial"
 	- "serial" if the port type is unknown.
 - reg : offset and length of the register set for the device.
--- linux-2.6.orig/drivers/tty/serial/of_serial.c
+++ linux-2.6/drivers/tty/serial/of_serial.c
@@ -208,6 +208,7 @@ static struct of_device_id __devinitdata
 	{ .compatible = "ns16750",  .data = (void *)PORT_16750, },
 	{ .compatible = "ns16850",  .data = (void *)PORT_16850, },
 	{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
+	{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
 #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
 	{ .compatible = "ibm,qpace-nwp-serial",
 		.data = (void *)PORT_NWPSERIAL, },

^ permalink raw reply

* Re: [RFC PATCH] pch_uart: Add eg20t_port lock field, avoid recursive spinlocks
From: Darren Hart @ 2012-06-01 18:36 UTC (permalink / raw)
  To: Tomoya MORINAGA
  Cc: Linux Kernel Mailing List, Feng Tang, Alexander Stein,
	Greg Kroah-Hartman, Alan Cox, linux-serial
In-Reply-To: <CANKRQnhZErpvcsRW3ukNzY0_zv4x=5OzQ-sr+aeuxL63=tQ=4A@mail.gmail.com>



On 06/01/2012 01:30 AM, Tomoya MORINAGA wrote:
> On Thu, May 31, 2012 at 5:54 PM, Darren Hart <dvhart@linux.intel.com> wrote:
>> @@ -1376,7 +1379,8 @@ static void pch_uart_set_termios(struct uart_port *port,
>>
>>        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>>
>> -       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&priv->lock, flags);
>> +       spin_lock(&port->lock);
>>
>>        uart_update_timeout(port, termios->c_cflag, baud);
>>        rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
>> @@ -1389,7 +1393,8 @@ static void pch_uart_set_termios(struct uart_port *port,
>>                tty_termios_encode_baud_rate(termios, baud, baud);
>>
>>  out:
>> -       spin_unlock_irqrestore(&port->lock, flags);
>> +       spin_unlock(&port->lock);
>> +       spin_unlock_irqrestore(&priv->lock, flags);
>>  }
> 
> Are both port->lock and priv->lock really necessary ?

The priv lock protects the pch_uart_hal* calls and the io access.

The port lock protects the uart_update_timeout call. I'm assuming the
8250.c driver is correct in holding the port lock before making this
call and making other modifcations to the port struct.

So yes, I believe both are required. The port->lock was used as the lock
to protect the private data in the interrupt handler,
pch_uart_interrupt. If we could avoid holding that lock across the
entire function, limiting it to just around the pch_uart_hal calls
(perhaps by adding it to the hal calls and adding lockless __pch_uart*
calls) we could avoid the recursive lock that occurs with handle_rx. I
still think a priv-lock is a good idea though, even if just to clarify
what is being protected.

Thoughts?

> 
> 
>> @@ -1572,7 +1578,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
>>
>>        if (locked)
>>                spin_unlock(&priv->port.lock);
>> +       spin_unlock(&priv->lock);
>>        local_irq_restore(flags);
>> +
>>  }
> 
> Looks spare blank line.

Thanks, will fix for V2 after this discussion wraps up.

> 
> thanks.

-- 
Darren Hart
Intel Open Source Technology Center
Yocto Project - Linux Kernel

^ permalink raw reply

* Re: [RFC PATCH] pch_uart: Add eg20t_port lock field, avoid recursive spinlocks
From: Tomoya MORINAGA @ 2012-06-01  8:30 UTC (permalink / raw)
  To: Darren Hart
  Cc: Linux Kernel Mailing List, Feng Tang, Alexander Stein,
	Greg Kroah-Hartman, Alan Cox, linux-serial
In-Reply-To: <8854635ac5471f8671b93c65e3663eb1cb204c9d.1338454156.git.dvhart@linux.intel.com>

On Thu, May 31, 2012 at 5:54 PM, Darren Hart <dvhart@linux.intel.com> wrote:
> @@ -1376,7 +1379,8 @@ static void pch_uart_set_termios(struct uart_port *port,
>
>        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
>
> -       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&priv->lock, flags);
> +       spin_lock(&port->lock);
>
>        uart_update_timeout(port, termios->c_cflag, baud);
>        rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
> @@ -1389,7 +1393,8 @@ static void pch_uart_set_termios(struct uart_port *port,
>                tty_termios_encode_baud_rate(termios, baud, baud);
>
>  out:
> -       spin_unlock_irqrestore(&port->lock, flags);
> +       spin_unlock(&port->lock);
> +       spin_unlock_irqrestore(&priv->lock, flags);
>  }

Are both port->lock and priv->lock really necessary ?


> @@ -1572,7 +1578,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
>
>        if (locked)
>                spin_unlock(&priv->port.lock);
> +       spin_unlock(&priv->lock);
>        local_irq_restore(flags);
> +
>  }

Looks spare blank line.

thanks.
-- 
ROHM Co., Ltd.
tomoya
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox