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 v3.11-rc4 479 lines 12 kB view raw
1/* 2 * Serial Port driver for a NWP uart device 3 * 4 * Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 * 11 */ 12#include <linux/init.h> 13#include <linux/export.h> 14#include <linux/console.h> 15#include <linux/serial.h> 16#include <linux/serial_reg.h> 17#include <linux/serial_core.h> 18#include <linux/tty.h> 19#include <linux/tty_flip.h> 20#include <linux/irqreturn.h> 21#include <linux/mutex.h> 22#include <linux/of_platform.h> 23#include <linux/of_device.h> 24#include <linux/nwpserial.h> 25#include <asm/prom.h> 26#include <asm/dcr.h> 27 28#define NWPSERIAL_NR 2 29 30#define NWPSERIAL_STATUS_RXVALID 0x1 31#define NWPSERIAL_STATUS_TXFULL 0x2 32 33struct nwpserial_port { 34 struct uart_port port; 35 dcr_host_t dcr_host; 36 unsigned int ier; 37 unsigned int mcr; 38}; 39 40static DEFINE_MUTEX(nwpserial_mutex); 41static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR]; 42 43static void wait_for_bits(struct nwpserial_port *up, int bits) 44{ 45 unsigned int status, tmout = 10000; 46 47 /* Wait up to 10ms for the character(s) to be sent. */ 48 do { 49 status = dcr_read(up->dcr_host, UART_LSR); 50 51 if (--tmout == 0) 52 break; 53 udelay(1); 54 } while ((status & bits) != bits); 55} 56 57#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE 58static void nwpserial_console_putchar(struct uart_port *port, int c) 59{ 60 struct nwpserial_port *up; 61 up = container_of(port, struct nwpserial_port, port); 62 /* check if tx buffer is full */ 63 wait_for_bits(up, UART_LSR_THRE); 64 dcr_write(up->dcr_host, UART_TX, c); 65 up->port.icount.tx++; 66} 67 68static void 69nwpserial_console_write(struct console *co, const char *s, unsigned int count) 70{ 71 struct nwpserial_port *up = &nwpserial_ports[co->index]; 72 unsigned long flags; 73 int locked = 1; 74 75 if (oops_in_progress) 76 locked = spin_trylock_irqsave(&up->port.lock, flags); 77 else 78 spin_lock_irqsave(&up->port.lock, flags); 79 80 /* save and disable interrupt */ 81 up->ier = dcr_read(up->dcr_host, UART_IER); 82 dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI); 83 84 uart_console_write(&up->port, s, count, nwpserial_console_putchar); 85 86 /* wait for transmitter to become empty */ 87 while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0) 88 cpu_relax(); 89 90 /* restore interrupt state */ 91 dcr_write(up->dcr_host, UART_IER, up->ier); 92 93 if (locked) 94 spin_unlock_irqrestore(&up->port.lock, flags); 95} 96 97static struct uart_driver nwpserial_reg; 98static struct console nwpserial_console = { 99 .name = "ttySQ", 100 .write = nwpserial_console_write, 101 .device = uart_console_device, 102 .flags = CON_PRINTBUFFER, 103 .index = -1, 104 .data = &nwpserial_reg, 105}; 106#define NWPSERIAL_CONSOLE (&nwpserial_console) 107#else 108#define NWPSERIAL_CONSOLE NULL 109#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ 110 111/**************************************************************************/ 112 113static int nwpserial_request_port(struct uart_port *port) 114{ 115 return 0; 116} 117 118static void nwpserial_release_port(struct uart_port *port) 119{ 120 /* N/A */ 121} 122 123static void nwpserial_config_port(struct uart_port *port, int flags) 124{ 125 port->type = PORT_NWPSERIAL; 126} 127 128static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) 129{ 130 struct nwpserial_port *up = dev_id; 131 struct tty_port *port = &up->port.state->port; 132 irqreturn_t ret; 133 unsigned int iir; 134 unsigned char ch; 135 136 spin_lock(&up->port.lock); 137 138 /* check if the uart was the interrupt source. */ 139 iir = dcr_read(up->dcr_host, UART_IIR); 140 if (!iir) { 141 ret = IRQ_NONE; 142 goto out; 143 } 144 145 do { 146 up->port.icount.rx++; 147 ch = dcr_read(up->dcr_host, UART_RX); 148 if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) 149 tty_insert_flip_char(port, ch, TTY_NORMAL); 150 } while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR); 151 152 tty_flip_buffer_push(port); 153 ret = IRQ_HANDLED; 154 155 /* clear interrupt */ 156 dcr_write(up->dcr_host, UART_IIR, 1); 157out: 158 spin_unlock(&up->port.lock); 159 return ret; 160} 161 162static int nwpserial_startup(struct uart_port *port) 163{ 164 struct nwpserial_port *up; 165 int err; 166 167 up = container_of(port, struct nwpserial_port, port); 168 169 /* disable flow control by default */ 170 up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE; 171 dcr_write(up->dcr_host, UART_MCR, up->mcr); 172 173 /* register interrupt handler */ 174 err = request_irq(up->port.irq, nwpserial_interrupt, 175 IRQF_SHARED, "nwpserial", up); 176 if (err) 177 return err; 178 179 /* enable interrupts */ 180 up->ier = UART_IER_RDI; 181 dcr_write(up->dcr_host, UART_IER, up->ier); 182 183 /* enable receiving */ 184 up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID; 185 186 return 0; 187} 188 189static void nwpserial_shutdown(struct uart_port *port) 190{ 191 struct nwpserial_port *up; 192 up = container_of(port, struct nwpserial_port, port); 193 194 /* disable receiving */ 195 up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; 196 197 /* disable interrupts from this port */ 198 up->ier = 0; 199 dcr_write(up->dcr_host, UART_IER, up->ier); 200 201 /* free irq */ 202 free_irq(up->port.irq, up); 203} 204 205static int nwpserial_verify_port(struct uart_port *port, 206 struct serial_struct *ser) 207{ 208 return -EINVAL; 209} 210 211static const char *nwpserial_type(struct uart_port *port) 212{ 213 return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL; 214} 215 216static void nwpserial_set_termios(struct uart_port *port, 217 struct ktermios *termios, struct ktermios *old) 218{ 219 struct nwpserial_port *up; 220 up = container_of(port, struct nwpserial_port, port); 221 222 up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID 223 | NWPSERIAL_STATUS_TXFULL; 224 225 up->port.ignore_status_mask = 0; 226 /* ignore all characters if CREAD is not set */ 227 if ((termios->c_cflag & CREAD) == 0) 228 up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; 229 230 /* Copy back the old hardware settings */ 231 if (old) 232 tty_termios_copy_hw(termios, old); 233} 234 235static void nwpserial_break_ctl(struct uart_port *port, int ctl) 236{ 237 /* N/A */ 238} 239 240static void nwpserial_enable_ms(struct uart_port *port) 241{ 242 /* N/A */ 243} 244 245static void nwpserial_stop_rx(struct uart_port *port) 246{ 247 struct nwpserial_port *up; 248 up = container_of(port, struct nwpserial_port, port); 249 /* don't forward any more data (like !CREAD) */ 250 up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID; 251} 252 253static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c) 254{ 255 /* check if tx buffer is full */ 256 wait_for_bits(up, UART_LSR_THRE); 257 dcr_write(up->dcr_host, UART_TX, c); 258 up->port.icount.tx++; 259} 260 261static void nwpserial_start_tx(struct uart_port *port) 262{ 263 struct nwpserial_port *up; 264 struct circ_buf *xmit; 265 up = container_of(port, struct nwpserial_port, port); 266 xmit = &up->port.state->xmit; 267 268 if (port->x_char) { 269 nwpserial_putchar(up, up->port.x_char); 270 port->x_char = 0; 271 } 272 273 while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) { 274 nwpserial_putchar(up, xmit->buf[xmit->tail]); 275 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); 276 } 277} 278 279static unsigned int nwpserial_get_mctrl(struct uart_port *port) 280{ 281 return 0; 282} 283 284static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl) 285{ 286 /* N/A */ 287} 288 289static void nwpserial_stop_tx(struct uart_port *port) 290{ 291 /* N/A */ 292} 293 294static unsigned int nwpserial_tx_empty(struct uart_port *port) 295{ 296 struct nwpserial_port *up; 297 unsigned long flags; 298 int ret; 299 up = container_of(port, struct nwpserial_port, port); 300 301 spin_lock_irqsave(&up->port.lock, flags); 302 ret = dcr_read(up->dcr_host, UART_LSR); 303 spin_unlock_irqrestore(&up->port.lock, flags); 304 305 return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0; 306} 307 308static struct uart_ops nwpserial_pops = { 309 .tx_empty = nwpserial_tx_empty, 310 .set_mctrl = nwpserial_set_mctrl, 311 .get_mctrl = nwpserial_get_mctrl, 312 .stop_tx = nwpserial_stop_tx, 313 .start_tx = nwpserial_start_tx, 314 .stop_rx = nwpserial_stop_rx, 315 .enable_ms = nwpserial_enable_ms, 316 .break_ctl = nwpserial_break_ctl, 317 .startup = nwpserial_startup, 318 .shutdown = nwpserial_shutdown, 319 .set_termios = nwpserial_set_termios, 320 .type = nwpserial_type, 321 .release_port = nwpserial_release_port, 322 .request_port = nwpserial_request_port, 323 .config_port = nwpserial_config_port, 324 .verify_port = nwpserial_verify_port, 325}; 326 327static struct uart_driver nwpserial_reg = { 328 .owner = THIS_MODULE, 329 .driver_name = "nwpserial", 330 .dev_name = "ttySQ", 331 .major = TTY_MAJOR, 332 .minor = 68, 333 .nr = NWPSERIAL_NR, 334 .cons = NWPSERIAL_CONSOLE, 335}; 336 337int nwpserial_register_port(struct uart_port *port) 338{ 339 struct nwpserial_port *up = NULL; 340 int ret = -1; 341 int i; 342 static int first = 1; 343 int dcr_len; 344 int dcr_base; 345 struct device_node *dn; 346 347 mutex_lock(&nwpserial_mutex); 348 349 dn = port->dev->of_node; 350 if (dn == NULL) 351 goto out; 352 353 /* get dcr base. */ 354 dcr_base = dcr_resource_start(dn, 0); 355 356 /* find matching entry */ 357 for (i = 0; i < NWPSERIAL_NR; i++) 358 if (nwpserial_ports[i].port.iobase == dcr_base) { 359 up = &nwpserial_ports[i]; 360 break; 361 } 362 363 /* we didn't find a mtching entry, search for a free port */ 364 if (up == NULL) 365 for (i = 0; i < NWPSERIAL_NR; i++) 366 if (nwpserial_ports[i].port.type == PORT_UNKNOWN && 367 nwpserial_ports[i].port.iobase == 0) { 368 up = &nwpserial_ports[i]; 369 break; 370 } 371 372 if (up == NULL) { 373 ret = -EBUSY; 374 goto out; 375 } 376 377 if (first) 378 uart_register_driver(&nwpserial_reg); 379 first = 0; 380 381 up->port.membase = port->membase; 382 up->port.irq = port->irq; 383 up->port.uartclk = port->uartclk; 384 up->port.fifosize = port->fifosize; 385 up->port.regshift = port->regshift; 386 up->port.iotype = port->iotype; 387 up->port.flags = port->flags; 388 up->port.mapbase = port->mapbase; 389 up->port.private_data = port->private_data; 390 391 if (port->dev) 392 up->port.dev = port->dev; 393 394 if (up->port.iobase != dcr_base) { 395 up->port.ops = &nwpserial_pops; 396 up->port.fifosize = 16; 397 398 spin_lock_init(&up->port.lock); 399 400 up->port.iobase = dcr_base; 401 dcr_len = dcr_resource_len(dn, 0); 402 403 up->dcr_host = dcr_map(dn, dcr_base, dcr_len); 404 if (!DCR_MAP_OK(up->dcr_host)) { 405 printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL"); 406 goto out; 407 } 408 } 409 410 ret = uart_add_one_port(&nwpserial_reg, &up->port); 411 if (ret == 0) 412 ret = up->port.line; 413 414out: 415 mutex_unlock(&nwpserial_mutex); 416 417 return ret; 418} 419EXPORT_SYMBOL(nwpserial_register_port); 420 421void nwpserial_unregister_port(int line) 422{ 423 struct nwpserial_port *up = &nwpserial_ports[line]; 424 mutex_lock(&nwpserial_mutex); 425 uart_remove_one_port(&nwpserial_reg, &up->port); 426 427 up->port.type = PORT_UNKNOWN; 428 429 mutex_unlock(&nwpserial_mutex); 430} 431EXPORT_SYMBOL(nwpserial_unregister_port); 432 433#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE 434static int __init nwpserial_console_init(void) 435{ 436 struct nwpserial_port *up = NULL; 437 struct device_node *dn; 438 const char *name; 439 int dcr_base; 440 int dcr_len; 441 int i; 442 443 /* search for a free port */ 444 for (i = 0; i < NWPSERIAL_NR; i++) 445 if (nwpserial_ports[i].port.type == PORT_UNKNOWN) { 446 up = &nwpserial_ports[i]; 447 break; 448 } 449 450 if (up == NULL) 451 return -1; 452 453 name = of_get_property(of_chosen, "linux,stdout-path", NULL); 454 if (name == NULL) 455 return -1; 456 457 dn = of_find_node_by_path(name); 458 if (!dn) 459 return -1; 460 461 spin_lock_init(&up->port.lock); 462 up->port.ops = &nwpserial_pops; 463 up->port.type = PORT_NWPSERIAL; 464 up->port.fifosize = 16; 465 466 dcr_base = dcr_resource_start(dn, 0); 467 dcr_len = dcr_resource_len(dn, 0); 468 up->port.iobase = dcr_base; 469 470 up->dcr_host = dcr_map(dn, dcr_base, dcr_len); 471 if (!DCR_MAP_OK(up->dcr_host)) { 472 printk("Cannot map DCR resources for SERIAL"); 473 return -1; 474 } 475 register_console(&nwpserial_console); 476 return 0; 477} 478console_initcall(nwpserial_console_init); 479#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */