[PATCH] janitor: mark __init/__exit static drivers/net/ppp_deflate
[linux-2.6/history.git] / drivers / serial / serial_lh7a40x.c
blobd863368e45e2a1349b13ad7234818e9cd4b82904
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.
9 */
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.
16 * ---
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.
24 * - Use of SIRDIS
25 * For simplicity, we disable the IR functions of any UART whenever
26 * we enable it.
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/tty.h>
33 #include <linux/ioport.h>
34 #include <linux/init.h>
35 #include <linux/serial.h>
36 #include <linux/console.h>
37 #include <linux/sysrq.h>
39 #include <asm/io.h>
40 #include <asm/irq.h>
42 #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
43 #define SUPPORT_SYSRQ
44 #endif
46 #include <linux/serial_core.h>
48 #include <asm/arch/serial.h>
50 #define DEV_MAJOR 204
51 #define DEV_MINOR 16
52 #define DEV_NR 3
54 #define ISR_LOOP_LIMIT 256
56 #define UR(p,o) _UR ((p)->membase, o)
57 #define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
58 #define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
59 #define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
61 #define UART_REG_SIZE 32
63 #define UARTEN (0x01) /* UART enable */
64 #define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
66 #define RxEmpty (0x10)
67 #define TxEmpty (0x80)
68 #define TxFull (0x20)
69 #define nRxRdy RxEmpty
70 #define nTxRdy TxFull
71 #define TxBusy (0x08)
73 #define RxBreak (0x0800)
74 #define RxOverrunError (0x0400)
75 #define RxParityError (0x0200)
76 #define RxFramingError (0x0100)
77 #define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
79 #define DCD (0x04)
80 #define DSR (0x02)
81 #define CTS (0x01)
83 #define RxInt (0x01)
84 #define TxInt (0x02)
85 #define ModemInt (0x04)
86 #define RxTimeoutInt (0x08)
88 #define MSEOI (0x10)
90 #define WLEN_8 (0x60)
91 #define WLEN_7 (0x40)
92 #define WLEN_6 (0x20)
93 #define WLEN_5 (0x00)
94 #define WLEN (0x60) /* Mask for all word-length bits */
95 #define STP2 (0x08)
96 #define PEN (0x02) /* Parity Enable */
97 #define EPS (0x04) /* Even Parity Set */
98 #define FEN (0x10) /* FIFO Enable */
99 #define BRK (0x01) /* Send Break */
102 struct uart_port_lh7a40x {
103 struct uart_port port;
104 unsigned int statusPrev; /* Most recently read modem status */
107 static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
109 BIT_CLR (port, UART_R_INTEN, TxInt);
112 static void lh7a40xuart_start_tx (struct uart_port* port,
113 unsigned int tty_start)
115 BIT_SET (port, UART_R_INTEN, TxInt);
117 /* *** FIXME: do I need to check for startup of the
118 transmitter? The old driver did, but AMBA
119 doesn't . */
122 static void lh7a40xuart_stop_rx (struct uart_port* port)
124 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
127 static void lh7a40xuart_enable_ms (struct uart_port* port)
129 BIT_SET (port, UART_R_INTEN, ModemInt);
132 static void
133 #ifdef SUPPORT_SYSRQ
134 lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
135 #else
136 lh7a40xuart_rx_chars (struct uart_port* port)
137 #endif
139 struct tty_struct* tty = port->info->tty;
140 int cbRxMax = 256; /* (Gross) limit on receive */
141 unsigned int data; /* Received data and status */
143 while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
144 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
145 tty->flip.work.func((void*)tty);
146 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
147 printk(KERN_WARNING "TTY_DONT_FLIP set\n");
148 return;
152 data = UR (port, UART_R_DATA);
154 *tty->flip.char_buf_ptr = (unsigned char) data;
155 *tty->flip.flag_buf_ptr = TTY_NORMAL;
156 ++port->icount.rx;
158 if (data & RxError) { /* Quick check, short-circuit */
159 if (data & RxBreak) {
160 data &= ~(RxFramingError | RxParityError);
161 ++port->icount.brk;
162 if (uart_handle_break (port))
163 continue;
165 else if (data & RxParityError)
166 ++port->icount.parity;
167 else if (data & RxFramingError)
168 ++port->icount.frame;
169 if (data & RxOverrunError)
170 ++port->icount.overrun;
172 /* Mask by termios, leave Rx'd byte */
173 data &= port->read_status_mask | 0xff;
175 if (data & RxBreak)
176 *tty->flip.flag_buf_ptr = TTY_BREAK;
177 else if (data & RxParityError)
178 *tty->flip.flag_buf_ptr = TTY_PARITY;
179 else if (data & RxFramingError)
180 *tty->flip.flag_buf_ptr = TTY_FRAME;
183 if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
184 continue;
186 if ((data & port->ignore_status_mask) == 0) {
187 ++tty->flip.flag_buf_ptr;
188 ++tty->flip.char_buf_ptr;
189 ++tty->flip.count;
191 if ((data & RxOverrunError)
192 && tty->flip.count < TTY_FLIPBUF_SIZE) {
194 * Overrun is special, since it's reported
195 * immediately, and doesn't affect the current
196 * character
198 *tty->flip.char_buf_ptr++ = 0;
199 *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
200 ++tty->flip.count;
203 tty_flip_buffer_push (tty);
204 return;
207 static void lh7a40xuart_tx_chars (struct uart_port* port)
209 struct circ_buf* xmit = &port->info->xmit;
210 int cbTxMax = port->fifosize;
212 if (port->x_char) {
213 UR (port, UART_R_DATA) = port->x_char;
214 ++port->icount.tx;
215 port->x_char = 0;
216 return;
218 if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
219 lh7a40xuart_stop_tx (port, 0);
220 return;
223 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
224 that at least half of the FIFO is empty. Instead, we check
225 status for every character. Using the AMBA method causes
226 the transmitter to drop characters. */
228 do {
229 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
230 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
231 ++port->icount.tx;
232 if (uart_circ_empty(xmit))
233 break;
234 } while (!(UR (port, UART_R_STATUS) & nTxRdy)
235 && cbTxMax--);
237 if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
238 uart_write_wakeup (port);
240 if (uart_circ_empty (xmit))
241 lh7a40xuart_stop_tx (port, 0);
244 static void lh7a40xuart_modem_status (struct uart_port* port)
246 unsigned int status = UR (port, UART_R_STATUS);
247 unsigned int delta
248 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
250 BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
252 if (!delta) /* Only happens if we missed 2 transitions */
253 return;
255 ((struct uart_port_lh7a40x*) port)->statusPrev = status;
257 if (delta & DCD)
258 uart_handle_dcd_change (port, status & DCD);
260 if (delta & DSR)
261 ++port->icount.dsr;
263 if (delta & CTS)
264 uart_handle_cts_change (port, status & CTS);
266 wake_up_interruptible (&port->info->delta_msr_wait);
269 static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
270 struct pt_regs* regs)
272 struct uart_port* port = dev_id;
273 unsigned int cLoopLimit = ISR_LOOP_LIMIT;
274 unsigned int isr = UR (port, UART_R_ISR);
277 do {
278 if (isr & (RxInt | RxTimeoutInt))
279 #ifdef SUPPORT_SYSRQ
280 lh7a40xuart_rx_chars(port, regs);
281 #else
282 lh7a40xuart_rx_chars(port);
283 #endif
284 if (isr & ModemInt)
285 lh7a40xuart_modem_status (port);
286 if (isr & TxInt)
287 lh7a40xuart_tx_chars (port);
289 if (--cLoopLimit == 0)
290 break;
292 isr = UR (port, UART_R_ISR);
293 } while (isr & (RxInt | TxInt | RxTimeoutInt));
295 return IRQ_HANDLED;
298 static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
300 return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
303 static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
305 unsigned int result = 0;
306 unsigned int status = UR (port, UART_R_STATUS);
308 if (status & DCD)
309 result |= TIOCM_CAR;
310 if (status & DSR)
311 result |= TIOCM_DSR;
312 if (status & CTS)
313 result |= TIOCM_CTS;
315 return result;
318 static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
320 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
321 /* Note, kernel appears to be setting DTR and RTS on console. */
323 /* *** FIXME: this deserves more work. There's some work in
324 tracing all of the IO pins. */
325 #if 0
326 if( port->mapbase == UART1_PHYS) {
327 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
329 if (mctrl & TIOCM_RTS)
330 gpio->pbdr &= ~GPIOB_UART1_RTS;
331 else
332 gpio->pbdr |= GPIOB_UART1_RTS;
334 #endif
337 static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
339 unsigned long flags;
341 spin_lock_irqsave(&port->lock, flags);
342 if (break_state == -1)
343 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
344 else
345 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
346 spin_unlock_irqrestore(&port->lock, flags);
349 static int lh7a40xuart_startup (struct uart_port* port)
351 int retval;
353 retval = request_irq (port->irq, lh7a40xuart_int, 0,
354 "serial_lh7a40x", port);
355 if (retval)
356 return retval;
358 /* Initial modem control-line settings */
359 ((struct uart_port_lh7a40x*) port)->statusPrev
360 = UR (port, UART_R_STATUS);
362 /* There is presently no configuration option to enable IR.
363 Thus, we always disable it. */
365 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
366 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
368 return 0;
371 static void lh7a40xuart_shutdown (struct uart_port* port)
373 free_irq (port->irq, port);
374 BIT_CLR (port, UART_R_FCON, BRK | FEN);
375 BIT_CLR (port, UART_R_CON, UARTEN);
378 static void lh7a40xuart_set_termios (struct uart_port* port,
379 struct termios* termios,
380 struct termios* old)
382 unsigned int con;
383 unsigned int inten;
384 unsigned int fcon;
385 unsigned long flags;
386 unsigned int baud;
387 unsigned int quot;
389 baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
390 quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
392 switch (termios->c_cflag & CSIZE) {
393 case CS5:
394 fcon = WLEN_5;
395 break;
396 case CS6:
397 fcon = WLEN_6;
398 break;
399 case CS7:
400 fcon = WLEN_7;
401 break;
402 case CS8:
403 default:
404 fcon = WLEN_8;
405 break;
407 if (termios->c_cflag & CSTOPB)
408 fcon |= STP2;
409 if (termios->c_cflag & PARENB) {
410 fcon |= PEN;
411 if (!(termios->c_cflag & PARODD))
412 fcon |= EPS;
414 if (port->fifosize > 1)
415 fcon |= FEN;
417 spin_lock_irqsave (&port->lock, flags);
419 uart_update_timeout (port, termios->c_cflag, baud);
421 port->read_status_mask = RxOverrunError;
422 if (termios->c_iflag & INPCK)
423 port->read_status_mask |= RxFramingError | RxParityError;
424 if (termios->c_iflag & (BRKINT | PARMRK))
425 port->read_status_mask |= RxBreak;
427 /* Figure mask for status we ignore */
428 port->ignore_status_mask = 0;
429 if (termios->c_iflag & IGNPAR)
430 port->ignore_status_mask |= RxFramingError | RxParityError;
431 if (termios->c_iflag & IGNBRK) {
432 port->ignore_status_mask |= RxBreak;
433 /* Ignore overrun when ignorning parity */
434 /* *** FIXME: is this in the right place? */
435 if (termios->c_iflag & IGNPAR)
436 port->ignore_status_mask |= RxOverrunError;
439 /* Ignore all receive errors when receive disabled */
440 if ((termios->c_cflag & CREAD) == 0)
441 port->ignore_status_mask |= RxError;
443 con = UR (port, UART_R_CON);
444 inten = (UR (port, UART_R_INTEN) & ~ModemInt);
446 if (UART_ENABLE_MS (port, termios->c_cflag))
447 inten |= ModemInt;
449 BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
450 UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
451 UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
452 UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
453 UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
454 UR (port, UART_R_CON) = con; /* Restore UART mode */
456 spin_unlock_irqrestore(&port->lock, flags);
459 static const char* lh7a40xuart_type (struct uart_port* port)
461 return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
464 static void lh7a40xuart_release_port (struct uart_port* port)
466 release_mem_region (port->mapbase, UART_REG_SIZE);
469 static int lh7a40xuart_request_port (struct uart_port* port)
471 return request_mem_region (port->mapbase, UART_REG_SIZE,
472 "serial_lh7a40x") != NULL
473 ? 0 : -EBUSY;
476 static void lh7a40xuart_config_port (struct uart_port* port, int flags)
478 if (flags & UART_CONFIG_TYPE) {
479 port->type = PORT_LH7A40X;
480 lh7a40xuart_request_port (port);
484 static int lh7a40xuart_verify_port (struct uart_port* port,
485 struct serial_struct* ser)
487 int ret = 0;
489 if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
490 ret = -EINVAL;
491 if (ser->irq < 0 || ser->irq >= NR_IRQS)
492 ret = -EINVAL;
493 if (ser->baud_base < 9600) /* *** FIXME: is this true? */
494 ret = -EINVAL;
495 return ret;
498 static struct uart_ops lh7a40x_uart_ops = {
499 .tx_empty = lh7a40xuart_tx_empty,
500 .set_mctrl = lh7a40xuart_set_mctrl,
501 .get_mctrl = lh7a40xuart_get_mctrl,
502 .stop_tx = lh7a40xuart_stop_tx,
503 .start_tx = lh7a40xuart_start_tx,
504 .stop_rx = lh7a40xuart_stop_rx,
505 .enable_ms = lh7a40xuart_enable_ms,
506 .break_ctl = lh7a40xuart_break_ctl,
507 .startup = lh7a40xuart_startup,
508 .shutdown = lh7a40xuart_shutdown,
509 .set_termios = lh7a40xuart_set_termios,
510 .type = lh7a40xuart_type,
511 .release_port = lh7a40xuart_release_port,
512 .request_port = lh7a40xuart_request_port,
513 .config_port = lh7a40xuart_config_port,
514 .verify_port = lh7a40xuart_verify_port,
517 static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
519 .port = {
520 .membase = (void*) io_p2v (UART1_PHYS),
521 .mapbase = UART1_PHYS,
522 .iotype = SERIAL_IO_MEM,
523 .irq = IRQ_UART1INTR,
524 .uartclk = 14745600/2,
525 .fifosize = 16,
526 .ops = &lh7a40x_uart_ops,
527 .flags = ASYNC_BOOT_AUTOCONF,
528 .line = 0,
532 .port = {
533 .membase = (void*) io_p2v (UART2_PHYS),
534 .mapbase = UART2_PHYS,
535 .iotype = SERIAL_IO_MEM,
536 .irq = IRQ_UART2INTR,
537 .uartclk = 14745600/2,
538 .fifosize = 16,
539 .ops = &lh7a40x_uart_ops,
540 .flags = ASYNC_BOOT_AUTOCONF,
541 .line = 1,
545 .port = {
546 .membase = (void*) io_p2v (UART3_PHYS),
547 .mapbase = UART3_PHYS,
548 .iotype = SERIAL_IO_MEM,
549 .irq = IRQ_UART3INTR,
550 .uartclk = 14745600/2,
551 .fifosize = 16,
552 .ops = &lh7a40x_uart_ops,
553 .flags = ASYNC_BOOT_AUTOCONF,
554 .line = 2,
559 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
560 # define LH7A40X_CONSOLE NULL
561 #else
562 # define LH7A40X_CONSOLE &lh7a40x_console
565 static void lh7a40xuart_console_write (struct console* co,
566 const char* s,
567 unsigned int count)
569 struct uart_port* port = &lh7a40x_ports[co->index].port;
570 unsigned int con = UR (port, UART_R_CON);
571 unsigned int inten = UR (port, UART_R_INTEN);
574 UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
575 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
577 for (; count-- > 0; ++s) {
578 while (UR (port, UART_R_STATUS) & nTxRdy)
580 UR (port, UART_R_DATA) = *s;
581 if (*s == '\n') {
582 while ((UR (port, UART_R_STATUS) & TxBusy))
584 UR (port, UART_R_DATA) = '\r';
588 /* Wait until all characters are sent */
589 while (UR (port, UART_R_STATUS) & TxBusy)
592 /* Restore control and interrupt mask */
593 UR (port, UART_R_CON) = con;
594 UR (port, UART_R_INTEN) = inten;
597 static void __init lh7a40xuart_console_get_options (struct uart_port* port,
598 int* baud,
599 int* parity,
600 int* bits)
602 if (UR (port, UART_R_CON) & UARTEN) {
603 unsigned int fcon = UR (port, UART_R_FCON);
604 unsigned int quot = UR (port, UART_R_BRCON) + 1;
606 switch (fcon & (PEN | EPS)) {
607 default: *parity = 'n'; break;
608 case PEN: *parity = 'o'; break;
609 case PEN | EPS: *parity = 'e'; break;
612 switch (fcon & WLEN) {
613 default:
614 case WLEN_8: *bits = 8; break;
615 case WLEN_7: *bits = 7; break;
616 case WLEN_6: *bits = 6; break;
617 case WLEN_5: *bits = 5; break;
620 *baud = port->uartclk/(16*quot);
624 static int __init lh7a40xuart_console_setup (struct console* co, char* options)
626 struct uart_port* port;
627 int baud = 38400;
628 int bits = 8;
629 int parity = 'n';
630 int flow = 'n';
632 if (co->index >= DEV_NR) /* Bounds check on device number */
633 co->index = 0;
634 port = &lh7a40x_ports[co->index].port;
636 if (options)
637 uart_parse_options (options, &baud, &parity, &bits, &flow);
638 else
639 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
641 return uart_set_options (port, co, baud, parity, bits, flow);
644 extern struct uart_driver lh7a40x_reg;
645 static struct console lh7a40x_console = {
646 .name = "ttyAM",
647 .write = lh7a40xuart_console_write,
648 .device = uart_console_device,
649 .setup = lh7a40xuart_console_setup,
650 .flags = CON_PRINTBUFFER,
651 .index = -1,
652 .data = &lh7a40x_reg,
655 static int __init lh7a40xuart_console_init(void)
657 register_console (&lh7a40x_console);
658 return 0;
661 console_initcall (lh7a40xuart_console_init);
663 #endif
665 static struct uart_driver lh7a40x_reg = {
666 .owner = THIS_MODULE,
667 .driver_name = "ttyAM",
668 .dev_name = "ttyAM",
669 .major = DEV_MAJOR,
670 .minor = DEV_MINOR,
671 .nr = DEV_NR,
672 .cons = LH7A40X_CONSOLE,
675 static int __init lh7a40xuart_init(void)
677 int ret;
679 printk (KERN_INFO "serial: LH7A40X serial driver\n");
681 ret = uart_register_driver (&lh7a40x_reg);
683 if (ret == 0) {
684 int i;
686 for (i = 0; i < DEV_NR; i++)
687 uart_add_one_port (&lh7a40x_reg,
688 &lh7a40x_ports[i].port);
690 return ret;
693 static void __exit lh7a40xuart_exit(void)
695 int i;
697 for (i = 0; i < DEV_NR; i++)
698 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
700 uart_unregister_driver (&lh7a40x_reg);
703 module_init (lh7a40xuart_init);
704 module_exit (lh7a40xuart_exit);
706 MODULE_AUTHOR ("Marc Singer");
707 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
708 MODULE_LICENSE ("GPL");