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
31 #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
35 #include <linux/module.h>
36 #include <linux/ioport.h>
37 #include <linux/init.h>
38 #include <linux/console.h>
39 #include <linux/sysrq.h>
40 #include <linux/tty.h>
41 #include <linux/tty_flip.h>
42 #include <linux/serial_core.h>
43 #include <linux/serial.h>
47 #include <mach/hardware.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
);
139 static void lh7a40xuart_rx_chars (struct uart_port
* port
)
141 struct tty_struct
* tty
= port
->info
->port
.tty
;
142 int cbRxMax
= 256; /* (Gross) limit on receive */
143 unsigned int data
; /* Received data and status */
146 while (!(UR (port
, UART_R_STATUS
) & nRxRdy
) && --cbRxMax
) {
147 data
= UR (port
, UART_R_DATA
);
151 if (unlikely(data
& RxError
)) {
152 if (data
& RxBreak
) {
153 data
&= ~(RxFramingError
| RxParityError
);
155 if (uart_handle_break (port
))
158 else if (data
& RxParityError
)
159 ++port
->icount
.parity
;
160 else if (data
& RxFramingError
)
161 ++port
->icount
.frame
;
162 if (data
& RxOverrunError
)
163 ++port
->icount
.overrun
;
165 /* Mask by termios, leave Rx'd byte */
166 data
&= port
->read_status_mask
| 0xff;
170 else if (data
& RxParityError
)
172 else if (data
& RxFramingError
)
176 if (uart_handle_sysrq_char (port
, (unsigned char) data
))
179 uart_insert_char(port
, data
, RxOverrunError
, data
, flag
);
181 tty_flip_buffer_push (tty
);
185 static void lh7a40xuart_tx_chars (struct uart_port
* port
)
187 struct circ_buf
* xmit
= &port
->info
->xmit
;
188 int cbTxMax
= port
->fifosize
;
191 UR (port
, UART_R_DATA
) = port
->x_char
;
196 if (uart_circ_empty (xmit
) || uart_tx_stopped (port
)) {
197 lh7a40xuart_stop_tx (port
);
201 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
202 that at least half of the FIFO is empty. Instead, we check
203 status for every character. Using the AMBA method causes
204 the transmitter to drop characters. */
207 UR (port
, UART_R_DATA
) = xmit
->buf
[xmit
->tail
];
208 xmit
->tail
= (xmit
->tail
+ 1) & (UART_XMIT_SIZE
- 1);
210 if (uart_circ_empty(xmit
))
212 } while (!(UR (port
, UART_R_STATUS
) & nTxRdy
)
215 if (uart_circ_chars_pending (xmit
) < WAKEUP_CHARS
)
216 uart_write_wakeup (port
);
218 if (uart_circ_empty (xmit
))
219 lh7a40xuart_stop_tx (port
);
222 static void lh7a40xuart_modem_status (struct uart_port
* port
)
224 unsigned int status
= UR (port
, UART_R_STATUS
);
226 = status
^ ((struct uart_port_lh7a40x
*) port
)->statusPrev
;
228 BIT_SET (port
, UART_R_RAWISR
, MSEOI
); /* Clear modem status intr */
230 if (!delta
) /* Only happens if we missed 2 transitions */
233 ((struct uart_port_lh7a40x
*) port
)->statusPrev
= status
;
236 uart_handle_dcd_change (port
, status
& DCD
);
242 uart_handle_cts_change (port
, status
& CTS
);
244 wake_up_interruptible (&port
->info
->delta_msr_wait
);
247 static irqreturn_t
lh7a40xuart_int (int irq
, void* dev_id
)
249 struct uart_port
* port
= dev_id
;
250 unsigned int cLoopLimit
= ISR_LOOP_LIMIT
;
251 unsigned int isr
= UR (port
, UART_R_ISR
);
255 if (isr
& (RxInt
| RxTimeoutInt
))
256 lh7a40xuart_rx_chars(port
);
258 lh7a40xuart_modem_status (port
);
260 lh7a40xuart_tx_chars (port
);
262 if (--cLoopLimit
== 0)
265 isr
= UR (port
, UART_R_ISR
);
266 } while (isr
& (RxInt
| TxInt
| RxTimeoutInt
));
271 static unsigned int lh7a40xuart_tx_empty (struct uart_port
* port
)
273 return (UR (port
, UART_R_STATUS
) & TxEmpty
) ? TIOCSER_TEMT
: 0;
276 static unsigned int lh7a40xuart_get_mctrl (struct uart_port
* port
)
278 unsigned int result
= 0;
279 unsigned int status
= UR (port
, UART_R_STATUS
);
291 static void lh7a40xuart_set_mctrl (struct uart_port
* port
, unsigned int mctrl
)
293 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
294 /* Note, kernel appears to be setting DTR and RTS on console. */
296 /* *** FIXME: this deserves more work. There's some work in
297 tracing all of the IO pins. */
299 if( port
->mapbase
== UART1_PHYS
) {
300 gpioRegs_t
*gpio
= (gpioRegs_t
*)IO_ADDRESS(GPIO_PHYS
);
302 if (mctrl
& TIOCM_RTS
)
303 gpio
->pbdr
&= ~GPIOB_UART1_RTS
;
305 gpio
->pbdr
|= GPIOB_UART1_RTS
;
310 static void lh7a40xuart_break_ctl (struct uart_port
* port
, int break_state
)
314 spin_lock_irqsave(&port
->lock
, flags
);
315 if (break_state
== -1)
316 BIT_SET (port
, UART_R_FCON
, BRK
); /* Assert break */
318 BIT_CLR (port
, UART_R_FCON
, BRK
); /* Deassert break */
319 spin_unlock_irqrestore(&port
->lock
, flags
);
322 static int lh7a40xuart_startup (struct uart_port
* port
)
326 retval
= request_irq (port
->irq
, lh7a40xuart_int
, 0,
327 "serial_lh7a40x", port
);
331 /* Initial modem control-line settings */
332 ((struct uart_port_lh7a40x
*) port
)->statusPrev
333 = UR (port
, UART_R_STATUS
);
335 /* There is presently no configuration option to enable IR.
336 Thus, we always disable it. */
338 BIT_SET (port
, UART_R_CON
, UARTEN
| SIRDIS
);
339 BIT_SET (port
, UART_R_INTEN
, RxTimeoutInt
| RxInt
);
344 static void lh7a40xuart_shutdown (struct uart_port
* port
)
346 free_irq (port
->irq
, port
);
347 BIT_CLR (port
, UART_R_FCON
, BRK
| FEN
);
348 BIT_CLR (port
, UART_R_CON
, UARTEN
);
351 static void lh7a40xuart_set_termios (struct uart_port
* port
,
352 struct ktermios
* termios
,
353 struct ktermios
* old
)
362 baud
= uart_get_baud_rate (port
, termios
, old
, 8, port
->uartclk
/16);
363 quot
= uart_get_divisor (port
, baud
); /* -1 performed elsewhere */
365 switch (termios
->c_cflag
& CSIZE
) {
380 if (termios
->c_cflag
& CSTOPB
)
382 if (termios
->c_cflag
& PARENB
) {
384 if (!(termios
->c_cflag
& PARODD
))
387 if (port
->fifosize
> 1)
390 spin_lock_irqsave (&port
->lock
, flags
);
392 uart_update_timeout (port
, termios
->c_cflag
, baud
);
394 port
->read_status_mask
= RxOverrunError
;
395 if (termios
->c_iflag
& INPCK
)
396 port
->read_status_mask
|= RxFramingError
| RxParityError
;
397 if (termios
->c_iflag
& (BRKINT
| PARMRK
))
398 port
->read_status_mask
|= RxBreak
;
400 /* Figure mask for status we ignore */
401 port
->ignore_status_mask
= 0;
402 if (termios
->c_iflag
& IGNPAR
)
403 port
->ignore_status_mask
|= RxFramingError
| RxParityError
;
404 if (termios
->c_iflag
& IGNBRK
) {
405 port
->ignore_status_mask
|= RxBreak
;
406 /* Ignore overrun when ignorning parity */
407 /* *** FIXME: is this in the right place? */
408 if (termios
->c_iflag
& IGNPAR
)
409 port
->ignore_status_mask
|= RxOverrunError
;
412 /* Ignore all receive errors when receive disabled */
413 if ((termios
->c_cflag
& CREAD
) == 0)
414 port
->ignore_status_mask
|= RxError
;
416 con
= UR (port
, UART_R_CON
);
417 inten
= (UR (port
, UART_R_INTEN
) & ~ModemInt
);
419 if (UART_ENABLE_MS (port
, termios
->c_cflag
))
422 BIT_CLR (port
, UART_R_CON
, UARTEN
); /* Disable UART */
423 UR (port
, UART_R_INTEN
) = 0; /* Disable interrupts */
424 UR (port
, UART_R_BRCON
) = quot
- 1; /* Set baud rate divisor */
425 UR (port
, UART_R_FCON
) = fcon
; /* Set FIFO and frame ctrl */
426 UR (port
, UART_R_INTEN
) = inten
; /* Enable interrupts */
427 UR (port
, UART_R_CON
) = con
; /* Restore UART mode */
429 spin_unlock_irqrestore(&port
->lock
, flags
);
432 static const char* lh7a40xuart_type (struct uart_port
* port
)
434 return port
->type
== PORT_LH7A40X
? "LH7A40X" : NULL
;
437 static void lh7a40xuart_release_port (struct uart_port
* port
)
439 release_mem_region (port
->mapbase
, UART_REG_SIZE
);
442 static int lh7a40xuart_request_port (struct uart_port
* port
)
444 return request_mem_region (port
->mapbase
, UART_REG_SIZE
,
445 "serial_lh7a40x") != NULL
449 static void lh7a40xuart_config_port (struct uart_port
* port
, int flags
)
451 if (flags
& UART_CONFIG_TYPE
) {
452 port
->type
= PORT_LH7A40X
;
453 lh7a40xuart_request_port (port
);
457 static int lh7a40xuart_verify_port (struct uart_port
* port
,
458 struct serial_struct
* ser
)
462 if (ser
->type
!= PORT_UNKNOWN
&& ser
->type
!= PORT_LH7A40X
)
464 if (ser
->irq
< 0 || ser
->irq
>= nr_irqs
)
466 if (ser
->baud_base
< 9600) /* *** FIXME: is this true? */
471 static struct uart_ops lh7a40x_uart_ops
= {
472 .tx_empty
= lh7a40xuart_tx_empty
,
473 .set_mctrl
= lh7a40xuart_set_mctrl
,
474 .get_mctrl
= lh7a40xuart_get_mctrl
,
475 .stop_tx
= lh7a40xuart_stop_tx
,
476 .start_tx
= lh7a40xuart_start_tx
,
477 .stop_rx
= lh7a40xuart_stop_rx
,
478 .enable_ms
= lh7a40xuart_enable_ms
,
479 .break_ctl
= lh7a40xuart_break_ctl
,
480 .startup
= lh7a40xuart_startup
,
481 .shutdown
= lh7a40xuart_shutdown
,
482 .set_termios
= lh7a40xuart_set_termios
,
483 .type
= lh7a40xuart_type
,
484 .release_port
= lh7a40xuart_release_port
,
485 .request_port
= lh7a40xuart_request_port
,
486 .config_port
= lh7a40xuart_config_port
,
487 .verify_port
= lh7a40xuart_verify_port
,
490 static struct uart_port_lh7a40x lh7a40x_ports
[DEV_NR
] = {
493 .membase
= (void*) io_p2v (UART1_PHYS
),
494 .mapbase
= UART1_PHYS
,
496 .irq
= IRQ_UART1INTR
,
497 .uartclk
= 14745600/2,
499 .ops
= &lh7a40x_uart_ops
,
500 .flags
= UPF_BOOT_AUTOCONF
,
506 .membase
= (void*) io_p2v (UART2_PHYS
),
507 .mapbase
= UART2_PHYS
,
509 .irq
= IRQ_UART2INTR
,
510 .uartclk
= 14745600/2,
512 .ops
= &lh7a40x_uart_ops
,
513 .flags
= UPF_BOOT_AUTOCONF
,
519 .membase
= (void*) io_p2v (UART3_PHYS
),
520 .mapbase
= UART3_PHYS
,
522 .irq
= IRQ_UART3INTR
,
523 .uartclk
= 14745600/2,
525 .ops
= &lh7a40x_uart_ops
,
526 .flags
= UPF_BOOT_AUTOCONF
,
532 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
533 # define LH7A40X_CONSOLE NULL
535 # define LH7A40X_CONSOLE &lh7a40x_console
537 static void lh7a40xuart_console_putchar(struct uart_port
*port
, int ch
)
539 while (UR(port
, UART_R_STATUS
) & nTxRdy
)
541 UR(port
, UART_R_DATA
) = ch
;
544 static void lh7a40xuart_console_write (struct console
* co
,
548 struct uart_port
* port
= &lh7a40x_ports
[co
->index
].port
;
549 unsigned int con
= UR (port
, UART_R_CON
);
550 unsigned int inten
= UR (port
, UART_R_INTEN
);
553 UR (port
, UART_R_INTEN
) = 0; /* Disable all interrupts */
554 BIT_SET (port
, UART_R_CON
, UARTEN
| SIRDIS
); /* Enable UART */
556 uart_console_write(port
, s
, count
, lh7a40xuart_console_putchar
);
558 /* Wait until all characters are sent */
559 while (UR (port
, UART_R_STATUS
) & TxBusy
)
562 /* Restore control and interrupt mask */
563 UR (port
, UART_R_CON
) = con
;
564 UR (port
, UART_R_INTEN
) = inten
;
567 static void __init
lh7a40xuart_console_get_options (struct uart_port
* port
,
572 if (UR (port
, UART_R_CON
) & UARTEN
) {
573 unsigned int fcon
= UR (port
, UART_R_FCON
);
574 unsigned int quot
= UR (port
, UART_R_BRCON
) + 1;
576 switch (fcon
& (PEN
| EPS
)) {
577 default: *parity
= 'n'; break;
578 case PEN
: *parity
= 'o'; break;
579 case PEN
| EPS
: *parity
= 'e'; break;
582 switch (fcon
& WLEN
) {
584 case WLEN_8
: *bits
= 8; break;
585 case WLEN_7
: *bits
= 7; break;
586 case WLEN_6
: *bits
= 6; break;
587 case WLEN_5
: *bits
= 5; break;
590 *baud
= port
->uartclk
/(16*quot
);
594 static int __init
lh7a40xuart_console_setup (struct console
* co
, char* options
)
596 struct uart_port
* port
;
602 if (co
->index
>= DEV_NR
) /* Bounds check on device number */
604 port
= &lh7a40x_ports
[co
->index
].port
;
607 uart_parse_options (options
, &baud
, &parity
, &bits
, &flow
);
609 lh7a40xuart_console_get_options (port
, &baud
, &parity
, &bits
);
611 return uart_set_options (port
, co
, baud
, parity
, bits
, flow
);
614 static struct uart_driver lh7a40x_reg
;
615 static struct console lh7a40x_console
= {
617 .write
= lh7a40xuart_console_write
,
618 .device
= uart_console_device
,
619 .setup
= lh7a40xuart_console_setup
,
620 .flags
= CON_PRINTBUFFER
,
622 .data
= &lh7a40x_reg
,
625 static int __init
lh7a40xuart_console_init(void)
627 register_console (&lh7a40x_console
);
631 console_initcall (lh7a40xuart_console_init
);
635 static struct uart_driver lh7a40x_reg
= {
636 .owner
= THIS_MODULE
,
637 .driver_name
= "ttyAM",
642 .cons
= LH7A40X_CONSOLE
,
645 static int __init
lh7a40xuart_init(void)
649 printk (KERN_INFO
"serial: LH7A40X serial driver\n");
651 ret
= uart_register_driver (&lh7a40x_reg
);
656 for (i
= 0; i
< DEV_NR
; i
++) {
657 /* UART3, when used, requires GPIO pin reallocation */
658 if (lh7a40x_ports
[i
].port
.mapbase
== UART3_PHYS
)
660 uart_add_one_port (&lh7a40x_reg
,
661 &lh7a40x_ports
[i
].port
);
667 static void __exit
lh7a40xuart_exit(void)
671 for (i
= 0; i
< DEV_NR
; i
++)
672 uart_remove_one_port (&lh7a40x_reg
, &lh7a40x_ports
[i
].port
);
674 uart_unregister_driver (&lh7a40x_reg
);
677 module_init (lh7a40xuart_init
);
678 module_exit (lh7a40xuart_exit
);
680 MODULE_AUTHOR ("Marc Singer");
681 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
682 MODULE_LICENSE ("GPL");