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