Add preliminary RouterBoard RB1xx support
[openwrt.git] / target / linux / rb1xx-2.6 / files / drivers / serial / adm5120_uart.c
1 /*
2  *      Serial driver for ADM5120 SoC
3  *
4  *      Derived from drivers/serial/uart00.c
5  *      Copyright 2001 Altera Corporation
6  *
7  *      Some pieces are derived from the ADMtek 2.4 serial driver.
8  *      Copyright (C) ADMtek Incorporated, 2003
9  *              daniell@admtek.com.tw
10  *      Which again was derived from drivers/char/serial.c
11  *      Copyright (C) Linus Torvalds et al.
12  *
13  *      Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
14  */
15
16 #include <linux/autoconf.h>
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/ioport.h>
21 #include <linux/serial.h>
22 #include <linux/serial_core.h>
23 #include <linux/tty.h>
24 #include <linux/tty_flip.h>
25 #include <linux/console.h>
26
27 #define ADM5120_UART_BASE0              0x12600000
28 #define ADM5120_UART_BASE1              0x12800000
29 #define ADM5120_UART_SIZE               0x20
30
31 #define ADM5120_UART_IRQ0               1
32 #define ADM5120_UART_IRQ1               2
33
34 #define ADM5120_UART_REG(base, reg) \
35         (*(volatile u32 *)KSEG1ADDR((base)+(reg)))
36
37 #define ADM5120_UARTCLK_FREQ            62500000
38 #define ADM5120_UART_BAUDDIV(rate)      ((unsigned long)(ADM5120_UARTCLK_FREQ/(16*(rate)) - 1))
39
40 #define ADM5120_UART_BAUD115200         ADM5120_UART_BAUDDIV(115200)
41
42 #define ADM5120_UART_DATA               0x00
43 #define ADM5120_UART_RS                 0x04
44 #define ADM5120_UART_LCR_H              0x08
45 #define ADM5120_UART_LCR_M              0x0c
46 #define ADM5120_UART_LCR_L              0x10
47 #define ADM5120_UART_CR                 0x14
48 #define ADM5120_UART_FR                 0x18
49 #define ADM5120_UART_IR                 0x1c
50
51 #define ADM5120_UART_FE                 0x01
52 #define ADM5120_UART_PE                 0x02
53 #define ADM5120_UART_BE                 0x04
54 #define ADM5120_UART_OE                 0x08
55 #define ADM5120_UART_ERR                0x0f
56 #define ADM5120_UART_FIFO_EN            0x10
57 #define ADM5120_UART_EN                 0x01
58 #define ADM5120_UART_TIE                0x20
59 #define ADM5120_UART_RIE                0x50
60 #define ADM5120_UART_IE                 0x78
61 #define ADM5120_UART_CTS                0x01
62 #define ADM5120_UART_DSR                0x02
63 #define ADM5120_UART_DCD                0x04
64 #define ADM5120_UART_TXFF               0x20
65 #define ADM5120_UART_TXFE               0x80
66 #define ADM5120_UART_RXFE               0x10
67 #define ADM5120_UART_BRK                0x01
68 #define ADM5120_UART_PEN                0x02
69 #define ADM5120_UART_EPS                0x04
70 #define ADM5120_UART_STP2               0x08
71 #define ADM5120_UART_W5                 0x00
72 #define ADM5120_UART_W6                 0x20
73 #define ADM5120_UART_W7                 0x40
74 #define ADM5120_UART_W8                 0x60
75 #define ADM5120_UART_MIS                0x01
76 #define ADM5120_UART_RIS                0x02
77 #define ADM5120_UART_TIS                0x04
78 #define ADM5120_UART_RTIS               0x08
79
80 static void adm5120ser_stop_tx(struct uart_port *port)
81 {
82         ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) &= ~ADM5120_UART_TIE;
83 }
84
85 static void adm5120ser_irq_rx(struct uart_port *port)
86 {
87         struct tty_struct *tty = port->info->tty;
88         unsigned int status, ch, rds, flg, ignored = 0;
89
90         status = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
91         while (!(status & ADM5120_UART_RXFE)) {
92                 /* 
93                  * We need to read rds before reading the 
94                  * character from the fifo
95                  */
96                 rds = ADM5120_UART_REG(port->iobase, ADM5120_UART_RS);
97                 ch = ADM5120_UART_REG(port->iobase, ADM5120_UART_DATA);
98                 port->icount.rx++;
99
100                 if (tty->low_latency)
101                         tty_flip_buffer_push(tty);
102
103                 flg = TTY_NORMAL;
104
105                 /*
106                  * Note that the error handling code is
107                  * out of the main execution path
108                  */
109                 if (rds & ADM5120_UART_ERR)
110                         goto handle_error;
111                 if (uart_handle_sysrq_char(port, ch))
112                         goto ignore_char;
113
114         error_return:
115                 tty_insert_flip_char(tty, ch, flg);
116
117         ignore_char:
118                 status = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
119         }
120  out:
121         tty_flip_buffer_push(tty);
122         return;
123
124  handle_error:
125         ADM5120_UART_REG(port->iobase, ADM5120_UART_RS) = 0xff;
126         if (rds & ADM5120_UART_BE) {
127                 port->icount.brk++;
128                 if (uart_handle_break(port))
129                         goto ignore_char;
130         } else if (rds & ADM5120_UART_PE)
131                 port->icount.parity++;
132         else if (rds & ADM5120_UART_FE)
133                 port->icount.frame++;
134         if (rds & ADM5120_UART_OE)
135                 port->icount.overrun++;
136
137         if (rds & port->ignore_status_mask) {
138                 if (++ignored > 100)
139                         goto out;
140                 goto ignore_char;
141         }
142         rds &= port->read_status_mask;
143
144         if (rds & ADM5120_UART_BE)
145                 flg = TTY_BREAK;
146         else if (rds & ADM5120_UART_PE)
147                 flg = TTY_PARITY;
148         else if (rds & ADM5120_UART_FE)
149                 flg = TTY_FRAME;
150
151         if (rds & ADM5120_UART_OE) {
152                 /*
153                  * CHECK: does overrun affect the current character?
154                  * ASSUMPTION: it does not.
155                  */
156                 tty_insert_flip_char(tty, ch, flg);
157                 ch = 0;
158                 flg = TTY_OVERRUN;
159         }
160 #ifdef CONFIG_MAGIC_SYSRQ
161         port->sysrq = 0;
162 #endif
163         goto error_return;
164 }
165
166 static void adm5120ser_irq_tx(struct uart_port *port)
167 {
168         struct circ_buf *xmit = &port->info->xmit;
169         int count;
170
171         if (port->x_char) {
172                 ADM5120_UART_REG(port->iobase, ADM5120_UART_DATA) =
173                     port->x_char;
174                 port->icount.tx++;
175                 port->x_char = 0;
176                 return;
177         }
178         if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
179                 adm5120ser_stop_tx(port);
180                 return;
181         }
182
183         count = port->fifosize >> 1;
184         do {
185                 ADM5120_UART_REG(port->iobase, ADM5120_UART_DATA) =
186                     xmit->buf[xmit->tail];
187                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
188                 port->icount.tx++;
189                 if (uart_circ_empty(xmit))
190                         break;
191         } while (--count > 0);
192
193         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
194                 uart_write_wakeup(port);
195
196         if (uart_circ_empty(xmit))
197                 adm5120ser_stop_tx(port);
198 }
199
200 static void adm5120ser_irq_modem(struct uart_port *port)
201 {
202         unsigned int status;
203
204         status = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
205
206         if (status & ADM5120_UART_DCD)
207                 uart_handle_dcd_change(port, status & ADM5120_UART_DCD);
208
209         if (status & ADM5120_UART_DSR)
210                 port->icount.dsr++;
211
212         if (status & ADM5120_UART_CTS)
213                 uart_handle_cts_change(port, status & ADM5120_UART_CTS);
214
215         wake_up_interruptible(&port->info->delta_msr_wait);
216 }
217
218 static irqreturn_t adm5120ser_irq(int irq, void *dev_id)
219 {
220         struct uart_port *port = dev_id;
221         unsigned long ir = ADM5120_UART_REG(port->iobase, ADM5120_UART_IR);
222
223         if (ir & (ADM5120_UART_RIS | ADM5120_UART_RTIS))
224                 adm5120ser_irq_rx(port);
225         if (ir & ADM5120_UART_TIS)
226                 adm5120ser_irq_tx(port);
227         if (ir & ADM5120_UART_MIS) {
228                 adm5120ser_irq_modem(port);
229                 ADM5120_UART_REG(port->iobase, ADM5120_UART_IR) = 0xff;
230         }
231
232         return IRQ_HANDLED;
233 }
234
235 static unsigned int adm5120ser_tx_empty(struct uart_port *port)
236 {
237         unsigned int fr = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
238         return (fr & ADM5120_UART_TXFE) ? TIOCSER_TEMT : 0;
239 }
240
241 static void adm5120ser_set_mctrl(struct uart_port *port, unsigned int mctrl)
242 {
243 }
244
245 static unsigned int adm5120ser_get_mctrl(struct uart_port *port)
246 {
247         unsigned int result = 0;
248         unsigned int fr = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
249
250         if (fr & ADM5120_UART_CTS)
251                 result |= TIOCM_CTS;
252         if (fr & ADM5120_UART_DSR)
253                 result |= TIOCM_DSR;
254         if (fr & ADM5120_UART_DCD)
255                 result |= TIOCM_CAR;
256         return result;
257 }
258
259 static void adm5120ser_start_tx(struct uart_port *port)
260 {
261         ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) |= ADM5120_UART_TIE;
262 }
263
264 static void adm5120ser_stop_rx(struct uart_port *port)
265 {
266         ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) &= ~ADM5120_UART_RIE;
267 }
268
269 static void adm5120ser_enable_ms(struct uart_port *port)
270 {
271 }
272
273 static void adm5120ser_break_ctl(struct uart_port *port, int break_state)
274 {
275         unsigned long flags;
276         unsigned long lcrh;
277
278         spin_lock_irqsave(&port->lock, flags);
279         lcrh = ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H);
280         if (break_state == -1)
281                 lcrh |= ADM5120_UART_BRK;
282         else
283                 lcrh &= ~ADM5120_UART_BRK;
284         ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H) = lcrh;
285         spin_unlock_irqrestore(&port->lock, flags);
286 }
287
288 static int adm5120ser_startup(struct uart_port *port)
289 {
290         int ret;
291
292         ret = request_irq(port->irq, adm5120ser_irq, 0, "ADM5120 UART", port);
293         if (ret) {
294                 printk(KERN_ERR "Couldn't get irq %d\n", port->irq);
295                 return ret;
296         }
297         ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H) |=
298             ADM5120_UART_FIFO_EN;
299         ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) |=
300             ADM5120_UART_EN | ADM5120_UART_IE;
301         return 0;
302 }
303
304 static void adm5120ser_shutdown(struct uart_port *port)
305 {
306         ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) &= ~ADM5120_UART_IE;
307         free_irq(port->irq, port);
308 }
309
310 static void adm5120ser_set_termios(struct uart_port *port,
311     struct termios *termios, struct termios *old)
312 {
313         unsigned int baud, quot, lcrh;
314         unsigned long flags;
315
316         termios->c_cflag |= CREAD;
317
318         baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
319         quot = uart_get_divisor(port, baud);
320
321         lcrh = ADM5120_UART_FIFO_EN;
322         switch (termios->c_cflag & CSIZE) {
323                 case CS5:
324                         lcrh |= ADM5120_UART_W5;
325                         break;
326                 case CS6:
327                         lcrh |= ADM5120_UART_W6;
328                         break;
329                 case CS7:
330                         lcrh |= ADM5120_UART_W7;
331                         break;
332                 default:
333                         lcrh |= ADM5120_UART_W8;
334                         break;
335         }
336         if (termios->c_cflag & CSTOPB)
337                 lcrh |= ADM5120_UART_STP2;
338         if (termios->c_cflag & PARENB) {
339                 lcrh |= ADM5120_UART_PEN;
340                 if (!(termios->c_cflag & PARODD))
341                         lcrh |= ADM5120_UART_EPS;
342         }
343
344         spin_lock_irqsave(port->lock, flags);
345
346         ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H) = lcrh;
347
348         /*
349          * Update the per-port timeout.
350          */
351         uart_update_timeout(port, termios->c_cflag, baud);
352
353         port->read_status_mask = ADM5120_UART_OE;
354         if (termios->c_iflag & INPCK)
355                 port->read_status_mask |= ADM5120_UART_FE | ADM5120_UART_PE;
356         if (termios->c_iflag & (BRKINT | PARMRK))
357                 port->read_status_mask |= ADM5120_UART_BE;
358
359         /*
360          * Characters to ignore
361          */
362         port->ignore_status_mask = 0;
363         if (termios->c_iflag & IGNPAR)
364                 port->ignore_status_mask |= ADM5120_UART_FE | ADM5120_UART_PE;
365         if (termios->c_iflag & IGNBRK) {
366                 port->ignore_status_mask |= ADM5120_UART_BE;
367                 /*
368                  * If we're ignoring parity and break indicators,
369                  * ignore overruns to (for real raw support).
370                  */
371                 if (termios->c_iflag & IGNPAR)
372                         port->ignore_status_mask |= ADM5120_UART_OE;
373         }
374
375         quot = ADM5120_UART_BAUD115200;
376         ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_L) = quot & 0xff;
377         ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_M) = quot >> 8;
378
379         spin_unlock_irqrestore(&port->lock, flags);
380 }
381
382 static const char *adm5120ser_type(struct uart_port *port)
383 {
384         return port->type == PORT_ADM5120 ? "ADM5120" : NULL;
385 }
386
387 static void adm5120ser_config_port(struct uart_port *port, int flags)
388 {
389         if (flags & UART_CONFIG_TYPE)
390                 port->type = PORT_ADM5120;
391 }
392
393 static void adm5120ser_release_port(struct uart_port *port)
394 {
395         release_mem_region(port->iobase, ADM5120_UART_SIZE);
396 }
397
398 static int adm5120ser_request_port(struct uart_port *port)
399 {
400         return request_mem_region(port->iobase, ADM5120_UART_SIZE,
401             "adm5120-uart") != NULL ? 0 : -EBUSY; 
402 }
403
404 static struct uart_ops adm5120ser_ops = {
405         .tx_empty =     adm5120ser_tx_empty,
406         .set_mctrl =    adm5120ser_set_mctrl,
407         .get_mctrl =    adm5120ser_get_mctrl,
408         .stop_tx =      adm5120ser_stop_tx,
409         .start_tx =     adm5120ser_start_tx,
410         .stop_rx =      adm5120ser_stop_rx,
411         .enable_ms =    adm5120ser_enable_ms,
412         .break_ctl =    adm5120ser_break_ctl,
413         .startup =      adm5120ser_startup,
414         .shutdown =     adm5120ser_shutdown,
415         .set_termios =  adm5120ser_set_termios,
416         .type =         adm5120ser_type,
417         .config_port =  adm5120ser_config_port,
418         .release_port = adm5120ser_release_port,
419         .request_port = adm5120ser_request_port,
420 };
421
422 static void adm5120console_put(const char c)
423 {
424         while ((ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_FR) &
425              ADM5120_UART_TXFF) != 0);
426         ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_DATA) = c;
427 }
428
429 static void adm5120console_write(struct console *con, const char *s,
430     unsigned int count)
431 {
432         while (count--) {
433                 if (*s == '\n')
434                         adm5120console_put('\r');
435                 adm5120console_put(*s);
436                 s++;
437         }
438 }
439
440 static int __init adm5120console_setup(struct console *con, char *options)
441 {
442         /* Set to 115200 baud, 8N1 and enable FIFO */
443         ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_L) =
444             ADM5120_UART_BAUD115200 & 0xff;
445         ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_M) =
446             ADM5120_UART_BAUD115200 >> 8;
447         ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_H) =
448             ADM5120_UART_W8 | ADM5120_UART_FIFO_EN;
449         /* Enable port */
450         ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_CR) =
451             ADM5120_UART_EN;
452
453         return 0;
454 }
455
456 static struct uart_driver adm5120ser_reg;
457
458 static struct console adm5120_serconsole = {
459         .name =         "ttyS",
460         .write =        adm5120console_write,
461         .device =       uart_console_device,
462         .setup =        adm5120console_setup,
463         .flags =        CON_PRINTBUFFER,
464         .cflag =        B115200 | CS8 | CREAD,
465         .index =        0,
466         .data =         &adm5120ser_reg,
467 };
468
469 static int __init adm5120console_init(void)
470 {
471         register_console(&adm5120_serconsole);
472         return 0;
473 }
474
475 console_initcall(adm5120console_init);
476
477
478 static struct uart_port adm5120ser_ports[] = {
479         {
480                 .iobase =       ADM5120_UART_BASE0,
481                 .irq =          ADM5120_UART_IRQ0,
482                 .uartclk =      ADM5120_UARTCLK_FREQ,
483                 .fifosize =     16,
484                 .ops =          &adm5120ser_ops,
485                 .line =         0,
486                 .flags =        ASYNC_BOOT_AUTOCONF,
487         },
488 #if (CONFIG_ADM5120_NR_UARTS > 1)
489         {
490                 .iobase =       ADM5120_UART_BASE1,
491                 .irq =          ADM5120_UART_IRQ1,
492                 .uartclk =      ADM5120_UARTCLK_FREQ,
493                 .fifosize =     16,
494                 .ops =          &adm5120ser_ops,
495                 .line =         1,
496                 .flags =        ASYNC_BOOT_AUTOCONF,
497         },
498 #endif
499 };
500
501 static struct uart_driver adm5120ser_reg = {
502         .owner  =       THIS_MODULE,
503         .driver_name =  "ttyS",
504         .dev_name =     "ttyS",
505         .major =        TTY_MAJOR,
506         .minor =        64,
507         .nr =           CONFIG_ADM5120_NR_UARTS,
508         .cons =         &adm5120_serconsole,
509 };
510
511 static int __init adm5120ser_init(void)
512 {
513         int ret, i;
514
515         ret = uart_register_driver(&adm5120ser_reg);
516         if (!ret) {
517                 for (i = 0; i < CONFIG_ADM5120_NR_UARTS; i++)
518                         uart_add_one_port(&adm5120ser_reg, &adm5120ser_ports[i]);
519         }
520
521         return ret;
522 }
523
524 __initcall(adm5120ser_init);