1 From 6e138e4c3bfa5fb272d215107d85385456281ceb Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Sat, 24 Apr 2010 12:19:30 +0200
4 Subject: [PATCH] Add jz4740 serial driver
7 drivers/serial/8250.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++-
8 1 files changed, 103 insertions(+), 1 deletions(-)
10 diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
11 index 2b1ea3d..4c41c57 100644
12 --- a/drivers/serial/8250.c
13 +++ b/drivers/serial/8250.c
14 @@ -200,7 +200,7 @@ static const struct serial8250_config uart_config[] = {
20 .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
21 .flags = UART_CAP_FIFO,
23 @@ -407,6 +407,10 @@ static unsigned int mem_serial_in(struct uart_port *p, int offset)
24 static void mem_serial_out(struct uart_port *p, int offset, int value)
26 offset = map_8250_out_reg(p, offset) << p->regshift;
27 +#if defined(CONFIG_JZSOC)
28 + if (offset == (UART_FCR << p->regshift))
29 + value |= 0x10; /* set FCR.UUE */
31 writeb(value, p->membase + offset);
34 @@ -2209,6 +2213,83 @@ static void serial8250_shutdown(struct uart_port *port)
35 serial_unlink_irq_chain(up);
38 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
39 +static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */
40 +static unsigned short * serial8250_get_divisor(struct uart_port *port, unsigned int baud)
44 + unsigned short div, umr, uacr;
45 + unsigned short umr_best, div_best, uacr_best;
46 + long long t0, t1, t2, t3;
49 + umr_best = div_best = uacr_best = 0;
52 + if ((port->uartclk % (16 * baud)) == 0) {
53 + quot1[0] = port->uartclk / (16 * baud);
60 + umr = port->uartclk / (baud * div);
68 + for (i = 0; i < 12; i++) {
72 + for (j = 0; j <= i; j++) {
76 + /* the precision could be 1/2^(36) due to the value of t0 */
77 + t0 = 0x1000000000LL;
79 + t2 = (sum * div) * t0;
82 + do_div(t2, port->uartclk);
83 + do_div(t3, (2 * port->uartclk));
93 + for (i = 0; i < 12; i++) {
99 + /* the best value of umr should be near 16, and the value of uacr should better be smaller */
100 + if (abs(umr - 16) < abs(umr_best - 16) || (abs(umr - 16) == abs(umr_best - 16) && uacr_best > uacr)) {
108 + quot1[0] = div_best;
109 + quot1[1] = umr_best;
110 + quot1[2] = uacr_best;
115 static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
118 @@ -2228,6 +2309,7 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
125 serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
126 @@ -2237,6 +2319,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
127 unsigned char cval, fcr = 0;
129 unsigned int baud, quot;
130 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
131 + unsigned short *quot1;
134 switch (termios->c_cflag & CSIZE) {
136 @@ -2271,7 +2356,12 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
137 baud = uart_get_baud_rate(port, termios, old,
138 port->uartclk / 16 / 0xffff,
140 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
141 + quot1 = serial8250_get_divisor(port, baud);
142 + quot = quot1[0]; /* not usefull, just let gcc happy */
144 quot = serial8250_get_divisor(port, baud);
148 * Oxford Semi 952 rev B workaround
149 @@ -2349,6 +2439,10 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
150 if (up->capabilities & UART_CAP_UUE)
151 up->ier |= UART_IER_UUE | UART_IER_RTOIE;
154 + up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */
157 serial_out(up, UART_IER, up->ier);
159 if (up->capabilities & UART_CAP_EFR) {
160 @@ -2383,7 +2477,15 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
161 serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
164 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
166 +#define UART_UACR 10
167 + serial_dl_write(up, quot1[0]);
168 + serial_outp(up, UART_UMR, quot1[1]);
169 + serial_outp(up, UART_UACR, quot1[2]);
171 serial_dl_write(up, quot);
175 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR