linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] tty: vt8500_serial: Changes for -next
@ 2014-09-06 17:21 Alexey Charkov
  2014-09-06 17:21 ` [PATCH 1/4] tty: vt8500_serial: add support for UART in WM8880 chips Alexey Charkov
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Alexey Charkov @ 2014-09-06 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,

This series introduces a bit of clean-up (reduce magic numbers) and
new features for the VT8500 serial driver.

Firstly, in a new generation of WonderMedia SoC's the UART module
changed slightly, and now requires one more bit to be set in its
line control register to function properly. This is handled in the
first patch by adding a new DT 'compatible' string for the new chips.

Secondly, a couple of ommissions from the initial driver version are
now filled, namely RTS setting (second patch) and correct calculation
of baud rate predivisors, divisors etc. for any given input clock
(third patch). Initial version implicitly assumed input clock to be
always 24MHz and predivisor to be /2 (which holds for current chips,
but doesn't need to hold in general).

Thirdly, polled console functions are now implemented (fourth patch)
to support KGDB over VT8500 UART.

These changes have been tested on a WonderMedia WM8880 netbook (all),
and on a VIA Springboard (WM8950) (all except KGDB).

Greg, could you please merge these for -next, if they look fine?

Thanks a lot,
Alexey

Alexey Charkov (4):
  tty: vt8500_serial: add support for UART in WM8880 chips
  tty: vt8500_serial: add missing support for RTS setting
  tty: vt8500_serial: explicitly calculate base baud rate
  tty: vt8500_serial: add polled console functions

 .../devicetree/bindings/serial/via,vt8500-uart.txt |  17 ---
 .../devicetree/bindings/serial/vt8500-uart.txt     |   3 +-
 drivers/tty/serial/vt8500_serial.c                 | 136 ++++++++++++++++++---
 3 files changed, 118 insertions(+), 38 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/serial/via,vt8500-uart.txt

-- 
2.0.0

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

* [PATCH 1/4] tty: vt8500_serial: add support for UART in WM8880 chips
  2014-09-06 17:21 [PATCH 0/4] tty: vt8500_serial: Changes for -next Alexey Charkov
@ 2014-09-06 17:21 ` Alexey Charkov
  2014-09-06 17:21 ` [PATCH 2/4] tty: vt8500_serial: add missing support for RTS setting Alexey Charkov
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Alexey Charkov @ 2014-09-06 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Newer WonderMedia chips introduced another flag in the UART line control
register, which controls whether RTS/CTS signalling should be handled in
the driver or by the hardware itself.

This patch ensures that the kernel can control RTS/CTS (including
disabling it altogether) by forcing this flag to software mode on affected
chips (only WM8880 so far).

Also remove the redundant copy of the binding doc, while we are here.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
---
 .../devicetree/bindings/serial/via,vt8500-uart.txt | 17 ------
 .../devicetree/bindings/serial/vt8500-uart.txt     |  3 +-
 drivers/tty/serial/vt8500_serial.c                 | 70 +++++++++++++++++-----
 3 files changed, 58 insertions(+), 32 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/serial/via,vt8500-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt b/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
deleted file mode 100644
index 5feef1e..0000000
--- a/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-VIA/Wondermedia VT8500 UART Controller
------------------------------------------------------
-
-Required properties:
-- compatible : "via,vt8500-uart"
-- reg : Should contain 1 register ranges(address and length)
-- interrupts : UART interrupt
-- clocks : phandle to the uart source clock (usually a 24Mhz fixed clock)
-
-Example:
-
-	uart at d8210000 {
-		compatible = "via,vt8500-uart";
-		reg = <0xd8210000 0x1040>;
-		interrupts = <47>;
-		clocks = <&ref24>;
-	};
diff --git a/Documentation/devicetree/bindings/serial/vt8500-uart.txt b/Documentation/devicetree/bindings/serial/vt8500-uart.txt
index 795c393..2b64e61 100644
--- a/Documentation/devicetree/bindings/serial/vt8500-uart.txt
+++ b/Documentation/devicetree/bindings/serial/vt8500-uart.txt
@@ -1,7 +1,8 @@
 * VIA VT8500 and WonderMedia WM8xxx UART Controller
 
 Required properties:
-- compatible: should be "via,vt8500-uart"
+- compatible: should be "via,vt8500-uart" (for VIA/WonderMedia chips up to and
+	including WM8850/WM8950), or "wm,wm8880-uart" (for WM8880 and later)
 
 - reg: base physical address of the controller and length of memory mapped
 	region.
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 15ad6fc..f225719 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -33,8 +33,8 @@
 #include <linux/serial.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
-#include <linux/platform_device.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/err.h>
 
 /*
@@ -78,6 +78,29 @@
 #define RX_FIFO_INTS	(RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
 #define TX_FIFO_INTS	(TXFAE | TXFE | TXUDR)
 
+/*
+ * Line control bits
+ */
+
+#define VT8500_TXEN	(1 << 0)	/* Enable transmit logic */
+#define VT8500_RXEN	(1 << 1)	/* Enable receive logic */
+#define VT8500_CS8	(1 << 2)	/* 8-bit data length (vs. 7-bit) */
+#define VT8500_CSTOPB	(1 << 3)	/* 2 stop bits (vs. 1) */
+#define VT8500_PARENB	(1 << 4)	/* Enable parity */
+#define VT8500_PARODD	(1 << 5)	/* Odd parity (vs. even) */
+#define VT8500_RTS	(1 << 6)	/* Ready to send */
+#define VT8500_LOOPBK	(1 << 7)	/* Enable internal loopback */
+#define VT8500_DMA	(1 << 8)	/* Enable DMA mode (needs FIFO) */
+#define VT8500_BREAK	(1 << 9)	/* Initiate break signal */
+#define VT8500_PSLVERR	(1 << 10)	/* APB error upon empty RX FIFO read */
+#define VT8500_SWRTSCTS	(1 << 11)	/* Software-controlled RTS/CTS */
+
+/*
+ * Capability flags (driver-internal)
+ */
+
+#define VT8500_HAS_SWRTSCTS_SWITCH	(1 << 1)
+
 #define VT8500_MAX_PORTS	6
 
 struct vt8500_port {
@@ -85,6 +108,7 @@ struct vt8500_port {
 	char			name[16];
 	struct clk		*clk;
 	unsigned int		ier;
+	unsigned int		vt8500_uart_flags;
 };
 
 /*
@@ -272,7 +296,8 @@ static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
 static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
 {
 	if (break_ctl)
-		vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
+		vt8500_write(port,
+			     vt8500_read(port, VT8500_URLCR) | VT8500_BREAK,
 			     VT8500_URLCR);
 }
 
@@ -347,31 +372,35 @@ static void vt8500_set_termios(struct uart_port *port,
 
 	/* calculate parity */
 	lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
-	lcr &= ~((1 << 5) | (1 << 4));
+	lcr &= ~(VT8500_PARENB | VT8500_PARODD);
 	if (termios->c_cflag & PARENB) {
-		lcr |= (1 << 4);
+		lcr |= VT8500_PARENB;
 		termios->c_cflag &= ~CMSPAR;
 		if (termios->c_cflag & PARODD)
-			lcr |= (1 << 5);
+			lcr |= VT8500_PARODD;
 	}
 
 	/* calculate bits per char */
-	lcr &= ~(1 << 2);
+	lcr &= ~VT8500_CS8;
 	switch (termios->c_cflag & CSIZE) {
 	case CS7:
 		break;
 	case CS8:
 	default:
-		lcr |= (1 << 2);
+		lcr |= VT8500_CS8;
 		termios->c_cflag &= ~CSIZE;
 		termios->c_cflag |= CS8;
 		break;
 	}
 
 	/* calculate stop bits */
-	lcr &= ~(1 << 3);
+	lcr &= ~VT8500_CSTOPB;
 	if (termios->c_cflag & CSTOPB)
-		lcr |= (1 << 3);
+		lcr |= VT8500_CSTOPB;
+
+	lcr &= ~VT8500_SWRTSCTS;
+	if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH)
+		lcr |= VT8500_SWRTSCTS;
 
 	/* set parity, bits per char, and stop bit */
 	vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
@@ -548,14 +577,31 @@ static struct uart_driver vt8500_uart_driver = {
 	.cons		= VT8500_CONSOLE,
 };
 
+static unsigned int vt8500_flags; /* none required so far */
+static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH;
+
+static const struct of_device_id wmt_dt_ids[] = {
+	{ .compatible = "via,vt8500-uart", .data = &vt8500_flags},
+	{ .compatible = "wm,wm8880-uart", .data = &wm8880_flags},
+	{}
+};
+
 static int vt8500_serial_probe(struct platform_device *pdev)
 {
 	struct vt8500_port *vt8500_port;
 	struct resource *mmres, *irqres;
 	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match;
+	const unsigned int *flags;
 	int ret;
 	int port;
 
+	match = of_match_device(wmt_dt_ids, &pdev->dev);
+	if (!match)
+		return -EINVAL;
+
+	flags = match->data;
+
 	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!mmres || !irqres)
@@ -605,6 +651,7 @@ static int vt8500_serial_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	vt8500_port->vt8500_uart_flags = *flags;
 	vt8500_port->uart.type = PORT_VT8500;
 	vt8500_port->uart.iotype = UPIO_MEM;
 	vt8500_port->uart.mapbase = mmres->start;
@@ -639,11 +686,6 @@ static int vt8500_serial_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id wmt_dt_ids[] = {
-	{ .compatible = "via,vt8500-uart", },
-	{}
-};
-
 static struct platform_driver vt8500_platform_driver = {
 	.probe  = vt8500_serial_probe,
 	.remove = vt8500_serial_remove,
-- 
2.0.0

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

* [PATCH 2/4] tty: vt8500_serial: add missing support for RTS setting
  2014-09-06 17:21 [PATCH 0/4] tty: vt8500_serial: Changes for -next Alexey Charkov
  2014-09-06 17:21 ` [PATCH 1/4] tty: vt8500_serial: add support for UART in WM8880 chips Alexey Charkov
