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