1 /* 2 * linux/drivers/char/clps711x.c 3 * 4 * Driver for CLPS711x serial ports 5 * 6 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 7 * 8 * Copyright 1999 ARM Limited 9 * Copyright (C) 2000 Deep Blue Solutions Ltd. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 */ 25 26 #if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 27 #define SUPPORT_SYSRQ 28 #endif 29 30 #include <linux/module.h> 31 #include <linux/ioport.h> 32 #include <linux/init.h> 33 #include <linux/console.h> 34 #include <linux/sysrq.h> 35 #include <linux/spinlock.h> 36 #include <linux/device.h> 37 #include <linux/tty.h> 38 #include <linux/tty_flip.h> 39 #include <linux/serial_core.h> 40 #include <linux/serial.h> 41 #include <linux/io.h> 42 43 #include <mach/hardware.h> 44 #include <asm/irq.h> 45 #include <asm/hardware/clps7111.h> 46 47 #define UART_NR 2 48 49 #define SERIAL_CLPS711X_MAJOR 204 50 #define SERIAL_CLPS711X_MINOR 40 51 #define SERIAL_CLPS711X_NR UART_NR 52 53 /* 54 * We use the relevant SYSCON register as a base address for these ports. 55 */ 56 #define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) 57 #define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) 58 #define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) 59 #define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) 60 61 #define TX_IRQ(port) ((port)->irq) 62 #define RX_IRQ(port) ((port)->irq + 1) 63 64 #define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) 65 66 #define tx_enabled(port) ((port)->unused[0]) 67 68 static void clps711xuart_stop_tx(struct uart_port *port) 69 { 70 if (tx_enabled(port)) { 71 disable_irq(TX_IRQ(port)); 72 tx_enabled(port) = 0; 73 } 74 } 75 76 static void clps711xuart_start_tx(struct uart_port *port) 77 { 78 if (!tx_enabled(port)) { 79 enable_irq(TX_IRQ(port)); 80 tx_enabled(port) = 1; 81 } 82 } 83 84 static void clps711xuart_stop_rx(struct uart_port *port) 85 { 86 disable_irq(RX_IRQ(port)); 87 } 88 89 static void clps711xuart_enable_ms(struct uart_port *port) 90 { 91 } 92 93 static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) 94 { 95 struct uart_port *port = dev_id; 96 struct tty_struct *tty = port->state->port.tty; 97 unsigned int status, ch, flg; 98 99 status = clps_readl(SYSFLG(port)); 100 while (!(status & SYSFLG_URXFE)) { 101 ch = clps_readl(UARTDR(port)); 102 103 port->icount.rx++; 104 105 flg = TTY_NORMAL; 106 107 /* 108 * Note that the error handling code is 109 * out of the main execution path 110 */ 111 if (unlikely(ch & UART_ANY_ERR)) { 112 if (ch & UARTDR_PARERR) 113 port->icount.parity++; 114 else if (ch & UARTDR_FRMERR) 115 port->icount.frame++; 116 if (ch & UARTDR_OVERR) 117 port->icount.overrun++; 118 119 ch &= port->read_status_mask; 120 121 if (ch & UARTDR_PARERR) 122 flg = TTY_PARITY; 123 else if (ch & UARTDR_FRMERR) 124 flg = TTY_FRAME; 125 126 #ifdef SUPPORT_SYSRQ 127 port->sysrq = 0; 128 #endif 129 } 130 131 if (uart_handle_sysrq_char(port, ch)) 132 goto ignore_char; 133 134 /* 135 * CHECK: does overrun affect the current character? 136 * ASSUMPTION: it does not. 137 */ 138 uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); 139 140 ignore_char: 141 status = clps_readl(SYSFLG(port)); 142 } 143 tty_flip_buffer_push(tty); 144 return IRQ_HANDLED; 145 } 146 147 static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) 148 { 149 struct uart_port *port = dev_id; 150 struct circ_buf *xmit = &port->state->xmit; 151 int count; 152 153 if (port->x_char) { 154 clps_writel(port->x_char, UARTDR(port)); 155 port->icount.tx++; 156 port->x_char = 0; 157 return IRQ_HANDLED; 158 } 159 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 160 clps711xuart_stop_tx(port); 161 return IRQ_HANDLED; 162 } 163 164 count = port->fifosize >> 1; 165 do { 166 clps_writel(xmit->buf[xmit->tail], UARTDR(port)); 167 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 168 port->icount.tx++; 169 if (uart_circ_empty(xmit)) 170 break; 171 } while (--count > 0); 172 173 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 174 uart_write_wakeup(port); 175 176 if (uart_circ_empty(xmit)) 177 clps711xuart_stop_tx(port); 178 179 return IRQ_HANDLED; 180 } 181 182 static unsigned int clps711xuart_tx_empty(struct uart_port *port) 183 { 184 unsigned int status = clps_readl(SYSFLG(port)); 185 return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; 186 } 187 188 static unsigned int clps711xuart_get_mctrl(struct uart_port *port) 189 { 190 unsigned int port_addr; 191 unsigned int result = 0; 192 unsigned int status; 193 194 port_addr = SYSFLG(port); 195 if (port_addr == SYSFLG1) { 196 status = clps_readl(SYSFLG1); 197 if (status & SYSFLG1_DCD) 198 result |= TIOCM_CAR; 199 if (status & SYSFLG1_DSR) 200 result |= TIOCM_DSR; 201 if (status & SYSFLG1_CTS) 202 result |= TIOCM_CTS; 203 } 204 205 return result; 206 } 207 208 static void 209 clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) 210 { 211 } 212 213 static void clps711xuart_break_ctl(struct uart_port *port, int break_state) 214 { 215 unsigned long flags; 216 unsigned int ubrlcr; 217 218 spin_lock_irqsave(&port->lock, flags); 219 ubrlcr = clps_readl(UBRLCR(port)); 220 if (break_state == -1) 221 ubrlcr |= UBRLCR_BREAK; 222 else 223 ubrlcr &= ~UBRLCR_BREAK; 224 clps_writel(ubrlcr, UBRLCR(port)); 225 spin_unlock_irqrestore(&port->lock, flags); 226 } 227 228 static int clps711xuart_startup(struct uart_port *port) 229 { 230 unsigned int syscon; 231 int retval; 232 233 tx_enabled(port) = 1; 234 235 /* 236 * Allocate the IRQs 237 */ 238 retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0, 239 "clps711xuart_tx", port); 240 if (retval) 241 return retval; 242 243 retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0, 244 "clps711xuart_rx", port); 245 if (retval) { 246 free_irq(TX_IRQ(port), port); 247 return retval; 248 } 249 250 /* 251 * enable the port 252 */ 253 syscon = clps_readl(SYSCON(port)); 254 syscon |= SYSCON_UARTEN; 255 clps_writel(syscon, SYSCON(port)); 256 257 return 0; 258 } 259 260 static void clps711xuart_shutdown(struct uart_port *port) 261 { 262 unsigned int ubrlcr, syscon; 263 264 /* 265 * Free the interrupt 266 */ 267 free_irq(TX_IRQ(port), port); /* TX interrupt */ 268 free_irq(RX_IRQ(port), port); /* RX interrupt */ 269 270 /* 271 * disable the port 272 */ 273 syscon = clps_readl(SYSCON(port)); 274 syscon &= ~SYSCON_UARTEN; 275 clps_writel(syscon, SYSCON(port)); 276 277 /* 278 * disable break condition and fifos 279 */ 280 ubrlcr = clps_readl(UBRLCR(port)); 281 ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); 282 clps_writel(ubrlcr, UBRLCR(port)); 283 } 284 285 static void 286 clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios, 287 struct ktermios *old) 288 { 289 unsigned int ubrlcr, baud, quot; 290 unsigned long flags; 291 292 /* 293 * We don't implement CREAD. 294 */ 295 termios->c_cflag |= CREAD; 296 297 /* 298 * Ask the core to calculate the divisor for us. 299 */ 300 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 301 quot = uart_get_divisor(port, baud); 302 303 switch (termios->c_cflag & CSIZE) { 304 case CS5: 305 ubrlcr = UBRLCR_WRDLEN5; 306 break; 307 case CS6: 308 ubrlcr = UBRLCR_WRDLEN6; 309 break; 310 case CS7: 311 ubrlcr = UBRLCR_WRDLEN7; 312 break; 313 default: // CS8 314 ubrlcr = UBRLCR_WRDLEN8; 315 break; 316 } 317 if (termios->c_cflag & CSTOPB) 318 ubrlcr |= UBRLCR_XSTOP; 319 if (termios->c_cflag & PARENB) { 320 ubrlcr |= UBRLCR_PRTEN; 321 if (!(termios->c_cflag & PARODD)) 322 ubrlcr |= UBRLCR_EVENPRT; 323 } 324 if (port->fifosize > 1) 325 ubrlcr |= UBRLCR_FIFOEN; 326 327 spin_lock_irqsave(&port->lock, flags); 328 329 /* 330 * Update the per-port timeout. 331 */ 332 uart_update_timeout(port, termios->c_cflag, baud); 333 334 port->read_status_mask = UARTDR_OVERR; 335 if (termios->c_iflag & INPCK) 336 port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; 337 338 /* 339 * Characters to ignore 340 */ 341 port->ignore_status_mask = 0; 342 if (termios->c_iflag & IGNPAR) 343 port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; 344 if (termios->c_iflag & IGNBRK) { 345 /* 346 * If we're ignoring parity and break indicators, 347 * ignore overruns to (for real raw support). 348 */ 349 if (termios->c_iflag & IGNPAR) 350 port->ignore_status_mask |= UARTDR_OVERR; 351 } 352 353 quot -= 1; 354 355 clps_writel(ubrlcr | quot, UBRLCR(port)); 356 357 spin_unlock_irqrestore(&port->lock, flags); 358 } 359 360 static const char *clps711xuart_type(struct uart_port *port) 361 { 362 return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; 363 } 364 365 /* 366 * Configure/autoconfigure the port. 367 */ 368 static void clps711xuart_config_port(struct uart_port *port, int flags) 369 { 370 if (flags & UART_CONFIG_TYPE) 371 port->type = PORT_CLPS711X; 372 } 373 374 static void clps711xuart_release_port(struct uart_port *port) 375 { 376 } 377 378 static int clps711xuart_request_port(struct uart_port *port) 379 { 380 return 0; 381 } 382 383 static struct uart_ops clps711x_pops = { 384 .tx_empty = clps711xuart_tx_empty, 385 .set_mctrl = clps711xuart_set_mctrl_null, 386 .get_mctrl = clps711xuart_get_mctrl, 387 .stop_tx = clps711xuart_stop_tx, 388 .start_tx = clps711xuart_start_tx, 389 .stop_rx = clps711xuart_stop_rx, 390 .enable_ms = clps711xuart_enable_ms, 391 .break_ctl = clps711xuart_break_ctl, 392 .startup = clps711xuart_startup, 393 .shutdown = clps711xuart_shutdown, 394 .set_termios = clps711xuart_set_termios, 395 .type = clps711xuart_type, 396 .config_port = clps711xuart_config_port, 397 .release_port = clps711xuart_release_port, 398 .request_port = clps711xuart_request_port, 399 }; 400 401 static struct uart_port clps711x_ports[UART_NR] = { 402 { 403 .iobase = SYSCON1, 404 .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ 405 .uartclk = 3686400, 406 .fifosize = 16, 407 .ops = &clps711x_pops, 408 .line = 0, 409 .flags = UPF_BOOT_AUTOCONF, 410 }, 411 { 412 .iobase = SYSCON2, 413 .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ 414 .uartclk = 3686400, 415 .fifosize = 16, 416 .ops = &clps711x_pops, 417 .line = 1, 418 .flags = UPF_BOOT_AUTOCONF, 419 } 420 }; 421 422 #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE 423 static void clps711xuart_console_putchar(struct uart_port *port, int ch) 424 { 425 while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) 426 barrier(); 427 clps_writel(ch, UARTDR(port)); 428 } 429 430 /* 431 * Print a string to the serial port trying not to disturb 432 * any possible real use of the port... 433 * 434 * The console_lock must be held when we get here. 435 * 436 * Note that this is called with interrupts already disabled 437 */ 438 static void 439 clps711xuart_console_write(struct console *co, const char *s, 440 unsigned int count) 441 { 442 struct uart_port *port = clps711x_ports + co->index; 443 unsigned int status, syscon; 444 445 /* 446 * Ensure that the port is enabled. 447 */ 448 syscon = clps_readl(SYSCON(port)); 449 clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); 450 451 uart_console_write(port, s, count, clps711xuart_console_putchar); 452 453 /* 454 * Finally, wait for transmitter to become empty 455 * and restore the uart state. 456 */ 457 do { 458 status = clps_readl(SYSFLG(port)); 459 } while (status & SYSFLG_UBUSY); 460 461 clps_writel(syscon, SYSCON(port)); 462 } 463 464 static void __init 465 clps711xuart_console_get_options(struct uart_port *port, int *baud, 466 int *parity, int *bits) 467 { 468 if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { 469 unsigned int ubrlcr, quot; 470 471 ubrlcr = clps_readl(UBRLCR(port)); 472 473 *parity = 'n'; 474 if (ubrlcr & UBRLCR_PRTEN) { 475 if (ubrlcr & UBRLCR_EVENPRT) 476 *parity = 'e'; 477 else 478 *parity = 'o'; 479 } 480 481 if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) 482 *bits = 7; 483 else 484 *bits = 8; 485 486 quot = ubrlcr & UBRLCR_BAUD_MASK; 487 *baud = port->uartclk / (16 * (quot + 1)); 488 } 489 } 490 491 static int __init clps711xuart_console_setup(struct console *co, char *options) 492 { 493 struct uart_port *port; 494 int baud = 38400; 495 int bits = 8; 496 int parity = 'n'; 497 int flow = 'n'; 498 499 /* 500 * Check whether an invalid uart number has been specified, and 501 * if so, search for the first available port that does have 502 * console support. 503 */ 504 port = uart_get_console(clps711x_ports, UART_NR, co); 505 506 if (options) 507 uart_parse_options(options, &baud, &parity, &bits, &flow); 508 else 509 clps711xuart_console_get_options(port, &baud, &parity, &bits); 510 511 return uart_set_options(port, co, baud, parity, bits, flow); 512 } 513 514 static struct uart_driver clps711x_reg; 515 static struct console clps711x_console = { 516 .name = "ttyCL", 517 .write = clps711xuart_console_write, 518 .device = uart_console_device, 519 .setup = clps711xuart_console_setup, 520 .flags = CON_PRINTBUFFER, 521 .index = -1, 522 .data = &clps711x_reg, 523 }; 524 525 static int __init clps711xuart_console_init(void) 526 { 527 register_console(&clps711x_console); 528 return 0; 529 } 530 console_initcall(clps711xuart_console_init); 531 532 #define CLPS711X_CONSOLE &clps711x_console 533 #else 534 #define CLPS711X_CONSOLE NULL 535 #endif 536 537 static struct uart_driver clps711x_reg = { 538 .driver_name = "ttyCL", 539 .dev_name = "ttyCL", 540 .major = SERIAL_CLPS711X_MAJOR, 541 .minor = SERIAL_CLPS711X_MINOR, 542 .nr = UART_NR, 543 544 .cons = CLPS711X_CONSOLE, 545 }; 546 547 static int __init clps711xuart_init(void) 548 { 549 int ret, i; 550 551 printk(KERN_INFO "Serial: CLPS711x driver\n"); 552 553 ret = uart_register_driver(&clps711x_reg); 554 if (ret) 555 return ret; 556 557 for (i = 0; i < UART_NR; i++) 558 uart_add_one_port(&clps711x_reg, &clps711x_ports[i]); 559 560 return 0; 561 } 562 563 static void __exit clps711xuart_exit(void) 564 { 565 int i; 566 567 for (i = 0; i < UART_NR; i++) 568 uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]); 569 570 uart_unregister_driver(&clps711x_reg); 571 } 572 573 module_init(clps711xuart_init); 574 module_exit(clps711xuart_exit); 575 576 MODULE_AUTHOR("Deep Blue Solutions Ltd"); 577 MODULE_DESCRIPTION("CLPS-711x generic serial driver"); 578 MODULE_LICENSE("GPL"); 579 MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); 580