1 /* drivers/serial/serial_lh7a40x.c
3 * Copyright (C) 2004 Coastal Environmental Systems
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.
11 /* Driver for Sharp LH7A40X embedded serial ports
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.
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.
25 * For simplicity, we disable the IR functions of any UART whenever
30 #include <linux/config.h>
32 #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
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>
53 #define ISR_LOOP_LIMIT 256
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)
60 #define UART_REG_SIZE 32
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)
71 #define UARTEN (0x01) /* UART enable */
72 #define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
74 #define RxEmpty (0x10)
75 #define TxEmpty (0x80)
77 #define nRxRdy RxEmpty
81 #define RxBreak (0x0800)
82 #define RxOverrunError (0x0400)
83 #define RxParityError (0x0200)
84 #define RxFramingError (0x0100)
85 #define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
93 #define ModemInt (0x04)
94 #define RxTimeoutInt (0x08)
100 #define WLEN_6 (0x20)
101 #define WLEN_5 (0x00)
102 #define WLEN (0x60) /* Mask for all word-length bits */
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 */
110 struct uart_port_lh7a40x {
111 struct uart_port port;
112 unsigned int statusPrev; /* Most recently read modem status */
115 static void lh7a40xuart_stop_tx (struct uart_port* port)
117 BIT_CLR (port, UART_R_INTEN, TxInt);
120 static void lh7a40xuart_start_tx (struct uart_port* port)
122 BIT_SET (port, UART_R_INTEN, TxInt);
124 /* *** FIXME: do I need to check for startup of the
125 transmitter? The old driver did, but AMBA
129 static void lh7a40xuart_stop_rx (struct uart_port* port)
131 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
134 static void lh7a40xuart_enable_ms (struct uart_port* port)
136 BIT_SET (port, UART_R_INTEN, ModemInt);
141 lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
143 lh7a40xuart_rx_chars (struct uart_port* port)
146 struct tty_struct* tty = port->info->tty;
147 int cbRxMax = 256; /* (Gross) limit on receive */
148 unsigned int data, flag;/* Received data and status */
150 while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
151 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
152 if (tty->low_latency)
153 tty_flip_buffer_push(tty);
155 * If this failed then we will throw away the
156 * bytes but must do so to clear interrupts
160 data = UR (port, UART_R_DATA);
164 if (unlikely(data & RxError)) { /* Quick check, short-circuit */
165 if (data & RxBreak) {
166 data &= ~(RxFramingError | RxParityError);
168 if (uart_handle_break (port))
171 else if (data & RxParityError)
172 ++port->icount.parity;
173 else if (data & RxFramingError)
174 ++port->icount.frame;
175 if (data & RxOverrunError)
176 ++port->icount.overrun;
178 /* Mask by termios, leave Rx'd byte */
179 data &= port->read_status_mask | 0xff;
183 else if (data & RxParityError)
185 else if (data & RxFramingError)
189 if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
192 uart_insert_char(port, data, RxOverrunError, data, flag);
194 tty_flip_buffer_push (tty);
198 static void lh7a40xuart_tx_chars (struct uart_port* port)
200 struct circ_buf* xmit = &port->info->xmit;
201 int cbTxMax = port->fifosize;
204 UR (port, UART_R_DATA) = port->x_char;
209 if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
210 lh7a40xuart_stop_tx (port);
214 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
215 that at least half of the FIFO is empty. Instead, we check
216 status for every character. Using the AMBA method causes
217 the transmitter to drop characters. */
220 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
221 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
223 if (uart_circ_empty(xmit))
225 } while (!(UR (port, UART_R_STATUS) & nTxRdy)
228 if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
229 uart_write_wakeup (port);
231 if (uart_circ_empty (xmit))
232 lh7a40xuart_stop_tx (port);
235 static void lh7a40xuart_modem_status (struct uart_port* port)
237 unsigned int status = UR (port, UART_R_STATUS);
239 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
241 BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
243 if (!delta) /* Only happens if we missed 2 transitions */
246 ((struct uart_port_lh7a40x*) port)->statusPrev = status;
249 uart_handle_dcd_change (port, status & DCD);
255 uart_handle_cts_change (port, status & CTS);
257 wake_up_interruptible (&port->info->delta_msr_wait);
260 static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
261 struct pt_regs* regs)
263 struct uart_port* port = dev_id;
264 unsigned int cLoopLimit = ISR_LOOP_LIMIT;
265 unsigned int isr = UR (port, UART_R_ISR);
269 if (isr & (RxInt | RxTimeoutInt))
271 lh7a40xuart_rx_chars(port, regs);
273 lh7a40xuart_rx_chars(port);
276 lh7a40xuart_modem_status (port);
278 lh7a40xuart_tx_chars (port);
280 if (--cLoopLimit == 0)
283 isr = UR (port, UART_R_ISR);
284 } while (isr & (RxInt | TxInt | RxTimeoutInt));
289 static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
291 return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
294 static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
296 unsigned int result = 0;
297 unsigned int status = UR (port, UART_R_STATUS);
309 static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
311 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
312 /* Note, kernel appears to be setting DTR and RTS on console. */
314 /* *** FIXME: this deserves more work. There's some work in
315 tracing all of the IO pins. */
317 if( port->mapbase == UART1_PHYS) {
318 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
320 if (mctrl & TIOCM_RTS)
321 gpio->pbdr &= ~GPIOB_UART1_RTS;
323 gpio->pbdr |= GPIOB_UART1_RTS;
328 static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
332 spin_lock_irqsave(&port->lock, flags);
333 if (break_state == -1)
334 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
336 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
337 spin_unlock_irqrestore(&port->lock, flags);
340 static int lh7a40xuart_startup (struct uart_port* port)
344 retval = request_irq (port->irq, lh7a40xuart_int, 0,
345 "serial_lh7a40x", port);
349 /* Initial modem control-line settings */
350 ((struct uart_port_lh7a40x*) port)->statusPrev
351 = UR (port, UART_R_STATUS);
353 /* There is presently no configuration option to enable IR.
354 Thus, we always disable it. */
356 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
357 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
362 static void lh7a40xuart_shutdown (struct uart_port* port)
364 free_irq (port->irq, port);
365 BIT_CLR (port, UART_R_FCON, BRK | FEN);
366 BIT_CLR (port, UART_R_CON, UARTEN);
369 static void lh7a40xuart_set_termios (struct uart_port* port,
370 struct termios* termios,
380 baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
381 quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
383 switch (termios->c_cflag & CSIZE) {
398 if (termios->c_cflag & CSTOPB)
400 if (termios->c_cflag & PARENB) {
402 if (!(termios->c_cflag & PARODD))
405 if (port->fifosize > 1)
408 spin_lock_irqsave (&port->lock, flags);
410 uart_update_timeout (port, termios->c_cflag, baud);
412 port->read_status_mask = RxOverrunError;
413 if (termios->c_iflag & INPCK)
414 port->read_status_mask |= RxFramingError | RxParityError;
415 if (termios->c_iflag & (BRKINT | PARMRK))
416 port->read_status_mask |= RxBreak;
418 /* Figure mask for status we ignore */
419 port->ignore_status_mask = 0;
420 if (termios->c_iflag & IGNPAR)
421 port->ignore_status_mask |= RxFramingError | RxParityError;
422 if (termios->c_iflag & IGNBRK) {
423 port->ignore_status_mask |= RxBreak;
424 /* Ignore overrun when ignorning parity */
425 /* *** FIXME: is this in the right place? */
426 if (termios->c_iflag & IGNPAR)
427 port->ignore_status_mask |= RxOverrunError;
430 /* Ignore all receive errors when receive disabled */
431 if ((termios->c_cflag & CREAD) == 0)
432 port->ignore_status_mask |= RxError;
434 con = UR (port, UART_R_CON);
435 inten = (UR (port, UART_R_INTEN) & ~ModemInt);
437 if (UART_ENABLE_MS (port, termios->c_cflag))
440 BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
441 UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
442 UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
443 UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
444 UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
445 UR (port, UART_R_CON) = con; /* Restore UART mode */
447 spin_unlock_irqrestore(&port->lock, flags);
450 static const char* lh7a40xuart_type (struct uart_port* port)
452 return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
455 static void lh7a40xuart_release_port (struct uart_port* port)
457 release_mem_region (port->mapbase, UART_REG_SIZE);
460 static int lh7a40xuart_request_port (struct uart_port* port)
462 return request_mem_region (port->mapbase, UART_REG_SIZE,
463 "serial_lh7a40x") != NULL
467 static void lh7a40xuart_config_port (struct uart_port* port, int flags)
469 if (flags & UART_CONFIG_TYPE) {
470 port->type = PORT_LH7A40X;
471 lh7a40xuart_request_port (port);
475 static int lh7a40xuart_verify_port (struct uart_port* port,
476 struct serial_struct* ser)
480 if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
482 if (ser->irq < 0 || ser->irq >= NR_IRQS)
484 if (ser->baud_base < 9600) /* *** FIXME: is this true? */
489 static struct uart_ops lh7a40x_uart_ops = {
490 .tx_empty = lh7a40xuart_tx_empty,
491 .set_mctrl = lh7a40xuart_set_mctrl,
492 .get_mctrl = lh7a40xuart_get_mctrl,
493 .stop_tx = lh7a40xuart_stop_tx,
494 .start_tx = lh7a40xuart_start_tx,
495 .stop_rx = lh7a40xuart_stop_rx,
496 .enable_ms = lh7a40xuart_enable_ms,
497 .break_ctl = lh7a40xuart_break_ctl,
498 .startup = lh7a40xuart_startup,
499 .shutdown = lh7a40xuart_shutdown,
500 .set_termios = lh7a40xuart_set_termios,
501 .type = lh7a40xuart_type,
502 .release_port = lh7a40xuart_release_port,
503 .request_port = lh7a40xuart_request_port,
504 .config_port = lh7a40xuart_config_port,
505 .verify_port = lh7a40xuart_verify_port,
508 static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
511 .membase = (void*) io_p2v (UART1_PHYS),
512 .mapbase = UART1_PHYS,
513 .iotype = SERIAL_IO_MEM,
514 .irq = IRQ_UART1INTR,
515 .uartclk = 14745600/2,
517 .ops = &lh7a40x_uart_ops,
518 .flags = ASYNC_BOOT_AUTOCONF,
524 .membase = (void*) io_p2v (UART2_PHYS),
525 .mapbase = UART2_PHYS,
526 .iotype = SERIAL_IO_MEM,
527 .irq = IRQ_UART2INTR,
528 .uartclk = 14745600/2,
530 .ops = &lh7a40x_uart_ops,
531 .flags = ASYNC_BOOT_AUTOCONF,
537 .membase = (void*) io_p2v (UART3_PHYS),
538 .mapbase = UART3_PHYS,
539 .iotype = SERIAL_IO_MEM,
540 .irq = IRQ_UART3INTR,
541 .uartclk = 14745600/2,
543 .ops = &lh7a40x_uart_ops,
544 .flags = ASYNC_BOOT_AUTOCONF,
550 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
551 # define LH7A40X_CONSOLE NULL
553 # define LH7A40X_CONSOLE &lh7a40x_console
556 static void lh7a40xuart_console_write (struct console* co,
560 struct uart_port* port = &lh7a40x_ports[co->index].port;
561 unsigned int con = UR (port, UART_R_CON);
562 unsigned int inten = UR (port, UART_R_INTEN);
565 UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
566 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
568 for (; count-- > 0; ++s) {
569 while (UR (port, UART_R_STATUS) & nTxRdy)
571 UR (port, UART_R_DATA) = *s;
573 while ((UR (port, UART_R_STATUS) & TxBusy))
575 UR (port, UART_R_DATA) = '\r';
579 /* Wait until all characters are sent */
580 while (UR (port, UART_R_STATUS) & TxBusy)
583 /* Restore control and interrupt mask */
584 UR (port, UART_R_CON) = con;
585 UR (port, UART_R_INTEN) = inten;
588 static void __init lh7a40xuart_console_get_options (struct uart_port* port,
593 if (UR (port, UART_R_CON) & UARTEN) {
594 unsigned int fcon = UR (port, UART_R_FCON);
595 unsigned int quot = UR (port, UART_R_BRCON) + 1;
597 switch (fcon & (PEN | EPS)) {
598 default: *parity = 'n'; break;
599 case PEN: *parity = 'o'; break;
600 case PEN | EPS: *parity = 'e'; break;
603 switch (fcon & WLEN) {
605 case WLEN_8: *bits = 8; break;
606 case WLEN_7: *bits = 7; break;
607 case WLEN_6: *bits = 6; break;
608 case WLEN_5: *bits = 5; break;
611 *baud = port->uartclk/(16*quot);
615 static int __init lh7a40xuart_console_setup (struct console* co, char* options)
617 struct uart_port* port;
623 if (co->index >= DEV_NR) /* Bounds check on device number */
625 port = &lh7a40x_ports[co->index].port;
628 uart_parse_options (options, &baud, &parity, &bits, &flow);
630 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
632 return uart_set_options (port, co, baud, parity, bits, flow);
635 static struct uart_driver lh7a40x_reg;
636 static struct console lh7a40x_console = {
638 .write = lh7a40xuart_console_write,
639 .device = uart_console_device,
640 .setup = lh7a40xuart_console_setup,
641 .flags = CON_PRINTBUFFER,
643 .data = &lh7a40x_reg,
646 static int __init lh7a40xuart_console_init(void)
648 register_console (&lh7a40x_console);
652 console_initcall (lh7a40xuart_console_init);
656 static struct uart_driver lh7a40x_reg = {
657 .owner = THIS_MODULE,
658 .driver_name = "ttyAM",
663 .cons = LH7A40X_CONSOLE,
666 static int __init lh7a40xuart_init(void)
670 printk (KERN_INFO "serial: LH7A40X serial driver\n");
672 ret = uart_register_driver (&lh7a40x_reg);
677 for (i = 0; i < DEV_NR; i++)
678 uart_add_one_port (&lh7a40x_reg,
679 &lh7a40x_ports[i].port);
684 static void __exit lh7a40xuart_exit(void)
688 for (i = 0; i < DEV_NR; i++)
689 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
691 uart_unregister_driver (&lh7a40x_reg);
694 module_init (lh7a40xuart_init);
695 module_exit (lh7a40xuart_exit);
697 MODULE_AUTHOR ("Marc Singer");
698 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
699 MODULE_LICENSE ("GPL");