@ 2014-09-06 17:21 ` Alexey Charkov
  2014-09-06 17:21 ` [PATCH 3/4] tty: vt8500_serial: explicitly calculate base baud rate Alexey Charkov
  2014-09-06 17:21 ` [PATCH 4/4] tty: vt8500_serial: add polled console functions Alexey Charkov
  3 siblings, 0 replies; 5+ messages in thread
From: Alexey Charkov @ 2014-09-06 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Alexey Charkov <alchark@gmail.com>
---
 drivers/tty/serial/vt8500_serial.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index f225719..47e74f9 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -291,6 +291,14 @@ static unsigned int vt8500_get_mctrl(struct uart_port *port)
 
 static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
+	unsigned int lcr = vt8500_read(port, VT8500_URLCR);
+
+	if (mctrl & TIOCM_RTS)
+		lcr |= VT8500_RTS;
+	else
+		lcr &= ~VT8500_RTS;
+
+	vt8500_write(port, lcr, VT8500_URLCR);
 }
 
 static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
-- 
2.0.0

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

* [PATCH 3/4] tty: vt8500_serial: explicitly calculate base baud rate
  2014-09-06 17:21 [PATCH 0/4] tty: vt8500_serial: Changes for -next Alexey Charkov
  2014-09-06 17:21 ` [PATCH 1/4] tty: vt8500_serial: add support for UART in WM8880 chips Alexey Charkov
  2014-09-06 17:21 ` [PATCH 2/4] tty: vt8500_serial: add missing support for RTS setting Alexey Charkov
@ 2014-09-06 17:21 ` Alexey Charkov
  2014-09-06 17:21 ` [PATCH 4/4] tty: vt8500_serial: add polled console functions Alexey Charkov
  3 siblings, 0 replies; 5+ messages in thread
From: Alexey Charkov @ 2014-09-06 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Current code relies on the UART clock pre-divisor to be already
configured in the baud rate register. Calculate it in the driver
and set explicitly instead, also return the "real" effective baud
rate, which is generally slightly different from the requested value.

While at this, also ensure that break signal timing is updated when
baud rate changes.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
---
 drivers/tty/serial/vt8500_serial.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 47e74f9..bfcebfd 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -101,12 +101,15 @@
 
 #define VT8500_HAS_SWRTSCTS_SWITCH	(1 << 1)
 
+#define VT8500_RECOMMENDED_CLK		12000000
+#define VT8500_OVERSAMPLING_DIVISOR	13
 #define VT8500_MAX_PORTS	6
 
 struct vt8500_port {
 	struct uart_port	uart;
 	char			name[16];
 	struct clk		*clk;
+	unsigned int		clk_predivisor;
 	unsigned int		ier;
 	unsigned int		vt8500_uart_flags;
 };
@@ -311,20 +314,25 @@ static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
 
 static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
 {
+	struct vt8500_port *vt8500_port =
+			container_of(port, struct vt8500_port, uart);
 	unsigned long div;
 	unsigned int loops = 1000;
 
-	div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
+	div = ((vt8500_port->clk_predivisor - 1) & 0xf) << 16;
+	div |= (uart_get_divisor(port, baud) - 1) & 0x3ff;
 
-	if (unlikely((baud < 900) || (baud > 921600)))
-		div |= 7;
-	else
-		div |= (921600 / baud) - 1;
+	/* Effective baud rate */
+	baud = port->uartclk / 16 / ((div & 0x3ff) + 1);
 
 	while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
 		cpu_relax();
+
 	vt8500_write(port, div, VT8500_URDIV);
 
+	/* Break signal timing depends on baud rate, update accordingly */
+	vt8500_write(port, mult_frac(baud, 4096, 1000000), VT8500_URBKR);
+
 	return baud;
 }
 
@@ -660,6 +668,10 @@ static int vt8500_serial_probe(struct platform_device *pdev)
 	}
 
 	vt8500_port->vt8500_uart_flags = *flags;
+	vt8500_port->clk_predivisor = DIV_ROUND_CLOSEST(
+					clk_get_rate(vt8500_port->clk),
+					VT8500_RECOMMENDED_CLK
+				      );
 	vt8500_port->uart.type = PORT_VT8500;
 	vt8500_port->uart.iotype = UPIO_MEM;
 	vt8500_port->uart.mapbase = mmres->start;
@@ -670,7 +682,10 @@ static int vt8500_serial_probe(struct platform_device *pdev)
 	vt8500_port->uart.dev = &pdev->dev;
 	vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
 
-	vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk);
+	/* Serial core uses the magic "16" everywhere - adjust for it */
+	vt8500_port->uart.uartclk = 16 * clk_get_rate(vt8500_port->clk) /
+					vt8500_port->clk_predivisor /
+					VT8500_OVERSAMPLING_DIVISOR;
 
 	snprintf(vt8500_port->name, sizeof(vt8500_port->name),
 		 "VT8500 UART%d", pdev->id);
-- 
2.0.0

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

* [PATCH 4/4] tty: vt8500_serial: add polled console functions
  2014-09-06 17:21 [PATCH 0/4] tty: vt8500_serial: Changes for -next Alexey Charkov
                   ` (2 preceding siblings ...)
  2014-09-06 17:21 ` [PATCH 3/4] tty: vt8500_serial: explicitly calculate base baud rate Alexey Charkov
@ 2014-09-06 17:21 ` Alexey Charkov
  3 siblings, 0 replies; 5+ messages in thread
