Merge git://oss.sgi.com:8090/xfs-2.6
[deliverable/linux.git] / drivers / serial / serial_lh7a40x.c
1 /* drivers/serial/serial_lh7a40x.c
2 *
3 * Copyright (C) 2004 Coastal Environmental Systems
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 */
10
11 /* Driver for Sharp LH7A40X embedded serial ports
12 *
13 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
14 * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
15 *
16 * ---
17 *
18 * This driver supports the embedded UARTs of the Sharp LH7A40X series
19 * CPUs. While similar to the 16550 and other UART chips, there is
20 * nothing close to register compatibility. Moreover, some of the
21 * modem control lines are not available, either in the chip or they
22 * are lacking in the board-level implementation.
23 *
24 * - Use of SIRDIS
25 * For simplicity, we disable the IR functions of any UART whenever
26 * we enable it.
27 *
28 */
29
30 #include <linux/config.h>
31
32 #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
33 #define SUPPORT_SYSRQ
34 #endif
35
36 #include <linux/module.h>
37 #include <linux/ioport.h>
38 #include <linux/init.h>
39 #include <linux/console.h>
40 #include <linux/sysrq.h>
41 #include <linux/tty.h>
42 #include <linux/tty_flip.h>
43 #include <linux/serial_core.h>
44 #include <linux/serial.h>
45
46 #include <asm/io.h>
47 #include <asm/irq.h>
48
49 #define DEV_MAJOR 204
50 #define DEV_MINOR 16
51 #define DEV_NR 3
52
53 #define ISR_LOOP_LIMIT 256
54
55 #define UR(p,o) _UR ((p)->membase, o)
56 #define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
57 #define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
58 #define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
59
60 #define UART_REG_SIZE 32
61
62 #define UART_R_DATA (0x00)
63 #define UART_R_FCON (0x04)
64 #define UART_R_BRCON (0x08)
65 #define UART_R_CON (0x0c)
66 #define UART_R_STATUS (0x10)
67 #define UART_R_RAWISR (0x14)
68 #define UART_R_INTEN (0x18)
69 #define UART_R_ISR (0x1c)
70
71 #define UARTEN (0x01) /* UART enable */
72 #define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
73
74 #define RxEmpty (0x10)
75 #define TxEmpty (0x80)
76 #define TxFull (0x20)
77 #define nRxRdy RxEmpty
78 #define nTxRdy TxFull
79 #define TxBusy (0x08)
80
81 #define RxBreak (0x0800)
82 #define RxOverrunError (0x0400)
83 #define RxParityError (0x0200)
84 #define RxFramingError (0x0100)
85 #define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
86
87 #define DCD (0x04)
88 #define DSR (0x02)
89 #define CTS (0x01)
90
91 #define RxInt (0x01)
92 #define TxInt (0x02)
93 #define ModemInt (0x04)
94 #define RxTimeoutInt (0x08)
95
96 #define MSEOI (0x10)
97
98 #define WLEN_8 (0x60)
99 #define WLEN_7 (0x40)
100 #define WLEN_6 (0x20)
101 #define WLEN_5 (0x00)
102 #define WLEN (0x60) /* Mask for all word-length bits */
103 #define STP2 (0x08)
104 #define PEN (0x02) /* Parity Enable */
105 #define EPS (0x04) /* Even Parity Set */
106 #define FEN (0x10) /* FIFO Enable */
107 #define BRK (0x01) /* Send Break */
108
109
110 struct uart_port_lh7a40x {
111 struct uart_port port;
112 unsigned int statusPrev; /* Most recently read modem status */
113 };
114
115 static void lh7a40xuart_stop_tx (struct uart_port* port)
116 {
117 BIT_CLR (port, UART_R_INTEN, TxInt);
118 }
119
120 static void lh7a40xuart_start_tx (struct uart_port* port)
121 {
122 BIT_SET (port, UART_R_INTEN, TxInt);
123
124 /* *** FIXME: do I need to check for startup of the
125 transmitter? The old driver did, but AMBA
126 doesn't . */
127 }
128
129 static void lh7a40xuart_stop_rx (struct uart_port* port)
130 {
131 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
132 }
133
134 static void lh7a40xuart_enable_ms (struct uart_port* port)
135 {
136 BIT_SET (port, UART_R_INTEN, ModemInt);
137 }
138
139 static void
140 #ifdef SUPPORT_SYSRQ
141 lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
142 #else
143 lh7a40xuart_rx_chars (struct uart_port* port)
144 #endif
145 {
146 struct tty_struct* tty = port->info->tty;
147 int cbRxMax = 256; /* (Gross) limit on receive */
148 unsigned int data; /* Received data and status */
149 unsigned int flag;
150
151 while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
152 data = UR (port, UART_R_DATA);
153 flag = TTY_NORMAL;
154 ++port->icount.rx;
155
156 if (unlikely(data & RxError)) {
157 if (data & RxBreak) {
158 data &= ~(RxFramingError | RxParityError);
159 ++port->icount.brk;
160 if (uart_handle_break (port))
161 continue;
162 }
163 else if (data & RxParityError)
164 ++port->icount.parity;
165 else if (data & RxFramingError)
166 ++port->icount.frame;
167 if (data & RxOverrunError)
168 ++port->icount.overrun;
169
170 /* Mask by termios, leave Rx'd byte */
171 data &= port->read_status_mask | 0xff;
172
173 if (data & RxBreak)
174 flag = TTY_BREAK;
175 else if (data & RxParityError)
176 flag = TTY_PARITY;
177 else if (data & RxFramingError)
178 flag = TTY_FRAME;
179 }
180
181 if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
182 continue;
183
184 uart_insert_char(port, data, RxOverrunError, data, flag);
185 }
186 tty_flip_buffer_push (tty);
187 return;
188 }
189
190 static void lh7a40xuart_tx_chars (struct uart_port* port)
191 {
192 struct circ_buf* xmit = &port->info->xmit;
193 int cbTxMax = port->fifosize;
194
195 if (port->x_char) {
196 UR (port, UART_R_DATA) = port->x_char;
197 ++port->icount.tx;
198 port->x_char = 0;
199 return;
200 }
201 if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
202 lh7a40xuart_stop_tx (port);
203 return;
204 }
205
206 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
207 that at least half of the FIFO is empty. Instead, we check
208 status for every character. Using the AMBA method causes
209 the transmitter to drop characters. */
210
211 do {
212 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
213 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
214 ++port->icount.tx;
215 if (uart_circ_empty(xmit))
216 break;
217 } while (!(UR (port, UART_R_STATUS) & nTxRdy)
218 && cbTxMax--);
219
220 if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
221 uart_write_wakeup (port);
222
223 if (uart_circ_empty (xmit))
224 lh7a40xuart_stop_tx (port);
225 }
226
227 static void lh7a40xuart_modem_status (struct uart_port* port)
228 {
229 unsigned int status = UR (port, UART_R_STATUS);
230 unsigned int delta
231 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
232
233 BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
234
235 if (!delta) /* Only happens if we missed 2 transitions */
236 return;
237
238 ((struct uart_port_lh7a40x*) port)->statusPrev = status;
239
240 if (delta & DCD)
241 uart_handle_dcd_change (port, status & DCD);
242
243 if (delta & DSR)
244 ++port->icount.dsr;
245
246 if (delta & CTS)
247 uart_handle_cts_change (port, status & CTS);
248
249 wake_up_interruptible (&port->info->delta_msr_wait);
250 }
251
252 static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
253 struct pt_regs* regs)
254 {
255 struct uart_port* port = dev_id;
256 unsigned int cLoopLimit = ISR_LOOP_LIMIT;
257 unsigned int isr = UR (port, UART_R_ISR);
258
259
260 do {
261 if (isr & (RxInt | RxTimeoutInt))
262 #ifdef SUPPORT_SYSRQ
263 lh7a40xuart_rx_chars(port, regs);
264 #else
265 lh7a40xuart_rx_chars(port);
266 #endif
267 if (isr & ModemInt)
268 lh7a40xuart_modem_status (port);
269 if (isr & TxInt)
270 lh7a40xuart_tx_chars (port);
271
272 if (--cLoopLimit == 0)
273 break;
274
275 isr = UR (port, UART_R_ISR);
276 } while (isr & (RxInt | TxInt | RxTimeoutInt));
277
278 return IRQ_HANDLED;
279 }
280
281 static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
282 {
283 return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
284 }
285
286 static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
287 {
288 unsigned int result = 0;
289 unsigned int status = UR (port, UART_R_STATUS);
290
291 if (status & DCD)
292 result |= TIOCM_CAR;
293 if (status & DSR)
294 result |= TIOCM_DSR;
295 if (status & CTS)
296 result |= TIOCM_CTS;
297
298 return result;
299 }
300
301 static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
302 {
303 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
304 /* Note, kernel appears to be setting DTR and RTS on console. */
305
306 /* *** FIXME: this deserves more work. There's some work in
307 tracing all of the IO pins. */
308 #if 0
309 if( port->mapbase == UART1_PHYS) {
310 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
311
312 if (mctrl & TIOCM_RTS)
313 gpio->pbdr &= ~GPIOB_UART1_RTS;
314 else
315 gpio->pbdr |= GPIOB_UART1_RTS;
316 }
317 #endif
318 }
319
320 static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
321 {
322 unsigned long flags;
323
324 spin_lock_irqsave(&port->lock, flags);
325 if (break_state == -1)
326 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
327 else
328 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
329 spin_unlock_irqrestore(&port->lock, flags);
330 }
331
332 static int lh7a40xuart_startup (struct uart_port* port)
333 {
334 int retval;
335
336 retval = request_irq (port->irq, lh7a40xuart_int, 0,
337 "serial_lh7a40x", port);
338 if (retval)
339 return retval;
340
341 /* Initial modem control-line settings */
342 ((struct uart_port_lh7a40x*) port)->statusPrev
343 = UR (port, UART_R_STATUS);
344
345 /* There is presently no configuration option to enable IR.
346 Thus, we always disable it. */
347
348 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
349 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
350
351 return 0;
352 }
353
354 static void lh7a40xuart_shutdown (struct uart_port* port)
355 {
356 free_irq (port->irq, port);
357 BIT_CLR (port, UART_R_FCON, BRK | FEN);
358 BIT_CLR (port, UART_R_CON, UARTEN);
359 }
360
361 static void lh7a40xuart_set_termios (struct uart_port* port,
362 struct termios* termios,
363 struct termios* old)
364 {
365 unsigned int con;
366 unsigned int inten;
367 unsigned int fcon;
368 unsigned long flags;
369 unsigned int baud;
370 unsigned int quot;
371
372 baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
373 quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
374
375 switch (termios->c_cflag & CSIZE) {
376 case CS5:
377 fcon = WLEN_5;
378 break;
379 case CS6:
380 fcon = WLEN_6;
381 break;
382 case CS7:
383 fcon = WLEN_7;
384 break;
385 case CS8:
386 default:
387 fcon = WLEN_8;
388 break;
389 }
390 if (termios->c_cflag & CSTOPB)
391 fcon |= STP2;
392 if (termios->c_cflag & PARENB) {
393 fcon |= PEN;
394 if (!(termios->c_cflag & PARODD))
395 fcon |= EPS;
396 }
397 if (port->fifosize > 1)
398 fcon |= FEN;
399
400 spin_lock_irqsave (&port->lock, flags);
401
402 uart_update_timeout (port, termios->c_cflag, baud);
403
404 port->read_status_mask = RxOverrunError;
405 if (termios->c_iflag & INPCK)
406 port->read_status_mask |= RxFramingError | RxParityError;
407 if (termios->c_iflag & (BRKINT | PARMRK))
408 port->read_status_mask |= RxBreak;
409
410 /* Figure mask for status we ignore */
411 port->ignore_status_mask = 0;
412 if (termios->c_iflag & IGNPAR)
413 port->ignore_status_mask |= RxFramingError | RxParityError;
414 if (termios->c_iflag & IGNBRK) {
415 port->ignore_status_mask |= RxBreak;
416 /* Ignore overrun when ignorning parity */
417 /* *** FIXME: is this in the right place? */
418 if (termios->c_iflag & IGNPAR)
419 port->ignore_status_mask |= RxOverrunError;
420 }
421
422 /* Ignore all receive errors when receive disabled */
423 if ((termios->c_cflag & CREAD) == 0)
424 port->ignore_status_mask |= RxError;
425
426 con = UR (port, UART_R_CON);
427 inten = (UR (port, UART_R_INTEN) & ~ModemInt);
428
429 if (UART_ENABLE_MS (port, termios->c_cflag))
430 inten |= ModemInt;
431
432 BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
433 UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
434 UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
435 UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
436 UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
437 UR (port, UART_R_CON) = con; /* Restore UART mode */
438
439 spin_unlock_irqrestore(&port->lock, flags);
440 }
441
442 static const char* lh7a40xuart_type (struct uart_port* port)
443 {
444 return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
445 }
446
447 static void lh7a40xuart_release_port (struct uart_port* port)
448 {
449 release_mem_region (port->mapbase, UART_REG_SIZE);
450 }
451
452 static int lh7a40xuart_request_port (struct uart_port* port)
453 {
454 return request_mem_region (port->mapbase, UART_REG_SIZE,
455 "serial_lh7a40x") != NULL
456 ? 0 : -EBUSY;
457 }
458
459 static void lh7a40xuart_config_port (struct uart_port* port, int flags)
460 {
461 if (flags & UART_CONFIG_TYPE) {
462 port->type = PORT_LH7A40X;
463 lh7a40xuart_request_port (port);
464 }
465 }
466
467 static int lh7a40xuart_verify_port (struct uart_port* port,
468 struct serial_struct* ser)
469 {
470 int ret = 0;
471
472 if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
473 ret = -EINVAL;
474 if (ser->irq < 0 || ser->irq >= NR_IRQS)
475 ret = -EINVAL;
476 if (ser->baud_base < 9600) /* *** FIXME: is this true? */
477 ret = -EINVAL;
478 return ret;
479 }
480
481 static struct uart_ops lh7a40x_uart_ops = {
482 .tx_empty = lh7a40xuart_tx_empty,
483 .set_mctrl = lh7a40xuart_set_mctrl,
484 .get_mctrl = lh7a40xuart_get_mctrl,
485 .stop_tx = lh7a40xuart_stop_tx,
486 .start_tx = lh7a40xuart_start_tx,
487 .stop_rx = lh7a40xuart_stop_rx,
488 .enable_ms = lh7a40xuart_enable_ms,
489 .break_ctl = lh7a40xuart_break_ctl,
490 .startup = lh7a40xuart_startup,
491 .shutdown = lh7a40xuart_shutdown,
492 .set_termios = lh7a40xuart_set_termios,
493 .type = lh7a40xuart_type,
494 .release_port = lh7a40xuart_release_port,
495 .request_port = lh7a40xuart_request_port,
496 .config_port = lh7a40xuart_config_port,
497 .verify_port = lh7a40xuart_verify_port,
498 };
499
500 static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
501 {
502 .port = {
503 .membase = (void*) io_p2v (UART1_PHYS),
504 .mapbase = UART1_PHYS,
505 .iotype = UPIO_MEM,
506 .irq = IRQ_UART1INTR,
507 .uartclk = 14745600/2,
508 .fifosize = 16,
509 .ops = &lh7a40x_uart_ops,
510 .flags = UPF_BOOT_AUTOCONF,
511 .line = 0,
512 },
513 },
514 {
515 .port = {
516 .membase = (void*) io_p2v (UART2_PHYS),
517 .mapbase = UART2_PHYS,
518 .iotype = UPIO_MEM,
519 .irq = IRQ_UART2INTR,
520 .uartclk = 14745600/2,
521 .fifosize = 16,
522 .ops = &lh7a40x_uart_ops,
523 .flags = UPF_BOOT_AUTOCONF,
524 .line = 1,
525 },
526 },
527 {
528 .port = {
529 .membase = (void*) io_p2v (UART3_PHYS),
530 .mapbase = UART3_PHYS,
531 .iotype = UPIO_MEM,
532 .irq = IRQ_UART3INTR,
533 .uartclk = 14745600/2,
534 .fifosize = 16,
535 .ops = &lh7a40x_uart_ops,
536 .flags = UPF_BOOT_AUTOCONF,
537 .line = 2,
538 },
539 },
540 };
541
542 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
543 # define LH7A40X_CONSOLE NULL
544 #else
545 # define LH7A40X_CONSOLE &lh7a40x_console
546
547 static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
548 {
549 while (UR(port, UART_R_STATUS) & nTxRdy)
550 ;
551 UR(port, UART_R_DATA) = ch;
552 }
553
554 static void lh7a40xuart_console_write (struct console* co,
555 const char* s,
556 unsigned int count)
557 {
558 struct uart_port* port = &lh7a40x_ports[co->index].port;
559 unsigned int con = UR (port, UART_R_CON);
560 unsigned int inten = UR (port, UART_R_INTEN);
561
562
563 UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
564 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
565
566 uart_console_write(port, s, count, lh7a40xuart_console_putchar);
567
568 /* Wait until all characters are sent */
569 while (UR (port, UART_R_STATUS) & TxBusy)
570 ;
571
572 /* Restore control and interrupt mask */
573 UR (port, UART_R_CON) = con;
574 UR (port, UART_R_INTEN) = inten;
575 }
576
577 static void __init lh7a40xuart_console_get_options (struct uart_port* port,
578 int* baud,
579 int* parity,
580 int* bits)
581 {
582 if (UR (port, UART_R_CON) & UARTEN) {
583 unsigned int fcon = UR (port, UART_R_FCON);
584 unsigned int quot = UR (port, UART_R_BRCON) + 1;
585
586 switch (fcon & (PEN | EPS)) {
587 default: *parity = 'n'; break;
588 case PEN: *parity = 'o'; break;
589 case PEN | EPS: *parity = 'e'; break;
590 }
591
592 switch (fcon & WLEN) {
593 default:
594 case WLEN_8: *bits = 8; break;
595 case WLEN_7: *bits = 7; break;
596 case WLEN_6: *bits = 6; break;
597 case WLEN_5: *bits = 5; break;
598 }
599
600 *baud = port->uartclk/(16*quot);
601 }
602 }
603
604 static int __init lh7a40xuart_console_setup (struct console* co, char* options)
605 {
606 struct uart_port* port;
607 int baud = 38400;
608 int bits = 8;
609 int parity = 'n';
610 int flow = 'n';
611
612 if (co->index >= DEV_NR) /* Bounds check on device number */
613 co->index = 0;
614 port = &lh7a40x_ports[co->index].port;
615
616 if (options)
617 uart_parse_options (options, &baud, &parity, &bits, &flow);
618 else
619 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
620
621 return uart_set_options (port, co, baud, parity, bits, flow);
622 }
623
624 static struct uart_driver lh7a40x_reg;
625 static struct console lh7a40x_console = {
626 .name = "ttyAM",
627 .write = lh7a40xuart_console_write,
628 .device = uart_console_device,
629 .setup = lh7a40xuart_console_setup,
630 .flags = CON_PRINTBUFFER,
631 .index = -1,
632 .data = &lh7a40x_reg,
633 };
634
635 static int __init lh7a40xuart_console_init(void)
636 {
637 register_console (&lh7a40x_console);
638 return 0;
639 }
640
641 console_initcall (lh7a40xuart_console_init);
642
643 #endif
644
645 static struct uart_driver lh7a40x_reg = {
646 .owner = THIS_MODULE,
647 .driver_name = "ttyAM",
648 .dev_name = "ttyAM",
649 .major = DEV_MAJOR,
650 .minor = DEV_MINOR,
651 .nr = DEV_NR,
652 .cons = LH7A40X_CONSOLE,
653 };
654
655 static int __init lh7a40xuart_init(void)
656 {
657 int ret;
658
659 printk (KERN_INFO "serial: LH7A40X serial driver\n");
660
661 ret = uart_register_driver (&lh7a40x_reg);
662
663 if (ret == 0) {
664 int i;
665
666 for (i = 0; i < DEV_NR; i++) {
667 /* UART3, when used, requires GPIO pin reallocation */
668 if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
669 GPIO_PINMUX |= 1<<3;
670 uart_add_one_port (&lh7a40x_reg,
671 &lh7a40x_ports[i].port);
672 }
673 }
674 return ret;
675 }
676
677 static void __exit lh7a40xuart_exit(void)
678 {
679 int i;
680
681 for (i = 0; i < DEV_NR; i++)
682 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
683
684 uart_unregister_driver (&lh7a40x_reg);
685 }
686
687 module_init (lh7a40xuart_init);
688 module_exit (lh7a40xuart_exit);
689
690 MODULE_AUTHOR ("Marc Singer");
691 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
692 MODULE_LICENSE ("GPL");
This page took 0.044345 seconds and 6 git commands to generate.