1/* 2 * Driver for CLPS711x serial ports 3 * 4 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 5 * 6 * Copyright 1999 ARM Limited 7 * Copyright (C) 2000 Deep Blue Solutions Ltd. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 25#define SUPPORT_SYSRQ 26#endif 27 28#include <linux/module.h> 29#include <linux/ioport.h> 30#include <linux/init.h> 31#include <linux/console.h> 32#include <linux/sysrq.h> 33#include <linux/spinlock.h> 34#include <linux/device.h> 35#include <linux/tty.h> 36#include <linux/tty_flip.h> 37#include <linux/serial_core.h> 38#include <linux/serial.h> 39#include <linux/io.h> 40 41#include <mach/hardware.h> 42#include <asm/irq.h> 43#include <asm/hardware/clps7111.h> 44 45#define UART_NR 2 46 47#define SERIAL_CLPS711X_MAJOR 204 48#define SERIAL_CLPS711X_MINOR 40 49#define SERIAL_CLPS711X_NR UART_NR 50 51/* 52 * We use the relevant SYSCON register as a base address for these ports. 53 */ 54#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) 55#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) 56#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) 57#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) 58 59#define TX_IRQ(port) ((port)->irq) 60#define RX_IRQ(port) ((port)->irq + 1) 61 62#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) 63 64#define tx_enabled(port) ((port)->unused[0]) 65 66static void clps711xuart_stop_tx(struct uart_port *port) 67{ 68 if (tx_enabled(port)) { 69 disable_irq(TX_IRQ(port)); 70 tx_enabled(port) = 0; 71 } 72} 73 74static void clps711xuart_start_tx(struct uart_port *port) 75{ 76 if (!tx_enabled(port)) { 77 enable_irq(TX_IRQ(port)); 78 tx_enabled(port) = 1; 79 } 80} 81 82static void clps711xuart_stop_rx(struct uart_port *port) 83{ 84 disable_irq(RX_IRQ(port)); 85} 86 87static void clps711xuart_enable_ms(struct uart_port *port) 88{ 89} 90 91static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id) 92{ 93 struct uart_port *port = dev_id; 94 struct tty_struct *tty = port->state->port.tty; 95 unsigned int status, ch, flg; 96 97 status = clps_readl(SYSFLG(port)); 98 while (!(status & SYSFLG_URXFE)) { 99 ch = clps_readl(UARTDR(port)); 100 101 port->icount.rx++; 102 103 flg = TTY_NORMAL; 104 105 /* 106 * Note that the error handling code is 107 * out of the main execution path 108 */ 109 if (unlikely(ch & UART_ANY_ERR)) { 110 if (ch & UARTDR_PARERR) 111 port->icount.parity++; 112 else if (ch & UARTDR_FRMERR) 113 port->icount.frame++; 114 if (ch & UARTDR_OVERR) 115 port->icount.overrun++; 116 117 ch &= port->read_status_mask; 118 119 if (ch & UARTDR_PARERR) 120 flg = TTY_PARITY; 121 else if (ch & UARTDR_FRMERR) 122 flg = TTY_FRAME; 123 124#ifdef SUPPORT_SYSRQ 125 port->sysrq = 0; 126#endif 127 } 128 129 if (uart_handle_sysrq_char(port, ch)) 130 goto ignore_char; 131 132 /* 133 * CHECK: does overrun affect the current character? 134 * ASSUMPTION: it does not. 135 */ 136 uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); 137 138 ignore_char: 139 status = clps_readl(SYSFLG(port)); 140 } 141 tty_flip_buffer_push(tty); 142 return IRQ_HANDLED; 143} 144 145static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id) 146{ 147 struct uart_port *port = dev_id; 148 struct circ_buf *xmit = &port->state->xmit; 149 int count; 150 151 if (port->x_char) { 152 clps_writel(port->x_char, UARTDR(port)); 153 port->icount.tx++; 154 port->x_char = 0; 155 return IRQ_HANDLED; 156 } 157 158 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) 159 goto disable_tx_irq; 160 161 count = port->fifosize >> 1; 162 do { 163 clps_writel(xmit->buf[xmit->tail], UARTDR(port)); 164 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 165 port->icount.tx++; 166 if (uart_circ_empty(xmit)) 167 break; 168 } while (--count > 0); 169 170 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 171 uart_write_wakeup(port); 172 173 if (uart_circ_empty(xmit)) { 174 disable_tx_irq: 175 disable_irq_nosync(TX_IRQ(port)); 176 tx_enabled(port) = 0; 177 } 178 179 return IRQ_HANDLED; 180} 181 182static 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 188static 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 208static void 209clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) 210{ 211} 212 213static 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 228static 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 260static 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 285static void 286clps711xuart_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 360static 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 */ 368static void clps711xuart_config_port(struct uart_port *port, int flags) 369{ 370 if (flags & UART_CONFIG_TYPE) 371 port->type = PORT_CLPS711X; 372} 373 374static void clps711xuart_release_port(struct uart_port *port) 375{ 376} 377 378static int clps711xuart_request_port(struct uart_port *port) 379{ 380 return 0; 381} 382 383static 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 401static 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 423static 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 */ 438static void 439clps711xuart_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 464static void __init 465clps711xuart_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 491static 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 514static struct uart_driver clps711x_reg; 515static 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 525static int __init clps711xuart_console_init(void) 526{ 527 register_console(&clps711x_console); 528 return 0; 529} 530console_initcall(clps711xuart_console_init); 531 532#define CLPS711X_CONSOLE &clps711x_console 533#else 534#define CLPS711X_CONSOLE NULL 535#endif 536 537static 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 547static 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 563static 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 573module_init(clps711xuart_init); 574module_exit(clps711xuart_exit); 575 576MODULE_AUTHOR("Deep Blue Solutions Ltd"); 577MODULE_DESCRIPTION("CLPS-711x generic serial driver"); 578MODULE_LICENSE("GPL"); 579MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR); 580