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 data
= UR (port
, UART_R_DATA
);
155 if (unlikely(data
& RxError
)) { /* Quick check, short-circuit */
156 if (data
& RxBreak
) {
157 data
&= ~(RxFramingError
| RxParityError
);
159 if (uart_handle_break (port
))
162 else if (data
& RxParityError
)
163 ++port
->icount
.parity
;
164 else if (data
& RxFramingError
)
165 ++port
->icount
.frame
;
166 if (data
& RxOverrunError
)
167 ++port
->icount
.overrun
;
169 /* Mask by termios, leave Rx'd byte */
170 data
&= port
->read_status_mask
| 0xff;
174 else if (data
& RxParityError
)
176 else if (data
& RxFramingError
)
180 if (uart_handle_sysrq_char (port
, (unsigned char) data
, regs
))
183 uart_insert_char(port
, data
, RxOverrunError
, data
, flag
);
185 tty_flip_buffer_push (tty
);
189 static void lh7a40xuart_tx_chars (struct uart_port
* port
)
191 struct circ_buf
* xmit
= &port
->info
->xmit
;
192 int cbTxMax
= port
->fifosize
;
195 UR (port
, UART_R_DATA
) = port
->x_char
;
200 if (uart_circ_empty (xmit
) || uart_tx_stopped (port
)) {
201 lh7a40xuart_stop_tx (port
);
205 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
206 that at least half of the FIFO is empty. Instead, we check
207 status for every character. Using the AMBA method causes
208 the transmitter to drop characters. */
211 UR (port
, UART_R_DATA
) = xmit
->buf
[xmit
->tail
];
212 xmit
->tail
= (xmit
->tail
+ 1) & (UART_XMIT_SIZE
- 1);
214 if (uart_circ_empty(xmit
))
216 } while (!(UR (port
, UART_R_STATUS
) & nTxRdy
)
219 if (uart_circ_chars_pending (xmit
) < WAKEUP_CHARS
)
220 uart_write_wakeup (port
);
222 if (uart_circ_empty (xmit
))
223 lh7a40xuart_stop_tx (port
);
226 static void lh7a40xuart_modem_status (struct uart_port
* port
)
228 unsigned int status
= UR (port
, UART_R_STATUS
);
230 = status
^ ((struct uart_port_lh7a40x
*) port
)->statusPrev
;
232 BIT_SET (port
, UART_R_RAWISR
, MSEOI
); /* Clear modem status intr */
234 if (!delta
) /* Only happens if we missed 2 transitions */
237 ((struct uart_port_lh7a40x
*) port
)->statusPrev
= status
;
240 uart_handle_dcd_change (port
, status
& DCD
);
246 uart_handle_cts_change (port
, status
& CTS
);
248 wake_up_interruptible (&port
->info
->delta_msr_wait
);
251 static irqreturn_t
lh7a40xuart_int (int irq
, void* dev_id
,
252 struct pt_regs
* regs
)
254 struct uart_port
* port
= dev_id
;
255 unsigned int cLoopLimit
= ISR_LOOP_LIMIT
;
256 unsigned int isr
= UR (port
, UART_R_ISR
);
260 if (isr
& (RxInt
| RxTimeoutInt
))
262 lh7a40xuart_rx_chars(port
, regs
);
264 lh7a40xuart_rx_chars(port
);
267 lh7a40xuart_modem_status (port
);
269 lh7a40xuart_tx_chars (port
);
271 if (--cLoopLimit
== 0)
274 isr
= UR (port
, UART_R_ISR
);
275 } while (isr
& (RxInt
| TxInt
| RxTimeoutInt
));
280 static unsigned int lh7a40xuart_tx_empty (struct uart_port
* port
)
282 return (UR (port
, UART_R_STATUS
) & TxEmpty
) ? TIOCSER_TEMT
: 0;
285 static unsigned int lh7a40xuart_get_mctrl (struct uart_port
* port
)
287 unsigned int result
= 0;
288 unsigned int status
= UR (port
, UART_R_STATUS
);
300 static void lh7a40xuart_set_mctrl (struct uart_port
* port
, unsigned int mctrl
)
302 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
303 /* Note, kernel appears to be setting DTR and RTS on console. */
305 /* *** FIXME: this deserves more work. There's some work in
306 tracing all of the IO pins. */
308 if( port
->mapbase
== UART1_PHYS
) {
309 gpioRegs_t
*gpio
= (gpioRegs_t
*)IO_ADDRESS(GPIO_PHYS
);
311 if (mctrl
& TIOCM_RTS
)
312 gpio
->pbdr
&= ~GPIOB_UART1_RTS
;
314 gpio
->pbdr
|= GPIOB_UART1_RTS
;
319 static void lh7a40xuart_break_ctl (struct uart_port
* port
, int break_state
)
323 spin_lock_irqsave(&port
->lock
, flags
);
324 if (break_state
== -1)
325 BIT_SET (port
, UART_R_FCON
, BRK
); /* Assert break */
327 BIT_CLR (port
, UART_R_FCON
, BRK
); /* Deassert break */
328 spin_unlock_irqrestore(&port
->lock
, flags
);
331 static int lh7a40xuart_startup (struct uart_port
* port
)
335 retval
= request_irq (port
->irq
, lh7a40xuart_int
, 0,
336 "serial_lh7a40x", port
);
340 /* Initial modem control-line settings */
341 ((struct uart_port_lh7a40x
*) port
)->statusPrev
342 = UR (port
, UART_R_STATUS
);
344 /* There is presently no configuration option to enable IR.
345 Thus, we always disable it. */
347 BIT_SET (port
, UART_R_CON
, UARTEN
| SIRDIS
);
348 BIT_SET (port
, UART_R_INTEN
, RxTimeoutInt
| RxInt
);
353 static void lh7a40xuart_shutdown (struct uart_port
* port
)
355 free_irq (port
->irq
, port
);
356 BIT_CLR (port
, UART_R_FCON
, BRK
| FEN
);
357 BIT_CLR (port
, UART_R_CON
, UARTEN
);
360 static void lh7a40xuart_set_termios (struct uart_port
* port
,
361 struct termios
* termios
,
371 baud
= uart_get_baud_rate (port
, termios
, old
, 8, port
->uartclk
/16);
372 quot
= uart_get_divisor (port
, baud
); /* -1 performed elsewhere */
374 switch (termios
->c_cflag
& CSIZE
) {
389 if (termios
->c_cflag
& CSTOPB
)
391 if (termios
->c_cflag
& PARENB
) {
393 if (!(termios
->c_cflag
& PARODD
))
396 if (port
->fifosize
> 1)
399 spin_lock_irqsave (&port
->lock
, flags
);
401 uart_update_timeout (port
, termios
->c_cflag
, baud
);
403 port
->read_status_mask
= RxOverrunError
;
404 if (termios
->c_iflag
& INPCK
)
405 port
->read_status_mask
|= RxFramingError
| RxParityError
;
406 if (termios
->c_iflag
& (BRKINT
| PARMRK
))
407 port
->read_status_mask
|= RxBreak
;
409 /* Figure mask for status we ignore */
410 port
->ignore_status_mask
= 0;
411 if (termios
->c_iflag
& IGNPAR
)
412 port
->ignore_status_mask
|= RxFramingError
| RxParityError
;
413 if (termios
->c_iflag
& IGNBRK
) {
414 port
->ignore_status_mask
|= RxBreak
;
415 /* Ignore overrun when ignorning parity */
416 /* *** FIXME: is this in the right place? */
417 if (termios
->c_iflag
& IGNPAR
)
418 port
->ignore_status_mask
|= RxOverrunError
;
421 /* Ignore all receive errors when receive disabled */
422 if ((termios
->c_cflag
& CREAD
) == 0)
423 port
->ignore_status_mask
|= RxError
;
425 con
= UR (port
, UART_R_CON
);
426 inten
= (UR (port
, UART_R_INTEN
) & ~ModemInt
);
428 if (UART_ENABLE_MS (port
, termios
->c_cflag
))
431 BIT_CLR (port
, UART_R_CON
, UARTEN
); /* Disable UART */
432 UR (port
, UART_R_INTEN
) = 0; /* Disable interrupts */
433 UR (port
, UART_R_BRCON
) = quot
- 1; /* Set baud rate divisor */
434 UR (port
, UART_R_FCON
) = fcon
; /* Set FIFO and frame ctrl */
435 UR (port
, UART_R_INTEN
) = inten
; /* Enable interrupts */
436 UR (port
, UART_R_CON
) = con
; /* Restore UART mode */
438 spin_unlock_irqrestore(&port
->lock
, flags
);
441 static const char* lh7a40xuart_type (struct uart_port
* port
)
443 return port
->type
== PORT_LH7A40X
? "LH7A40X" : NULL
;
446 static void lh7a40xuart_release_port (struct uart_port
* port
)
448 release_mem_region (port
->mapbase
, UART_REG_SIZE
);
451 static int lh7a40xuart_request_port (struct uart_port
* port
)
453 return request_mem_region (port
->mapbase
, UART_REG_SIZE
,
454 "serial_lh7a40x") != NULL
458 static void lh7a40xuart_config_port (struct uart_port
* port
, int flags
)
460 if (flags
& UART_CONFIG_TYPE
) {
461 port
->type
= PORT_LH7A40X
;
462 lh7a40xuart_request_port (port
);
466 static int lh7a40xuart_verify_port (struct uart_port
* port
,
467 struct serial_struct
* ser
)
471 if (ser
->type
!= PORT_UNKNOWN
&& ser
->type
!= PORT_LH7A40X
)
473 if (ser
->irq
< 0 || ser
->irq
>= NR_IRQS
)
475 if (ser
->baud_base
< 9600) /* *** FIXME: is this true? */
480 static struct uart_ops lh7a40x_uart_ops
= {
481 .tx_empty
= lh7a40xuart_tx_empty
,
482 .set_mctrl
= lh7a40xuart_set_mctrl
,
483 .get_mctrl
= lh7a40xuart_get_mctrl
,
484 .stop_tx
= lh7a40xuart_stop_tx
,
485 .start_tx
= lh7a40xuart_start_tx
,
486 .stop_rx
= lh7a40xuart_stop_rx
,
487 .enable_ms
= lh7a40xuart_enable_ms
,
488 .break_ctl
= lh7a40xuart_break_ctl
,
489 .startup
= lh7a40xuart_startup
,
490 .shutdown
= lh7a40xuart_shutdown
,
491 .set_termios
= lh7a40xuart_set_termios
,
492 .type
= lh7a40xuart_type
,
493 .release_port
= lh7a40xuart_release_port
,
494 .request_port
= lh7a40xuart_request_port
,
495 .config_port
= lh7a40xuart_config_port
,
496 .verify_port
= lh7a40xuart_verify_port
,
499 static struct uart_port_lh7a40x lh7a40x_ports
[DEV_NR
] = {
502 .membase
= (void*) io_p2v (UART1_PHYS
),
503 .mapbase
= UART1_PHYS
,
505 .irq
= IRQ_UART1INTR
,
506 .uartclk
= 14745600/2,
508 .ops
= &lh7a40x_uart_ops
,
509 .flags
= UPF_BOOT_AUTOCONF
,
515 .membase
= (void*) io_p2v (UART2_PHYS
),
516 .mapbase
= UART2_PHYS
,
518 .irq
= IRQ_UART2INTR
,
519 .uartclk
= 14745600/2,
521 .ops
= &lh7a40x_uart_ops
,
522 .flags
= UPF_BOOT_AUTOCONF
,
528 .membase
= (void*) io_p2v (UART3_PHYS
),
529 .mapbase
= UART3_PHYS
,
531 .irq
= IRQ_UART3INTR
,
532 .uartclk
= 14745600/2,
534 .ops
= &lh7a40x_uart_ops
,
535 .flags
= UPF_BOOT_AUTOCONF
,
541 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
542 # define LH7A40X_CONSOLE NULL
544 # define LH7A40X_CONSOLE &lh7a40x_console
546 static void lh7a40xuart_console_putchar(struct uart_port
*port
, int ch
)
548 while (UR(port
, UART_R_STATUS
) & nTxRdy
)
550 UR(port
, UART_R_DATA
) = ch
;
553 static void lh7a40xuart_console_write (struct console
* co
,
557 struct uart_port
* port
= &lh7a40x_ports
[co
->index
].port
;
558 unsigned int con
= UR (port
, UART_R_CON
);
559 unsigned int inten
= UR (port
, UART_R_INTEN
);
562 UR (port
, UART_R_INTEN
) = 0; /* Disable all interrupts */
563 BIT_SET (port
, UART_R_CON
, UARTEN
| SIRDIS
); /* Enable UART */
565 uart_console_write(port
, s
, count
, lh7a40xuart_console_putchar
);
567 /* Wait until all characters are sent */
568 while (UR (port
, UART_R_STATUS
) & TxBusy
)
571 /* Restore control and interrupt mask */
572 UR (port
, UART_R_CON
) = con
;
573 UR (port
, UART_R_INTEN
) = inten
;
576 static void __init
lh7a40xuart_console_get_options (struct uart_port
* port
,
581 if (UR (port
, UART_R_CON
) & UARTEN
) {
582 unsigned int fcon
= UR (port
, UART_R_FCON
);
583 unsigned int quot
= UR (port
, UART_R_BRCON
) + 1;
585 switch (fcon
& (PEN
| EPS
)) {
586 default: *parity
= 'n'; break;
587 case PEN
: *parity
= 'o'; break;
588 case PEN
| EPS
: *parity
= 'e'; break;
591 switch (fcon
& WLEN
) {
593 case WLEN_8
: *bits
= 8; break;
594 case WLEN_7
: *bits
= 7; break;
595 case WLEN_6
: *bits
= 6; break;
596 case WLEN_5
: *bits
= 5; break;
599 *baud
= port
->uartclk
/(16*quot
);
603 static int __init
lh7a40xuart_console_setup (struct console
* co
, char* options
)
605 struct uart_port
* port
;
611 if (co
->index
>= DEV_NR
) /* Bounds check on device number */
613 port
= &lh7a40x_ports
[co
->index
].port
;
616 uart_parse_options (options
, &baud
, &parity
, &bits
, &flow
);
618 lh7a40xuart_console_get_options (port
, &baud
, &parity
, &bits
);
620 return uart_set_options (port
, co
, baud
, parity
, bits
, flow
);
623 static struct uart_driver lh7a40x_reg
;
624 static struct console lh7a40x_console
= {
626 .write
= lh7a40xuart_console_write
,
627 .device
= uart_console_device
,
628 .setup
= lh7a40xuart_console_setup
,
629 .flags
= CON_PRINTBUFFER
,
631 .data
= &lh7a40x_reg
,
634 static int __init
lh7a40xuart_console_init(void)
636 register_console (&lh7a40x_console
);
640 console_initcall (lh7a40xuart_console_init
);
644 static struct uart_driver lh7a40x_reg
= {
645 .owner
= THIS_MODULE
,
646 .driver_name
= "ttyAM",
651 .cons
= LH7A40X_CONSOLE
,
654 static int __init
lh7a40xuart_init(void)
658 printk (KERN_INFO
"serial: LH7A40X serial driver\n");
660 ret
= uart_register_driver (&lh7a40x_reg
);
665 for (i
= 0; i
< DEV_NR
; i
++)
666 uart_add_one_port (&lh7a40x_reg
,
667 &lh7a40x_ports
[i
].port
);
672 static void __exit
lh7a40xuart_exit(void)
676 for (i
= 0; i
< DEV_NR
; i
++)
677 uart_remove_one_port (&lh7a40x_reg
, &lh7a40x_ports
[i
].port
);
679 uart_unregister_driver (&lh7a40x_reg
);
682 module_init (lh7a40xuart_init
);
683 module_exit (lh7a40xuart_exit
);
685 MODULE_AUTHOR ("Marc Singer");
686 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
687 MODULE_LICENSE ("GPL");