Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 529 lines 12 kB view raw
1/* 2 * linux/drivers/char/21285.c 3 * 4 * Driver for the serial port on the 21285 StrongArm-110 core logic chip. 5 * 6 * Based on drivers/char/serial.c 7 * 8 * $Id: 21285.c,v 1.37 2002/07/28 10:03:27 rmk Exp $ 9 */ 10#include <linux/config.h> 11#include <linux/module.h> 12#include <linux/tty.h> 13#include <linux/ioport.h> 14#include <linux/init.h> 15#include <linux/console.h> 16#include <linux/device.h> 17#include <linux/tty_flip.h> 18#include <linux/serial_core.h> 19#include <linux/serial.h> 20 21#include <asm/io.h> 22#include <asm/irq.h> 23#include <asm/mach-types.h> 24#include <asm/hardware/dec21285.h> 25#include <asm/hardware.h> 26 27#define BAUD_BASE (mem_fclk_21285/64) 28 29#define SERIAL_21285_NAME "ttyFB" 30#define SERIAL_21285_MAJOR 204 31#define SERIAL_21285_MINOR 4 32 33#define RXSTAT_DUMMY_READ 0x80000000 34#define RXSTAT_FRAME (1 << 0) 35#define RXSTAT_PARITY (1 << 1) 36#define RXSTAT_OVERRUN (1 << 2) 37#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN) 38 39#define H_UBRLCR_BREAK (1 << 0) 40#define H_UBRLCR_PARENB (1 << 1) 41#define H_UBRLCR_PAREVN (1 << 2) 42#define H_UBRLCR_STOPB (1 << 3) 43#define H_UBRLCR_FIFO (1 << 4) 44 45static const char serial21285_name[] = "Footbridge UART"; 46 47#define tx_enabled(port) ((port)->unused[0]) 48#define rx_enabled(port) ((port)->unused[1]) 49 50/* 51 * The documented expression for selecting the divisor is: 52 * BAUD_BASE / baud - 1 53 * However, typically BAUD_BASE is not divisible by baud, so 54 * we want to select the divisor that gives us the minimum 55 * error. Therefore, we want: 56 * int(BAUD_BASE / baud - 0.5) -> 57 * int(BAUD_BASE / baud - (baud >> 1) / baud) -> 58 * int((BAUD_BASE - (baud >> 1)) / baud) 59 */ 60 61static void serial21285_stop_tx(struct uart_port *port) 62{ 63 if (tx_enabled(port)) { 64 disable_irq(IRQ_CONTX); 65 tx_enabled(port) = 0; 66 } 67} 68 69static void serial21285_start_tx(struct uart_port *port) 70{ 71 if (!tx_enabled(port)) { 72 enable_irq(IRQ_CONTX); 73 tx_enabled(port) = 1; 74 } 75} 76 77static void serial21285_stop_rx(struct uart_port *port) 78{ 79 if (rx_enabled(port)) { 80 disable_irq(IRQ_CONRX); 81 rx_enabled(port) = 0; 82 } 83} 84 85static void serial21285_enable_ms(struct uart_port *port) 86{ 87} 88 89static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs) 90{ 91 struct uart_port *port = dev_id; 92 struct tty_struct *tty = port->info->tty; 93 unsigned int status, ch, flag, rxs, max_count = 256; 94 95 status = *CSR_UARTFLG; 96 while (!(status & 0x10) && max_count--) { 97 if (tty->flip.count >= TTY_FLIPBUF_SIZE) { 98 if (tty->low_latency) 99 tty_flip_buffer_push(tty); 100 /* 101 * If this failed then we will throw away the 102 * bytes but must do so to clear interrupts 103 */ 104 } 105 106 ch = *CSR_UARTDR; 107 flag = TTY_NORMAL; 108 port->icount.rx++; 109 110 rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ; 111 if (unlikely(rxs & RXSTAT_ANYERR)) { 112 if (rxs & RXSTAT_PARITY) 113 port->icount.parity++; 114 else if (rxs & RXSTAT_FRAME) 115 port->icount.frame++; 116 if (rxs & RXSTAT_OVERRUN) 117 port->icount.overrun++; 118 119 rxs &= port->read_status_mask; 120 121 if (rxs & RXSTAT_PARITY) 122 flag = TTY_PARITY; 123 else if (rxs & RXSTAT_FRAME) 124 flag = TTY_FRAME; 125 } 126 127 uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag); 128 129 status = *CSR_UARTFLG; 130 } 131 tty_flip_buffer_push(tty); 132 133 return IRQ_HANDLED; 134} 135 136static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs) 137{ 138 struct uart_port *port = dev_id; 139 struct circ_buf *xmit = &port->info->xmit; 140 int count = 256; 141 142 if (port->x_char) { 143 *CSR_UARTDR = port->x_char; 144 port->icount.tx++; 145 port->x_char = 0; 146 goto out; 147 } 148 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 149 serial21285_stop_tx(port); 150 goto out; 151 } 152 153 do { 154 *CSR_UARTDR = xmit->buf[xmit->tail]; 155 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 156 port->icount.tx++; 157 if (uart_circ_empty(xmit)) 158 break; 159 } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); 160 161 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 162 uart_write_wakeup(port); 163 164 if (uart_circ_empty(xmit)) 165 serial21285_stop_tx(port); 166 167 out: 168 return IRQ_HANDLED; 169} 170 171static unsigned int serial21285_tx_empty(struct uart_port *port) 172{ 173 return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT; 174} 175 176/* no modem control lines */ 177static unsigned int serial21285_get_mctrl(struct uart_port *port) 178{ 179 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; 180} 181 182static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl) 183{ 184} 185 186static void serial21285_break_ctl(struct uart_port *port, int break_state) 187{ 188 unsigned long flags; 189 unsigned int h_lcr; 190 191 spin_lock_irqsave(&port->lock, flags); 192 h_lcr = *CSR_H_UBRLCR; 193 if (break_state) 194 h_lcr |= H_UBRLCR_BREAK; 195 else 196 h_lcr &= ~H_UBRLCR_BREAK; 197 *CSR_H_UBRLCR = h_lcr; 198 spin_unlock_irqrestore(&port->lock, flags); 199} 200 201static int serial21285_startup(struct uart_port *port) 202{ 203 int ret; 204 205 tx_enabled(port) = 1; 206 rx_enabled(port) = 1; 207 208 ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0, 209 serial21285_name, port); 210 if (ret == 0) { 211 ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0, 212 serial21285_name, port); 213 if (ret) 214 free_irq(IRQ_CONRX, port); 215 } 216 217 return ret; 218} 219 220static void serial21285_shutdown(struct uart_port *port) 221{ 222 free_irq(IRQ_CONTX, port); 223 free_irq(IRQ_CONRX, port); 224} 225 226static void 227serial21285_set_termios(struct uart_port *port, struct termios *termios, 228 struct termios *old) 229{ 230 unsigned long flags; 231 unsigned int baud, quot, h_lcr; 232 233 /* 234 * We don't support modem control lines. 235 */ 236 termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); 237 termios->c_cflag |= CLOCAL; 238 239 /* 240 * We don't support BREAK character recognition. 241 */ 242 termios->c_iflag &= ~(IGNBRK | BRKINT); 243 244 /* 245 * Ask the core to calculate the divisor for us. 246 */ 247 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 248 quot = uart_get_divisor(port, baud); 249 250 switch (termios->c_cflag & CSIZE) { 251 case CS5: 252 h_lcr = 0x00; 253 break; 254 case CS6: 255 h_lcr = 0x20; 256 break; 257 case CS7: 258 h_lcr = 0x40; 259 break; 260 default: /* CS8 */ 261 h_lcr = 0x60; 262 break; 263 } 264 265 if (termios->c_cflag & CSTOPB) 266 h_lcr |= H_UBRLCR_STOPB; 267 if (termios->c_cflag & PARENB) { 268 h_lcr |= H_UBRLCR_PARENB; 269 if (!(termios->c_cflag & PARODD)) 270 h_lcr |= H_UBRLCR_PAREVN; 271 } 272 273 if (port->fifosize) 274 h_lcr |= H_UBRLCR_FIFO; 275 276 spin_lock_irqsave(&port->lock, flags); 277 278 /* 279 * Update the per-port timeout. 280 */ 281 uart_update_timeout(port, termios->c_cflag, baud); 282 283 /* 284 * Which character status flags are we interested in? 285 */ 286 port->read_status_mask = RXSTAT_OVERRUN; 287 if (termios->c_iflag & INPCK) 288 port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; 289 290 /* 291 * Which character status flags should we ignore? 292 */ 293 port->ignore_status_mask = 0; 294 if (termios->c_iflag & IGNPAR) 295 port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; 296 if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) 297 port->ignore_status_mask |= RXSTAT_OVERRUN; 298 299 /* 300 * Ignore all characters if CREAD is not set. 301 */ 302 if ((termios->c_cflag & CREAD) == 0) 303 port->ignore_status_mask |= RXSTAT_DUMMY_READ; 304 305 quot -= 1; 306 307 *CSR_UARTCON = 0; 308 *CSR_L_UBRLCR = quot & 0xff; 309 *CSR_M_UBRLCR = (quot >> 8) & 0x0f; 310 *CSR_H_UBRLCR = h_lcr; 311 *CSR_UARTCON = 1; 312 313 spin_unlock_irqrestore(&port->lock, flags); 314} 315 316static const char *serial21285_type(struct uart_port *port) 317{ 318 return port->type == PORT_21285 ? "DC21285" : NULL; 319} 320 321static void serial21285_release_port(struct uart_port *port) 322{ 323 release_mem_region(port->mapbase, 32); 324} 325 326static int serial21285_request_port(struct uart_port *port) 327{ 328 return request_mem_region(port->mapbase, 32, serial21285_name) 329 != NULL ? 0 : -EBUSY; 330} 331 332static void serial21285_config_port(struct uart_port *port, int flags) 333{ 334 if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0) 335 port->type = PORT_21285; 336} 337 338/* 339 * verify the new serial_struct (for TIOCSSERIAL). 340 */ 341static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser) 342{ 343 int ret = 0; 344 if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) 345 ret = -EINVAL; 346 if (ser->irq != NO_IRQ) 347 ret = -EINVAL; 348 if (ser->baud_base != port->uartclk / 16) 349 ret = -EINVAL; 350 return ret; 351} 352 353static struct uart_ops serial21285_ops = { 354 .tx_empty = serial21285_tx_empty, 355 .get_mctrl = serial21285_get_mctrl, 356 .set_mctrl = serial21285_set_mctrl, 357 .stop_tx = serial21285_stop_tx, 358 .start_tx = serial21285_start_tx, 359 .stop_rx = serial21285_stop_rx, 360 .enable_ms = serial21285_enable_ms, 361 .break_ctl = serial21285_break_ctl, 362 .startup = serial21285_startup, 363 .shutdown = serial21285_shutdown, 364 .set_termios = serial21285_set_termios, 365 .type = serial21285_type, 366 .release_port = serial21285_release_port, 367 .request_port = serial21285_request_port, 368 .config_port = serial21285_config_port, 369 .verify_port = serial21285_verify_port, 370}; 371 372static struct uart_port serial21285_port = { 373 .mapbase = 0x42000160, 374 .iotype = SERIAL_IO_MEM, 375 .irq = NO_IRQ, 376 .fifosize = 16, 377 .ops = &serial21285_ops, 378 .flags = ASYNC_BOOT_AUTOCONF, 379}; 380 381static void serial21285_setup_ports(void) 382{ 383 serial21285_port.uartclk = mem_fclk_21285 / 4; 384} 385 386#ifdef CONFIG_SERIAL_21285_CONSOLE 387 388static void 389serial21285_console_write(struct console *co, const char *s, 390 unsigned int count) 391{ 392 int i; 393 394 for (i = 0; i < count; i++) { 395 while (*CSR_UARTFLG & 0x20) 396 barrier(); 397 *CSR_UARTDR = s[i]; 398 if (s[i] == '\n') { 399 while (*CSR_UARTFLG & 0x20) 400 barrier(); 401 *CSR_UARTDR = '\r'; 402 } 403 } 404} 405 406static void __init 407serial21285_get_options(struct uart_port *port, int *baud, 408 int *parity, int *bits) 409{ 410 if (*CSR_UARTCON == 1) { 411 unsigned int tmp; 412 413 tmp = *CSR_H_UBRLCR; 414 switch (tmp & 0x60) { 415 case 0x00: 416 *bits = 5; 417 break; 418 case 0x20: 419 *bits = 6; 420 break; 421 case 0x40: 422 *bits = 7; 423 break; 424 default: 425 case 0x60: 426 *bits = 8; 427 break; 428 } 429 430 if (tmp & H_UBRLCR_PARENB) { 431 *parity = 'o'; 432 if (tmp & H_UBRLCR_PAREVN) 433 *parity = 'e'; 434 } 435 436 tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8); 437 438 *baud = port->uartclk / (16 * (tmp + 1)); 439 } 440} 441 442static int __init serial21285_console_setup(struct console *co, char *options) 443{ 444 struct uart_port *port = &serial21285_port; 445 int baud = 9600; 446 int bits = 8; 447 int parity = 'n'; 448 int flow = 'n'; 449 450 if (machine_is_personal_server()) 451 baud = 57600; 452 453 /* 454 * Check whether an invalid uart number has been specified, and 455 * if so, search for the first available port that does have 456 * console support. 457 */ 458 if (options) 459 uart_parse_options(options, &baud, &parity, &bits, &flow); 460 else 461 serial21285_get_options(port, &baud, &parity, &bits); 462 463 return uart_set_options(port, co, baud, parity, bits, flow); 464} 465 466extern struct uart_driver serial21285_reg; 467 468static struct console serial21285_console = 469{ 470 .name = SERIAL_21285_NAME, 471 .write = serial21285_console_write, 472 .device = uart_console_device, 473 .setup = serial21285_console_setup, 474 .flags = CON_PRINTBUFFER, 475 .index = -1, 476 .data = &serial21285_reg, 477}; 478 479static int __init rs285_console_init(void) 480{ 481 serial21285_setup_ports(); 482 register_console(&serial21285_console); 483 return 0; 484} 485console_initcall(rs285_console_init); 486 487#define SERIAL_21285_CONSOLE &serial21285_console 488#else 489#define SERIAL_21285_CONSOLE NULL 490#endif 491 492static struct uart_driver serial21285_reg = { 493 .owner = THIS_MODULE, 494 .driver_name = "ttyFB", 495 .dev_name = "ttyFB", 496 .devfs_name = "ttyFB", 497 .major = SERIAL_21285_MAJOR, 498 .minor = SERIAL_21285_MINOR, 499 .nr = 1, 500 .cons = SERIAL_21285_CONSOLE, 501}; 502 503static int __init serial21285_init(void) 504{ 505 int ret; 506 507 printk(KERN_INFO "Serial: 21285 driver $Revision: 1.37 $\n"); 508 509 serial21285_setup_ports(); 510 511 ret = uart_register_driver(&serial21285_reg); 512 if (ret == 0) 513 uart_add_one_port(&serial21285_reg, &serial21285_port); 514 515 return ret; 516} 517 518static void __exit serial21285_exit(void) 519{ 520 uart_remove_one_port(&serial21285_reg, &serial21285_port); 521 uart_unregister_driver(&serial21285_reg); 522} 523 524module_init(serial21285_init); 525module_exit(serial21285_exit); 526 527MODULE_LICENSE("GPL"); 528MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $"); 529MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);