aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-12-22 12:48:26 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-01-05 11:58:44 -0500
commitc19f12b5ef3adf3c139eabbe3d3d0201838b77b1 (patch)
tree8e4feb43846bb02a50132dc97d3a8d8cac8346ee /drivers/serial
parent5063e2c567ee569cccfc01ebf80c898cb4e6833a (diff)
ARM: PL011: Allow better handling of vendor data
Rather than copying all vendor data into the port structure, copy just that which is frequently used, and keep a pointer to the remaining vendor data structure. This makes it easier to add vendor quirks in the future. Acked-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/amba-pl011.c51
1 files changed, 27 insertions, 24 deletions
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index c77b3eb5142d..6afdd9b39720 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -63,22 +63,6 @@
63#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) 63#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
64#define UART_DUMMY_DR_RX (1 << 16) 64#define UART_DUMMY_DR_RX (1 << 16)
65 65
66/*
67 * We wrap our port structure around the generic uart_port.
68 */
69struct uart_amba_port {
70 struct uart_port port;
71 struct clk *clk;
72 unsigned int im; /* interrupt mask */
73 unsigned int old_status;
74 unsigned int ifls; /* vendor-specific */
75 unsigned int lcrh_tx; /* vendor-specific */
76 unsigned int lcrh_rx; /* vendor-specific */
77 bool oversampling; /* vendor-specific */
78 bool autorts;
79 char type[12];
80};
81
82/* There is by now at least one vendor with differing details, so handle it */ 66/* There is by now at least one vendor with differing details, so handle it */
83struct vendor_data { 67struct vendor_data {
84 unsigned int ifls; 68 unsigned int ifls;
@@ -104,6 +88,21 @@ static struct vendor_data vendor_st = {
104 .oversampling = true, 88 .oversampling = true,
105}; 89};
106 90
91/*
92 * We wrap our port structure around the generic uart_port.
93 */
94struct uart_amba_port {
95 struct uart_port port;
96 struct clk *clk;
97 const struct vendor_data *vendor;
98 unsigned int im; /* interrupt mask */
99 unsigned int old_status;
100 unsigned int lcrh_tx; /* vendor-specific */
101 unsigned int lcrh_rx; /* vendor-specific */
102 bool autorts;
103 char type[12];
104};
105
107static void pl011_stop_tx(struct uart_port *port) 106static void pl011_stop_tx(struct uart_port *port)
108{ 107{
109 struct uart_amba_port *uap = (struct uart_amba_port *)port; 108 struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -397,7 +396,7 @@ static int pl011_startup(struct uart_port *port)
397 if (retval) 396 if (retval)
398 goto clk_dis; 397 goto clk_dis;
399 398
400 writew(uap->ifls, uap->port.membase + UART011_IFLS); 399 writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
401 400
402 /* 401 /*
403 * Provoke TX FIFO interrupt into asserting. 402 * Provoke TX FIFO interrupt into asserting.
@@ -503,13 +502,18 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
503 struct uart_amba_port *uap = (struct uart_amba_port *)port; 502 struct uart_amba_port *uap = (struct uart_amba_port *)port;
504 unsigned int lcr_h, old_cr; 503 unsigned int lcr_h, old_cr;
505 unsigned long flags; 504 unsigned long flags;
506 unsigned int baud, quot; 505 unsigned int baud, quot, clkdiv;
506
507 if (uap->vendor->oversampling)
508 clkdiv = 8;
509 else
510 clkdiv = 16;
507 511
508 /* 512 /*
509 * Ask the core to calculate the divisor for us. 513 * Ask the core to calculate the divisor for us.
510 */ 514 */
511 baud = uart_get_baud_rate(port, termios, old, 0, 515 baud = uart_get_baud_rate(port, termios, old, 0,
512 port->uartclk/(uap->oversampling ? 8 : 16)); 516 port->uartclk / clkdiv);
513 517
514 if (baud > port->uartclk/16) 518 if (baud > port->uartclk/16)
515 quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); 519 quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
@@ -593,8 +597,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
593 uap->autorts = false; 597 uap->autorts = false;
594 } 598 }
595 599
596 if (uap->oversampling) { 600 if (uap->vendor->oversampling) {
597 if (baud > port->uartclk/16) 601 if (baud > port->uartclk / 16)
598 old_cr |= ST_UART011_CR_OVSFACT; 602 old_cr |= ST_UART011_CR_OVSFACT;
599 else 603 else
600 old_cr &= ~ST_UART011_CR_OVSFACT; 604 old_cr &= ~ST_UART011_CR_OVSFACT;
@@ -767,7 +771,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
767 771
768 *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); 772 *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
769 773
770 if (uap->oversampling) { 774 if (uap->vendor->oversampling) {
771 if (readw(uap->port.membase + UART011_CR) 775 if (readw(uap->port.membase + UART011_CR)
772 & ST_UART011_CR_OVSFACT) 776 & ST_UART011_CR_OVSFACT)
773 *baud *= 2; 777 *baud *= 2;
@@ -864,10 +868,9 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
864 goto unmap; 868 goto unmap;
865 } 869 }
866 870
867 uap->ifls = vendor->ifls; 871 uap->vendor = vendor;
868 uap->lcrh_rx = vendor->lcrh_rx; 872 uap->lcrh_rx = vendor->lcrh_rx;
869 uap->lcrh_tx = vendor->lcrh_tx; 873 uap->lcrh_tx = vendor->lcrh_tx;
870 uap->oversampling = vendor->oversampling;
871 uap->port.dev = &dev->dev; 874 uap->port.dev = &dev->dev;
872 uap->port.mapbase = dev->res.start; 875 uap->port.mapbase = dev->res.start;
873 uap->port.membase = base; 876 uap->port.membase = base;