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>
52 #define ISR_LOOP_LIMIT 256
54 #define UR(p,o) _UR ((p)->membase, o)
55 #define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
56 #define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
57 #define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
59 #define UART_REG_SIZE 32
61 #define UART_R_DATA (0x00)
62 #define UART_R_FCON (0x04)
63 #define UART_R_BRCON (0x08)
64 #define UART_R_CON (0x0c)
65 #define UART_R_STATUS (0x10)
66 #define UART_R_RAWISR (0x14)
67 #define UART_R_INTEN (0x18)
68 #define UART_R_ISR (0x1c)
70 #define UARTEN (0x01) /* UART enable */
71 #define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
73 #define RxEmpty (0x10)
74 #define TxEmpty (0x80)
76 #define nRxRdy RxEmpty
80 #define RxBreak (0x0800)
81 #define RxOverrunError (0x0400)
82 #define RxParityError (0x0200)
83 #define RxFramingError (0x0100)
84 #define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
92 #define ModemInt (0x04)
93 #define RxTimeoutInt (0x08)
100 #define WLEN_5 (0x00)
101 #define WLEN (0x60) /* Mask for all word-length bits */
103 #define PEN (0x02) /* Parity Enable */
104 #define EPS (0x04) /* Even Parity Set */
105 #define FEN (0x10) /* FIFO Enable */
106 #define BRK (0x01) /* Send Break */
109 struct uart_port_lh7a40x
{
110 struct uart_port port
;
111 unsigned int statusPrev
; /* Most recently read modem status */
114 static void lh7a40xuart_stop_tx (struct uart_port
* port
)
116 BIT_CLR (port
, UART_R_INTEN
, TxInt
);
119 static void lh7a40xuart_start_tx (struct uart_port
* port
)
121 BIT_SET (port
, UART_R_INTEN
, TxInt
);
123 /* *** FIXME: do I need to check for startup of the
124 transmitter? The old driver did, but AMBA
128 static void lh7a40xuart_stop_rx (struct uart_port
* port
)
130 BIT_SET (port
, UART_R_INTEN
, RxTimeoutInt
| RxInt
);
133 static void lh7a40xuart_enable_ms (struct uart_port
* port
)
135 BIT_SET (port
, UART_R_INTEN
, ModemInt
);
138 static void lh7a40xuart_rx_chars (struct uart_port
* port
)
140 struct tty_struct
* tty
= port
->info
->port
.tty
;
141 int cbRxMax
= 256; /* (Gross) limit on receive */
142 unsigned int data
; /* Received data and status */
145 while (!(UR (port
, UART_R_STATUS
) & nRxRdy
) && --cbRxMax
) {
146 data
= UR (port
, UART_R_DATA
);
150 if (unlikely(data
& RxError
)) {
151 if (data
& RxBreak
) {
152 data
&= ~(RxFramingError
| RxParityError
);
154 if (uart_handle_break (port
))
157 else if (data
& RxParityError
)
158 ++port
->icount
.parity
;
159 else if (data
& RxFramingError
)
160 ++port
->icount
.frame
;
161 if (data
& RxOverrunError
)
162 ++port
->icount
.overrun
;
164 /* Mask by termios, leave Rx'd byte */
165 data
&= port
->read_status_mask
| 0xff;
169 else if (data
& RxParityError
)
171 else if (data
& RxFramingError
)
175 if (uart_handle_sysrq_char (port
, (unsigned char) data
))
178 uart_insert_char(port
, data
, RxOverrunError
, data
, flag
);
180 tty_flip_buffer_push (tty
);
184 static void lh7a40xuart_tx_chars (struct uart_port
* port
)
186 struct circ_buf
* xmit
= &port
->info
->xmit
;
187 int cbTxMax
= port
->fifosize
;
190 UR (port
, UART_R_DATA
) = port
->x_char
;
195 if (uart_circ_empty (xmit
) || uart_tx_stopped (port
)) {
196 lh7a40xuart_stop_tx (port
);
200 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
201 that at least half of the FIFO is empty. Instead, we check
202 status for every character. Using the AMBA method causes
203 the transmitter to drop characters. */
206 UR (port
, UART_R_DATA
) = xmit
->buf
[xmit
->tail
];
207 xmit
->tail
= (xmit
->tail
+ 1) & (UART_XMIT_SIZE
- 1);
209 if (uart_circ_empty(xmit
))
211 } while (!(UR (port
, UART_R_STATUS
) & nTxRdy
)
214 if (uart_circ_chars_pending (xmit
) < WAKEUP_CHARS
)
215 uart_write_wakeup (port
);
217 if (uart_circ_empty (xmit
))
218 lh7a40xuart_stop_tx (port
);
221 static void lh7a40xuart_modem_status (struct uart_port
* port
)
223 unsigned int status
= UR (port
, UART_R_STATUS
);
225 = status
^ ((struct uart_port_lh7a40x
*) port
)->statusPrev
;
227 BIT_SET (port
, UART_R_RAWISR
, MSEOI
); /* Clear modem status intr */
229 if (!delta
) /* Only happens if we missed 2 transitions */
232 ((struct uart_port_lh7a40x
*) port
)->statusPrev
= status
;
235 uart_handle_dcd_change (port
, status
& DCD
);
241 uart_handle_cts_change (port
, status
& CTS
);
243 wake_up_interruptible (&port
->info
->delta_msr_wait
);
246 static irqreturn_t
lh7a40xuart_int (int irq
, void* dev_id
)
248 struct uart_port
* port
= dev_id
;
249 unsigned int cLoopLimit
= ISR_LOOP_LIMIT
;
250 unsigned int isr
= UR (port
, UART_R_ISR
);
254 if (isr
& (RxInt
| RxTimeoutInt
))
255 lh7a40xuart_rx_chars(port
);
257 lh7a40xuart_modem_status (port
);
259 lh7a40xuart_tx_chars (port
);
261 if (--cLoopLimit
== 0)
264 isr
= UR (port
, UART_R_ISR
);
265 } while (isr
& (RxInt
| TxInt
| RxTimeoutInt
));
270 static unsigned int lh7a40xuart_tx_empty (struct uart_port
* port
)
272 return (UR (port
, UART_R_STATUS
) & TxEmpty
) ? TIOCSER_TEMT
: 0;
275 static unsigned int lh7a40xuart_get_mctrl (struct uart_port
* port
)
277 unsigned int result
= 0;
278 unsigned int status
= UR (port
, UART_R_STATUS
);
290 static void lh7a40xuart_set_mctrl (struct uart_port
* port
, unsigned int mctrl
)
292 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
293 /* Note, kernel appears to be setting DTR and RTS on console. */
295 /* *** FIXME: this deserves more work. There's some work in
296 tracing all of the IO pins. */
298 if( port
->mapbase
== UART1_PHYS
) {
299 gpioRegs_t
*gpio
= (gpioRegs_t
*)IO_ADDRESS(GPIO_PHYS
);
301 if (mctrl
& TIOCM_RTS
)
302 gpio
->pbdr
&= ~GPIOB_UART1_RTS
;
304 gpio
->pbdr
|= GPIOB_UART1_RTS
;
309 static void lh7a40xuart_break_ctl (struct uart_port
* port
, int break_state
)
313 spin_lock_irqsave(&port
->lock
, flags
);
314 if (break_state
== -1)
315 BIT_SET (port
, UART_R_FCON
, BRK
); /* Assert break */
317 BIT_CLR (port
, UART_R_FCON
, BRK
); /* Deassert break */
318 spin_unlock_irqrestore(&port
->lock
, flags
);
321 static int lh7a40xuart_startup (struct uart_port
* port
)
325 retval
= request_irq (port
->irq
, lh7a40xuart_int
, 0,
326 "serial_lh7a40x", port
);
330 /* Initial modem control-line settings */
331 ((struct uart_port_lh7a40x
*) port
)->statusPrev
332 = UR (port
, UART_R_STATUS
);
334 /* There is presently no configuration option to enable IR.
335 Thus, we always disable it. */
337 BIT_SET (port
, UART_R_CON
, UARTEN
| SIRDIS
);
338 BIT_SET (port
, UART_R_INTEN
, RxTimeoutInt
| RxInt
);
343 static void lh7a40xuart_shutdown (struct uart_port
* port
)
345 free_irq (port
->irq
, port
);
346 BIT_CLR (port
, UART_R_FCON
, BRK
| FEN
);
347 BIT_CLR (port
, UART_R_CON
, UARTEN
);
350 static void lh7a40xuart_set_termios (struct uart_port
* port
,
351 struct ktermios
* termios
,
352 struct ktermios
* old
)
361 baud
= uart_get_baud_rate (port
, termios
, old
, 8, port
->uartclk
/16);
362 quot
= uart_get_divisor (port
, baud
); /* -1 performed elsewhere */
364 switch (termios
->c_cflag
& CSIZE
) {
379 if (termios
->c_cflag
& CSTOPB
)
381 if (termios
->c_cflag
& PARENB
) {
383 if (!(termios
->c_cflag
& PARODD
))
386 if (port
->fifosize
> 1)
389 spin_lock_irqsave (&port
->lock
, flags
);
391 uart_update_timeout (port
, termios
->c_cflag
, baud
);
393 port
->read_status_mask
= RxOverrunError
;
394 if (termios
->c_iflag
& INPCK
)
395 port
->read_status_mask
|= RxFramingError
| RxParityError
;
396 if (termios
->c_iflag
& (BRKINT
| PARMRK
))
397 port
->read_status_mask
|= RxBreak
;
399 /* Figure mask for status we ignore */
400 port
->ignore_status_mask
= 0;
401 if (termios
->c_iflag
& IGNPAR
)
402 port
->ignore_status_mask
|= RxFramingError
| RxParityError
;
403 if (termios
->c_iflag
& IGNBRK
) {
404 port
->ignore_status_mask
|= RxBreak
;
405 /* Ignore overrun when ignorning parity */
406 /* *** FIXME: is this in the right place? */
407 if (termios
->c_iflag
& IGNPAR
)
408 port
->ignore_status_mask
|= RxOverrunError
;
411 /* Ignore all receive errors when receive disabled */
412 if ((termios
->c_cflag
& CREAD
) == 0)
413 port
->ignore_status_mask
|= RxError
;
415 con
= UR (port
, UART_R_CON
);
416 inten
= (UR (port
, UART_R_INTEN
) & ~ModemInt
);
418 if (UART_ENABLE_MS (port
, termios
->c_cflag
))
421 BIT_CLR (port
, UART_R_CON
, UARTEN
); /* Disable UART */
422 UR (port
, UART_R_INTEN
) = 0; /* Disable interrupts */
423 UR (port
, UART_R_BRCON
) = quot
- 1; /* Set baud rate divisor */
424 UR (port
, UART_R_FCON
) = fcon
; /* Set FIFO and frame ctrl */
425 UR (port
, UART_R_INTEN
) = inten
; /* Enable interrupts */
426 UR (port
, UART_R_CON
) = con
; /* Restore UART mode */
428 spin_unlock_irqrestore(&port
->lock
, flags
);
431 static const char* lh7a40xuart_type (struct uart_port
* port
)
433 return port
->type
== PORT_LH7A40X
? "LH7A40X" : NULL
;
436 static void lh7a40xuart_release_port (struct uart_port
* port
)
438 release_mem_region (port
->mapbase
, UART_REG_SIZE
);
441 static int lh7a40xuart_request_port (struct uart_port
* port
)
443 return request_mem_region (port
->mapbase
, UART_REG_SIZE
,
444 "serial_lh7a40x") != NULL
448 static void lh7a40xuart_config_port (struct uart_port
* port
, int flags
)
450 if (flags
& UART_CONFIG_TYPE
) {
451 port
->type
= PORT_LH7A40X
;
452 lh7a40xuart_request_port (port
);
456 static int lh7a40xuart_verify_port (struct uart_port
* port
,
457 struct serial_struct
* ser
)
461 if (ser
->type
!= PORT_UNKNOWN
&& ser
->type
!= PORT_LH7A40X
)
463 if (ser
->irq
< 0 || ser
->irq
>= nr_irqs
)
465 if (ser
->baud_base
< 9600) /* *** FIXME: is this true? */
470 static struct uart_ops lh7a40x_uart_ops
= {
471 .tx_empty
= lh7a40xuart_tx_empty
,
472 .set_mctrl
= lh7a40xuart_set_mctrl
,
473 .get_mctrl
= lh7a40xuart_get_mctrl
,
474 .stop_tx
= lh7a40xuart_stop_tx
,
475 .start_tx
= lh7a40xuart_start_tx
,
476 .stop_rx
= lh7a40xuart_stop_rx
,
477 .enable_ms
= lh7a40xuart_enable_ms
,
478 .break_ctl
= lh7a40xuart_break_ctl
,
479 .startup
= lh7a40xuart_startup
,
480 .shutdown
= lh7a40xuart_shutdown
,
481 .set_termios
= lh7a40xuart_set_termios
,
482 .type
= lh7a40xuart_type
,
483 .release_port
= lh7a40xuart_release_port
,
484 .request_port
= lh7a40xuart_request_port
,
485 .config_port
= lh7a40xuart_config_port
,
486 .verify_port
= lh7a40xuart_verify_port
,
489 static struct uart_port_lh7a40x lh7a40x_ports
[DEV_NR
] = {
492 .membase
= (void*) io_p2v (UART1_PHYS
),
493 .mapbase
= UART1_PHYS
,
495 .irq
= IRQ_UART1INTR
,
496 .uartclk
= 14745600/2,
498 .ops
= &lh7a40x_uart_ops
,
499 .flags
= UPF_BOOT_AUTOCONF
,
505 .membase
= (void*) io_p2v (UART2_PHYS
),
506 .mapbase
= UART2_PHYS
,
508 .irq
= IRQ_UART2INTR
,
509 .uartclk
= 14745600/2,
511 .ops
= &lh7a40x_uart_ops
,
512 .flags
= UPF_BOOT_AUTOCONF
,
518 .membase
= (void*) io_p2v (UART3_PHYS
),
519 .mapbase
= UART3_PHYS
,
521 .irq
= IRQ_UART3INTR
,
522 .uartclk
= 14745600/2,
524 .ops
= &lh7a40x_uart_ops
,
525 .flags
= UPF_BOOT_AUTOCONF
,
531 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
532 # define LH7A40X_CONSOLE NULL
534 # define LH7A40X_CONSOLE &lh7a40x_console
536 static void lh7a40xuart_console_putchar(struct uart_port
*port
, int ch
)
538 while (UR(port
, UART_R_STATUS
) & nTxRdy
)
540 UR(port
, UART_R_DATA
) = ch
;
543 static void lh7a40xuart_console_write (struct console
* co
,
547 struct uart_port
* port
= &lh7a40x_ports
[co
->index
].port
;
548 unsigned int con
= UR (port
, UART_R_CON
);
549 unsigned int inten
= UR (port
, UART_R_INTEN
);
552 UR (port
, UART_R_INTEN
) = 0; /* Disable all interrupts */
553 BIT_SET (port
, UART_R_CON
, UARTEN
| SIRDIS
); /* Enable UART */
555 uart_console_write(port
, s
, count
, lh7a40xuart_console_putchar
);
557 /* Wait until all characters are sent */
558 while (UR (port
, UART_R_STATUS
) & TxBusy
)
561 /* Restore control and interrupt mask */
562 UR (port
, UART_R_CON
) = con
;
563 UR (port
, UART_R_INTEN
) = inten
;
566 static void __init
lh7a40xuart_console_get_options (struct uart_port
* port
,
571 if (UR (port
, UART_R_CON
) & UARTEN
) {
572 unsigned int fcon
= UR (port
, UART_R_FCON
);
573 unsigned int quot
= UR (port
, UART_R_BRCON
) + 1;
575 switch (fcon
& (PEN
| EPS
)) {
576 default: *parity
= 'n'; break;
577 case PEN
: *parity
= 'o'; break;
578 case PEN
| EPS
: *parity
= 'e'; break;
581 switch (fcon
& WLEN
) {
583 case WLEN_8
: *bits
= 8; break;
584 case WLEN_7
: *bits
= 7; break;
585 case WLEN_6
: *bits
= 6; break;
586 case WLEN_5
: *bits
= 5; break;
589 *baud
= port
->uartclk
/(16*quot
);
593 static int __init
lh7a40xuart_console_setup (struct console
* co
, char* options
)
595 struct uart_port
* port
;
601 if (co
->index
>= DEV_NR
) /* Bounds check on device number */
603 port
= &lh7a40x_ports
[co
->index
].port
;
606 uart_parse_options (options
, &baud
, &parity
, &bits
, &flow
);
608 lh7a40xuart_console_get_options (port
, &baud
, &parity
, &bits
);
610 return uart_set_options (port
, co
, baud
, parity
, bits
, flow
);
613 static struct uart_driver lh7a40x_reg
;
614 static struct console lh7a40x_console
= {
616 .write
= lh7a40xuart_console_write
,
617 .device
= uart_console_device
,
618 .setup
= lh7a40xuart_console_setup
,
619 .flags
= CON_PRINTBUFFER
,
621 .data
= &lh7a40x_reg
,
624 static int __init
lh7a40xuart_console_init(void)
626 register_console (&lh7a40x_console
);
630 console_initcall (lh7a40xuart_console_init
);
634 static struct uart_driver lh7a40x_reg
= {
635 .owner
= THIS_MODULE
,
636 .driver_name
= "ttyAM",
641 .cons
= LH7A40X_CONSOLE
,
644 static int __init
lh7a40xuart_init(void)
648 printk (KERN_INFO
"serial: LH7A40X serial driver\n");
650 ret
= uart_register_driver (&lh7a40x_reg
);
655 for (i
= 0; i
< DEV_NR
; i
++) {
656 /* UART3, when used, requires GPIO pin reallocation */
657 if (lh7a40x_ports
[i
].port
.mapbase
== UART3_PHYS
)
659 uart_add_one_port (&lh7a40x_reg
,
660 &lh7a40x_ports
[i
].port
);
666 static void __exit
lh7a40xuart_exit(void)
670 for (i
= 0; i
< DEV_NR
; i
++)
671 uart_remove_one_port (&lh7a40x_reg
, &lh7a40x_ports
[i
].port
);
673 uart_unregister_driver (&lh7a40x_reg
);
676 module_init (lh7a40xuart_init
);
677 module_exit (lh7a40xuart_exit
);
679 MODULE_AUTHOR ("Marc Singer");
680 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
681 MODULE_LICENSE ("GPL");