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