From: Alexey Charkov @ 2014-09-06 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

This adds simple polling functions for single-character transmit
and receive, as used by kgdb.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
---
 drivers/tty/serial/vt8500_serial.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index bfcebfd..b2bc9e8 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -566,6 +566,33 @@ static struct console vt8500_console = {
 #define VT8500_CONSOLE	NULL
 #endif
 
+#ifdef CONFIG_CONSOLE_POLL
+static int vt8500_get_poll_char(struct uart_port *port)
+{
+	unsigned int status = vt8500_read(port, VT8500_URFIDX);
+
+	if (!(status & 0x1f00))
+		return NO_POLL_CHAR;
+
+	return vt8500_read(port, VT8500_RXFIFO) & 0xff;
+}
+
+static void vt8500_put_poll_char(struct uart_port *port, unsigned char c)
+{
+	unsigned int status, tmout = 10000;
+
+	do {
+		status = vt8500_read(port, VT8500_URFIDX);
+
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while (status & 0x10);
+
+	vt8500_write(port, c, VT8500_TXFIFO);
+}
+#endif
+
 static struct uart_ops vt8500_uart_pops = {
 	.tx_empty	= vt8500_tx_empty,
 	.set_mctrl	= vt8500_set_mctrl,
@@ -583,6 +610,10 @@ static struct uart_ops vt8500_uart_pops = {
 	.request_port	= vt8500_request_port,
 	.config_port	= vt8500_config_port,
 	.verify_port	= vt8500_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char	= vt8500_get_poll_char,
+	.poll_put_char	= vt8500_put_poll_char,
+#endif
 };
 
 static struct uart_driver vt8500_uart_driver = {
-- 
2.0.0

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

end of thread, other threads:[~2014-09-06 17:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-06 17:21 [PATCH 0/4] tty: vt8500_serial: Changes for -next Alexey Charkov
2014-09-06 17:21 ` [PATCH 1/4] tty: vt8500_serial: add support for UART in WM8880 chips Alexey Charkov
2014-09-06 17:21 ` [PATCH 2/4] tty: vt8500_serial: add missing support for RTS setting Alexey Charkov
2014-09-06 17:21 ` [PATCH 3/4] tty: vt8500_serial: explicitly calculate base baud rate Alexey Charkov
2014-09-06 17:21 ` [PATCH 4/4] tty: vt8500_serial: add polled console functions Alexey Charkov

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