aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Charkov <alchark@gmail.com>2014-09-06 13:21:12 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-09-08 19:29:08 -0400
commitae382735247e2daebeed3bafd400ff71039d2241 (patch)
tree7baf9b4dd66fd936aa5fc52c7bb43703b131ecde
parent7d480ef776b53c43ec70155bfefbddc71b4d0883 (diff)
tty: vt8500_serial: add support for UART in WM8880 chips
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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/devicetree/bindings/serial/via,vt8500-uart.txt17
-rw-r--r--Documentation/devicetree/bindings/serial/vt8500-uart.txt3
-rw-r--r--drivers/tty/serial/vt8500_serial.c70
3 files changed, 58 insertions, 32 deletions
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 5feef1ef167d..000000000000
--- a/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
+++ /dev/null
@@ -1,17 +0,0 @@
1VIA/Wondermedia VT8500 UART Controller
2-----------------------------------------------------
3
4Required properties:
5- compatible : "via,vt8500-uart"
6- reg : Should contain 1 register ranges(address and length)
7- interrupts : UART interrupt
8- clocks : phandle to the uart source clock (usually a 24Mhz fixed clock)
9
10Example:
11
12 uart@d8210000 {
13 compatible = "via,vt8500-uart";
14 reg = <0xd8210000 0x1040>;
15 interrupts = <47>;
16 clocks = <&ref24>;
17 };
diff --git a/Documentation/devicetree/bindings/serial/vt8500-uart.txt b/Documentation/devicetree/bindings/serial/vt8500-uart.txt
index 795c393d09c4..2b64e6107fb3 100644
--- a/Documentation/devicetree/bindings/serial/vt8500-uart.txt
+++ b/Documentation/devicetree/bindings/serial/vt8500-uart.txt
@@ -1,7 +1,8 @@
1* VIA VT8500 and WonderMedia WM8xxx UART Controller 1* VIA VT8500 and WonderMedia WM8xxx UART Controller
2 2
3Required properties: 3Required properties:
4- compatible: should be "via,vt8500-uart" 4- compatible: should be "via,vt8500-uart" (for VIA/WonderMedia chips up to and
5 including WM8850/WM8950), or "wm,wm8880-uart" (for WM8880 and later)
5 6
6- reg: base physical address of the controller and length of memory mapped 7- reg: base physical address of the controller and length of memory mapped
7 region. 8 region.
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 15ad6fcda88b..f22571915185 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -33,8 +33,8 @@
33#include <linux/serial.h> 33#include <linux/serial.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/clk.h> 35#include <linux/clk.h>
36#include <linux/platform_device.h>
37#include <linux/of.h> 36#include <linux/of.h>
37#include <linux/of_device.h>
38#include <linux/err.h> 38#include <linux/err.h>
39 39
40/* 40/*
@@ -78,6 +78,29 @@
78#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT) 78#define RX_FIFO_INTS (RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
79#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR) 79#define TX_FIFO_INTS (TXFAE | TXFE | TXUDR)
80 80
81/*
82 * Line control bits
83 */
84
85#define VT8500_TXEN (1 << 0) /* Enable transmit logic */
86#define VT8500_RXEN (1 << 1) /* Enable receive logic */
87#define VT8500_CS8 (1 << 2) /* 8-bit data length (vs. 7-bit) */
88#define VT8500_CSTOPB (1 << 3) /* 2 stop bits (vs. 1) */
89#define VT8500_PARENB (1 << 4) /* Enable parity */
90#define VT8500_PARODD (1 << 5) /* Odd parity (vs. even) */
91#define VT8500_RTS (1 << 6) /* Ready to send */
92#define VT8500_LOOPBK (1 << 7) /* Enable internal loopback */
93#define VT8500_DMA (1 << 8) /* Enable DMA mode (needs FIFO) */
94#define VT8500_BREAK (1 << 9) /* Initiate break signal */
95#define VT8500_PSLVERR (1 << 10) /* APB error upon empty RX FIFO read */
96#define VT8500_SWRTSCTS (1 << 11) /* Software-controlled RTS/CTS */
97
98/*
99 * Capability flags (driver-internal)
100 */
101
102#define VT8500_HAS_SWRTSCTS_SWITCH (1 << 1)
103
81#define VT8500_MAX_PORTS 6 104#define VT8500_MAX_PORTS 6
82 105
83struct vt8500_port { 106struct vt8500_port {
@@ -85,6 +108,7 @@ struct vt8500_port {
85 char name[16]; 108 char name[16];
86 struct clk *clk; 109 struct clk *clk;
87 unsigned int ier; 110 unsigned int ier;
111 unsigned int vt8500_uart_flags;
88}; 112};
89 113
90/* 114/*
@@ -272,7 +296,8 @@ static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
272static void vt8500_break_ctl(struct uart_port *port, int break_ctl) 296static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
273{ 297{
274 if (break_ctl) 298 if (break_ctl)
275 vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9), 299 vt8500_write(port,
300 vt8500_read(port, VT8500_URLCR) | VT8500_BREAK,
276 VT8500_URLCR); 301 VT8500_URLCR);
277} 302}
278 303
@@ -347,31 +372,35 @@ static void vt8500_set_termios(struct uart_port *port,
347 372
348 /* calculate parity */ 373 /* calculate parity */
349 lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR); 374 lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
350 lcr &= ~((1 << 5) | (1 << 4)); 375 lcr &= ~(VT8500_PARENB | VT8500_PARODD);
351 if (termios->c_cflag & PARENB) { 376 if (termios->c_cflag & PARENB) {
352 lcr |= (1 << 4); 377 lcr |= VT8500_PARENB;
353 termios->c_cflag &= ~CMSPAR; 378 termios->c_cflag &= ~CMSPAR;
354 if (termios->c_cflag & PARODD) 379 if (termios->c_cflag & PARODD)
355 lcr |= (1 << 5); 380 lcr |= VT8500_PARODD;
356 } 381 }
357 382
358 /* calculate bits per char */ 383 /* calculate bits per char */
359 lcr &= ~(1 << 2); 384 lcr &= ~VT8500_CS8;
360 switch (termios->c_cflag & CSIZE) { 385 switch (termios->c_cflag & CSIZE) {
361 case CS7: 386 case CS7:
362 break; 387 break;
363 case CS8: 388 case CS8:
364 default: 389 default:
365 lcr |= (1 << 2); 390 lcr |= VT8500_CS8;
366 termios->c_cflag &= ~CSIZE; 391 termios->c_cflag &= ~CSIZE;
367 termios->c_cflag |= CS8; 392 termios->c_cflag |= CS8;
368 break; 393 break;
369 } 394 }
370 395
371 /* calculate stop bits */ 396 /* calculate stop bits */
372 lcr &= ~(1 << 3); 397 lcr &= ~VT8500_CSTOPB;
373 if (termios->c_cflag & CSTOPB) 398 if (termios->c_cflag & CSTOPB)
374 lcr |= (1 << 3); 399 lcr |= VT8500_CSTOPB;
400
401 lcr &= ~VT8500_SWRTSCTS;
402 if (vt8500_port->vt8500_uart_flags & VT8500_HAS_SWRTSCTS_SWITCH)
403 lcr |= VT8500_SWRTSCTS;
375 404
376 /* set parity, bits per char, and stop bit */ 405 /* set parity, bits per char, and stop bit */
377 vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR); 406 vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
@@ -548,14 +577,31 @@ static struct uart_driver vt8500_uart_driver = {
548 .cons = VT8500_CONSOLE, 577 .cons = VT8500_CONSOLE,
549}; 578};
550 579
580static unsigned int vt8500_flags; /* none required so far */
581static unsigned int wm8880_flags = VT8500_HAS_SWRTSCTS_SWITCH;
582
583static const struct of_device_id wmt_dt_ids[] = {
584 { .compatible = "via,vt8500-uart", .data = &vt8500_flags},
585 { .compatible = "wm,wm8880-uart", .data = &wm8880_flags},
586 {}
587};
588
551static int vt8500_serial_probe(struct platform_device *pdev) 589static int vt8500_serial_probe(struct platform_device *pdev)
552{ 590{
553 struct vt8500_port *vt8500_port; 591 struct vt8500_port *vt8500_port;
554 struct resource *mmres, *irqres; 592 struct resource *mmres, *irqres;
555 struct device_node *np = pdev->dev.of_node; 593 struct device_node *np = pdev->dev.of_node;
594 const struct of_device_id *match;
595 const unsigned int *flags;
556 int ret; 596 int ret;
557 int port; 597 int port;
558 598
599 match = of_match_device(wmt_dt_ids, &pdev->dev);
600 if (!match)
601 return -EINVAL;
602
603 flags = match->data;
604
559 mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 605 mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
560 irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 606 irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
561 if (!mmres || !irqres) 607 if (!mmres || !irqres)
@@ -605,6 +651,7 @@ static int vt8500_serial_probe(struct platform_device *pdev)
605 return ret; 651 return ret;
606 } 652 }
607 653
654 vt8500_port->vt8500_uart_flags = *flags;
608 vt8500_port->uart.type = PORT_VT8500; 655 vt8500_port->uart.type = PORT_VT8500;
609 vt8500_port->uart.iotype = UPIO_MEM; 656 vt8500_port->uart.iotype = UPIO_MEM;
610 vt8500_port->uart.mapbase = mmres->start; 657 vt8500_port->uart.mapbase = mmres->start;
@@ -639,11 +686,6 @@ static int vt8500_serial_remove(struct platform_device *pdev)
639 return 0; 686 return 0;
640} 687}
641 688
642static const struct of_device_id wmt_dt_ids[] = {
643 { .compatible = "via,vt8500-uart", },
644 {}
645};
646
647static struct platform_driver vt8500_platform_driver = { 689static struct platform_driver vt8500_platform_driver = {
648 .probe = vt8500_serial_probe, 690 .probe = vt8500_serial_probe,
649 .remove = vt8500_serial_remove, 691 .remove = vt8500_serial_remove,