blob: 56f269b6bfb12c53fb323c66dcab126010888bee [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* drivers/serial/serial_lh7a40x.c
2 *
3 * Copyright (C) 2004 Coastal Environmental Systems
4 *
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.
8 *
9 */
10
11/* Driver for Sharp LH7A40X embedded serial ports
12 *
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.
15 *
16 * ---
17 *
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.
23 *
24 * - Use of SIRDIS
25 * For simplicity, we disable the IR functions of any UART whenever
26 * we enable it.
27 *
28 */
29
30#include <linux/config.h>
31
32#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
33#define SUPPORT_SYSRQ
34#endif
35
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>
45
46#include <asm/io.h>
47#include <asm/irq.h>
48
49#define DEV_MAJOR 204
50#define DEV_MINOR 16
51#define DEV_NR 3
52
53#define ISR_LOOP_LIMIT 256
54
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)
59
60#define UART_REG_SIZE 32
61
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)
70
71#define UARTEN (0x01) /* UART enable */
72#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
73
74#define RxEmpty (0x10)
75#define TxEmpty (0x80)
76#define TxFull (0x20)
77#define nRxRdy RxEmpty
78#define nTxRdy TxFull
79#define TxBusy (0x08)
80
81#define RxBreak (0x0800)
82#define RxOverrunError (0x0400)
83#define RxParityError (0x0200)
84#define RxFramingError (0x0100)
85#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
86
87#define DCD (0x04)
88#define DSR (0x02)
89#define CTS (0x01)
90
91#define RxInt (0x01)
92#define TxInt (0x02)
93#define ModemInt (0x04)
94#define RxTimeoutInt (0x08)
95
96#define MSEOI (0x10)
97
98#define WLEN_8 (0x60)
99#define WLEN_7 (0x40)
100#define WLEN_6 (0x20)
101#define WLEN_5 (0x00)
102#define WLEN (0x60) /* Mask for all word-length bits */
103#define STP2 (0x08)
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 */
108
109
110struct uart_port_lh7a40x {
111 struct uart_port port;
112 unsigned int statusPrev; /* Most recently read modem status */
113};
114
115static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
116{
117 BIT_CLR (port, UART_R_INTEN, TxInt);
118}
119
120static void lh7a40xuart_start_tx (struct uart_port* port,
121 unsigned int tty_start)
122{
123 BIT_SET (port, UART_R_INTEN, TxInt);
124
125 /* *** FIXME: do I need to check for startup of the
126 transmitter? The old driver did, but AMBA
127 doesn't . */
128}
129
130static void lh7a40xuart_stop_rx (struct uart_port* port)
131{
132 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
133}
134
135static void lh7a40xuart_enable_ms (struct uart_port* port)
136{
137 BIT_SET (port, UART_R_INTEN, ModemInt);
138}
139
140static void
141#ifdef SUPPORT_SYSRQ
142lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
143#else
144lh7a40xuart_rx_chars (struct uart_port* port)
145#endif
146{
147 struct tty_struct* tty = port->info->tty;
148 int cbRxMax = 256; /* (Gross) limit on receive */
149 unsigned int data, flag;/* Received data and status */
150
151 while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
152 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
153 if (tty->low_latency)
154 tty_flip_buffer_push(tty);
155 /*
156 * If this failed then we will throw away the
157 * bytes but must do so to clear interrupts
158 */
159 }
160
161 data = UR (port, UART_R_DATA);
162 flag = TTY_NORMAL;
163 ++port->icount.rx;
164
Russell King45849282005-04-26 15:29:44 +0100165 if (unlikely(data & RxError)) { /* Quick check, short-circuit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 if (data & RxBreak) {
167 data &= ~(RxFramingError | RxParityError);
168 ++port->icount.brk;
169 if (uart_handle_break (port))
170 continue;
171 }
172 else if (data & RxParityError)
173 ++port->icount.parity;
174 else if (data & RxFramingError)
175 ++port->icount.frame;
176 if (data & RxOverrunError)
177 ++port->icount.overrun;
178
179 /* Mask by termios, leave Rx'd byte */
180 data &= port->read_status_mask | 0xff;
181
182 if (data & RxBreak)
183 flag = TTY_BREAK;
184 else if (data & RxParityError)
185 flag = TTY_PARITY;
186 else if (data & RxFramingError)
187 flag = TTY_FRAME;
188 }
189
190 if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
191 continue;
192
Russell King05ab3012005-05-09 23:21:59 +0100193 uart_insert_char(port, data, RxOverrunError, data, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 }
195 tty_flip_buffer_push (tty);
196 return;
197}
198
199static void lh7a40xuart_tx_chars (struct uart_port* port)
200{
201 struct circ_buf* xmit = &port->info->xmit;
202 int cbTxMax = port->fifosize;
203
204 if (port->x_char) {
205 UR (port, UART_R_DATA) = port->x_char;
206 ++port->icount.tx;
207 port->x_char = 0;
208 return;
209 }
210 if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
211 lh7a40xuart_stop_tx (port, 0);
212 return;
213 }
214
215 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
216 that at least half of the FIFO is empty. Instead, we check
217 status for every character. Using the AMBA method causes
218 the transmitter to drop characters. */
219
220 do {
221 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
222 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
223 ++port->icount.tx;
224 if (uart_circ_empty(xmit))
225 break;
226 } while (!(UR (port, UART_R_STATUS) & nTxRdy)
227 && cbTxMax--);
228
229 if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
230 uart_write_wakeup (port);
231
232 if (uart_circ_empty (xmit))
233 lh7a40xuart_stop_tx (port, 0);
234}
235
236static void lh7a40xuart_modem_status (struct uart_port* port)
237{
238 unsigned int status = UR (port, UART_R_STATUS);
239 unsigned int delta
240 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
241
242 BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
243
244 if (!delta) /* Only happens if we missed 2 transitions */
245 return;
246
247 ((struct uart_port_lh7a40x*) port)->statusPrev = status;
248
249 if (delta & DCD)
250 uart_handle_dcd_change (port, status & DCD);
251
252 if (delta & DSR)
253 ++port->icount.dsr;
254
255 if (delta & CTS)
256 uart_handle_cts_change (port, status & CTS);
257
258 wake_up_interruptible (&port->info->delta_msr_wait);
259}
260
261static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
262 struct pt_regs* regs)
263{
264 struct uart_port* port = dev_id;
265 unsigned int cLoopLimit = ISR_LOOP_LIMIT;
266 unsigned int isr = UR (port, UART_R_ISR);
267
268
269 do {
270 if (isr & (RxInt | RxTimeoutInt))
271#ifdef SUPPORT_SYSRQ
272 lh7a40xuart_rx_chars(port, regs);
273#else
274 lh7a40xuart_rx_chars(port);
275#endif
276 if (isr & ModemInt)
277 lh7a40xuart_modem_status (port);
278 if (isr & TxInt)
279 lh7a40xuart_tx_chars (port);
280
281 if (--cLoopLimit == 0)
282 break;
283
284 isr = UR (port, UART_R_ISR);
285 } while (isr & (RxInt | TxInt | RxTimeoutInt));
286
287 return IRQ_HANDLED;
288}
289
290static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
291{
292 return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
293}
294
295static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
296{
297 unsigned int result = 0;
298 unsigned int status = UR (port, UART_R_STATUS);
299
300 if (status & DCD)
301 result |= TIOCM_CAR;
302 if (status & DSR)
303 result |= TIOCM_DSR;
304 if (status & CTS)
305 result |= TIOCM_CTS;
306
307 return result;
308}
309
310static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
311{
312 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
313 /* Note, kernel appears to be setting DTR and RTS on console. */
314
315 /* *** FIXME: this deserves more work. There's some work in
316 tracing all of the IO pins. */
317#if 0
318 if( port->mapbase == UART1_PHYS) {
319 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
320
321 if (mctrl & TIOCM_RTS)
322 gpio->pbdr &= ~GPIOB_UART1_RTS;
323 else
324 gpio->pbdr |= GPIOB_UART1_RTS;
325 }
326#endif
327}
328
329static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
330{
331 unsigned long flags;
332
333 spin_lock_irqsave(&port->lock, flags);
334 if (break_state == -1)
335 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
336 else
337 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
338 spin_unlock_irqrestore(&port->lock, flags);
339}
340
341static int lh7a40xuart_startup (struct uart_port* port)
342{
343 int retval;
344
345 retval = request_irq (port->irq, lh7a40xuart_int, 0,
346 "serial_lh7a40x", port);
347 if (retval)
348 return retval;
349
350 /* Initial modem control-line settings */
351 ((struct uart_port_lh7a40x*) port)->statusPrev
352 = UR (port, UART_R_STATUS);
353
354 /* There is presently no configuration option to enable IR.
355 Thus, we always disable it. */
356
357 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
358 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
359
360 return 0;
361}
362
363static void lh7a40xuart_shutdown (struct uart_port* port)
364{
365 free_irq (port->irq, port);
366 BIT_CLR (port, UART_R_FCON, BRK | FEN);
367 BIT_CLR (port, UART_R_CON, UARTEN);
368}
369
370static void lh7a40xuart_set_termios (struct uart_port* port,
371 struct termios* termios,
372 struct termios* old)
373{
374 unsigned int con;
375 unsigned int inten;
376 unsigned int fcon;
377 unsigned long flags;
378 unsigned int baud;
379 unsigned int quot;
380
381 baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
382 quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
383
384 switch (termios->c_cflag & CSIZE) {
385 case CS5:
386 fcon = WLEN_5;
387 break;
388 case CS6:
389 fcon = WLEN_6;
390 break;
391 case CS7:
392 fcon = WLEN_7;
393 break;
394 case CS8:
395 default:
396 fcon = WLEN_8;
397 break;
398 }
399 if (termios->c_cflag & CSTOPB)
400 fcon |= STP2;
401 if (termios->c_cflag & PARENB) {
402 fcon |= PEN;
403 if (!(termios->c_cflag & PARODD))
404 fcon |= EPS;
405 }
406 if (port->fifosize > 1)
407 fcon |= FEN;
408
409 spin_lock_irqsave (&port->lock, flags);
410
411 uart_update_timeout (port, termios->c_cflag, baud);
412
413 port->read_status_mask = RxOverrunError;
414 if (termios->c_iflag & INPCK)
415 port->read_status_mask |= RxFramingError | RxParityError;
416 if (termios->c_iflag & (BRKINT | PARMRK))
417 port->read_status_mask |= RxBreak;
418
419 /* Figure mask for status we ignore */
420 port->ignore_status_mask = 0;
421 if (termios->c_iflag & IGNPAR)
422 port->ignore_status_mask |= RxFramingError | RxParityError;
423 if (termios->c_iflag & IGNBRK) {
424 port->ignore_status_mask |= RxBreak;
425 /* Ignore overrun when ignorning parity */
426 /* *** FIXME: is this in the right place? */
427 if (termios->c_iflag & IGNPAR)
428 port->ignore_status_mask |= RxOverrunError;
429 }
430
431 /* Ignore all receive errors when receive disabled */
432 if ((termios->c_cflag & CREAD) == 0)
433 port->ignore_status_mask |= RxError;
434
435 con = UR (port, UART_R_CON);
436 inten = (UR (port, UART_R_INTEN) & ~ModemInt);
437
438 if (UART_ENABLE_MS (port, termios->c_cflag))
439 inten |= ModemInt;
440
441 BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
442 UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
443 UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
444 UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
445 UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
446 UR (port, UART_R_CON) = con; /* Restore UART mode */
447
448 spin_unlock_irqrestore(&port->lock, flags);
449}
450
451static const char* lh7a40xuart_type (struct uart_port* port)
452{
453 return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
454}
455
456static void lh7a40xuart_release_port (struct uart_port* port)
457{
458 release_mem_region (port->mapbase, UART_REG_SIZE);
459}
460
461static int lh7a40xuart_request_port (struct uart_port* port)
462{
463 return request_mem_region (port->mapbase, UART_REG_SIZE,
464 "serial_lh7a40x") != NULL
465 ? 0 : -EBUSY;
466}
467
468static void lh7a40xuart_config_port (struct uart_port* port, int flags)
469{
470 if (flags & UART_CONFIG_TYPE) {
471 port->type = PORT_LH7A40X;
472 lh7a40xuart_request_port (port);
473 }
474}
475
476static int lh7a40xuart_verify_port (struct uart_port* port,
477 struct serial_struct* ser)
478{
479 int ret = 0;
480
481 if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
482 ret = -EINVAL;
483 if (ser->irq < 0 || ser->irq >= NR_IRQS)
484 ret = -EINVAL;
485 if (ser->baud_base < 9600) /* *** FIXME: is this true? */
486 ret = -EINVAL;
487 return ret;
488}
489
490static struct uart_ops lh7a40x_uart_ops = {
491 .tx_empty = lh7a40xuart_tx_empty,
492 .set_mctrl = lh7a40xuart_set_mctrl,
493 .get_mctrl = lh7a40xuart_get_mctrl,
494 .stop_tx = lh7a40xuart_stop_tx,
495 .start_tx = lh7a40xuart_start_tx,
496 .stop_rx = lh7a40xuart_stop_rx,
497 .enable_ms = lh7a40xuart_enable_ms,
498 .break_ctl = lh7a40xuart_break_ctl,
499 .startup = lh7a40xuart_startup,
500 .shutdown = lh7a40xuart_shutdown,
501 .set_termios = lh7a40xuart_set_termios,
502 .type = lh7a40xuart_type,
503 .release_port = lh7a40xuart_release_port,
504 .request_port = lh7a40xuart_request_port,
505 .config_port = lh7a40xuart_config_port,
506 .verify_port = lh7a40xuart_verify_port,
507};
508
509static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
510 {
511 .port = {
512 .membase = (void*) io_p2v (UART1_PHYS),
513 .mapbase = UART1_PHYS,
514 .iotype = SERIAL_IO_MEM,
515 .irq = IRQ_UART1INTR,
516 .uartclk = 14745600/2,
517 .fifosize = 16,
518 .ops = &lh7a40x_uart_ops,
519 .flags = ASYNC_BOOT_AUTOCONF,
520 .line = 0,
521 },
522 },
523 {
524 .port = {
525 .membase = (void*) io_p2v (UART2_PHYS),
526 .mapbase = UART2_PHYS,
527 .iotype = SERIAL_IO_MEM,
528 .irq = IRQ_UART2INTR,
529 .uartclk = 14745600/2,
530 .fifosize = 16,
531 .ops = &lh7a40x_uart_ops,
532 .flags = ASYNC_BOOT_AUTOCONF,
533 .line = 1,
534 },
535 },
536 {
537 .port = {
538 .membase = (void*) io_p2v (UART3_PHYS),
539 .mapbase = UART3_PHYS,
540 .iotype = SERIAL_IO_MEM,
541 .irq = IRQ_UART3INTR,
542 .uartclk = 14745600/2,
543 .fifosize = 16,
544 .ops = &lh7a40x_uart_ops,
545 .flags = ASYNC_BOOT_AUTOCONF,
546 .line = 2,
547 },
548 },
549};
550
551#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
552# define LH7A40X_CONSOLE NULL
553#else
554# define LH7A40X_CONSOLE &lh7a40x_console
555
556
557static void lh7a40xuart_console_write (struct console* co,
558 const char* s,
559 unsigned int count)
560{
561 struct uart_port* port = &lh7a40x_ports[co->index].port;
562 unsigned int con = UR (port, UART_R_CON);
563 unsigned int inten = UR (port, UART_R_INTEN);
564
565
566 UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
567 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
568
569 for (; count-- > 0; ++s) {
570 while (UR (port, UART_R_STATUS) & nTxRdy)
571 ;
572 UR (port, UART_R_DATA) = *s;
573 if (*s == '\n') {
574 while ((UR (port, UART_R_STATUS) & TxBusy))
575 ;
576 UR (port, UART_R_DATA) = '\r';
577 }
578 }
579
580 /* Wait until all characters are sent */
581 while (UR (port, UART_R_STATUS) & TxBusy)
582 ;
583
584 /* Restore control and interrupt mask */
585 UR (port, UART_R_CON) = con;
586 UR (port, UART_R_INTEN) = inten;
587}
588
589static void __init lh7a40xuart_console_get_options (struct uart_port* port,
590 int* baud,
591 int* parity,
592 int* bits)
593{
594 if (UR (port, UART_R_CON) & UARTEN) {
595 unsigned int fcon = UR (port, UART_R_FCON);
596 unsigned int quot = UR (port, UART_R_BRCON) + 1;
597
598 switch (fcon & (PEN | EPS)) {
599 default: *parity = 'n'; break;
600 case PEN: *parity = 'o'; break;
601 case PEN | EPS: *parity = 'e'; break;
602 }
603
604 switch (fcon & WLEN) {
605 default:
606 case WLEN_8: *bits = 8; break;
607 case WLEN_7: *bits = 7; break;
608 case WLEN_6: *bits = 6; break;
609 case WLEN_5: *bits = 5; break;
610 }
611
612 *baud = port->uartclk/(16*quot);
613 }
614}
615
616static int __init lh7a40xuart_console_setup (struct console* co, char* options)
617{
618 struct uart_port* port;
619 int baud = 38400;
620 int bits = 8;
621 int parity = 'n';
622 int flow = 'n';
623
624 if (co->index >= DEV_NR) /* Bounds check on device number */
625 co->index = 0;
626 port = &lh7a40x_ports[co->index].port;
627
628 if (options)
629 uart_parse_options (options, &baud, &parity, &bits, &flow);
630 else
631 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
632
633 return uart_set_options (port, co, baud, parity, bits, flow);
634}
635
636extern struct uart_driver lh7a40x_reg;
637static struct console lh7a40x_console = {
638 .name = "ttyAM",
639 .write = lh7a40xuart_console_write,
640 .device = uart_console_device,
641 .setup = lh7a40xuart_console_setup,
642 .flags = CON_PRINTBUFFER,
643 .index = -1,
644 .data = &lh7a40x_reg,
645};
646
647static int __init lh7a40xuart_console_init(void)
648{
649 register_console (&lh7a40x_console);
650 return 0;
651}
652
653console_initcall (lh7a40xuart_console_init);
654
655#endif
656
657static struct uart_driver lh7a40x_reg = {
658 .owner = THIS_MODULE,
659 .driver_name = "ttyAM",
660 .dev_name = "ttyAM",
661 .major = DEV_MAJOR,
662 .minor = DEV_MINOR,
663 .nr = DEV_NR,
664 .cons = LH7A40X_CONSOLE,
665};
666
667static int __init lh7a40xuart_init(void)
668{
669 int ret;
670
671 printk (KERN_INFO "serial: LH7A40X serial driver\n");
672
673 ret = uart_register_driver (&lh7a40x_reg);
674
675 if (ret == 0) {
676 int i;
677
678 for (i = 0; i < DEV_NR; i++)
679 uart_add_one_port (&lh7a40x_reg,
680 &lh7a40x_ports[i].port);
681 }
682 return ret;
683}
684
685static void __exit lh7a40xuart_exit(void)
686{
687 int i;
688
689 for (i = 0; i < DEV_NR; i++)
690 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
691
692 uart_unregister_driver (&lh7a40x_reg);
693}
694
695module_init (lh7a40xuart_init);
696module_exit (lh7a40xuart_exit);
697
698MODULE_AUTHOR ("Marc Singer");
699MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
700MODULE_LICENSE ("GPL");