MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / serial / p2001_uart.c
bloba1022ee4bcb5a0cad3abb37c4a62c4238e70a891
1 /*
2 * linux/drivers/char/p2001_uart.c
4 * Driver for P2001 uart port
6 * Copyright (C) 2004 Tobias Lorenz
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Version 1.0: First working version
25 * Version 1.1: Removed all READ_REG/WRITE_REG
26 * Version 1.2: Break handling
27 * Version 1.3: Hardware handshake
28 * Device naming, major/minor nr for setserial
29 * ISR cleanups
32 #include <linux/config.h>
33 #include <linux/module.h>
34 #include <linux/tty.h>
35 #include <linux/ioport.h>
36 #include <linux/init.h>
37 #include <linux/serial.h>
38 #include <linux/console.h>
39 #include <linux/sysrq.h>
40 #include <linux/device.h>
41 #include <linux/serial_core.h>
43 #include <asm/io.h>
44 #include <asm/irq.h>
45 #include <asm/hardware.h>
47 #if defined(CONFIG_P2001_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
48 #define SUPPORT_SYSRQ
49 #endif
52 /**************************************************************************
53 * Definitions
54 **************************************************************************/
55 static const char *version =
56 "p2001_uart.c:v1.3 10/02/2004 Tobias Lorenz (tobias.lorenz@gmx.net)\n";
58 static const char p2001_uart_name[] = "P2001 uart";
60 #define TX_MIN_BUF 10
62 #define tx_enabled(port) ((port)->unused[0])
63 #define rx_enabled(port) ((port)->unused[1])
65 extern struct uart_driver p2001_uart_driver; /* UART Driver */
66 extern struct uart_port p2001_uart_port; /* UART Port */
67 extern struct uart_ops p2001_uart_ops; /* UART Operations */
68 extern struct console p2001_console; /* Console */
72 /**************************************************************************
73 * UART Driver
74 **************************************************************************/
76 static struct uart_driver p2001_uart_driver = {
77 .owner = THIS_MODULE,
78 .driver_name = "serial", /* name of tty/console device */
79 .dev_name = "ttyS", /* name of tty/console device */
80 #ifdef CONFIG_DEVFS_FS
81 .devfs_name = "tts/", /* name of tty/console device */
82 #endif
83 .major = 4, /* major number for the driver */
84 .minor = 64, /* starting minor number */
85 .nr = 1, /* maximum number of serial ports this driver supports */
86 #ifdef CONFIG_P2001_UART_CONSOLE
87 .cons = &p2001_console,
88 #endif
93 /**************************************************************************
94 * UART Port
95 **************************************************************************/
97 static struct uart_port p2001_uart_port = {
98 .membase = (void*)P2001_UART, /* read/write[bwl] */
99 .mapbase = (unsigned int)P2001_UART, /* for ioremap */
100 .iotype = UPIO_MEM, /* io access style */
101 .irq = IRQ_UART, /* irq number */
102 .uartclk = CONFIG_SYSCLK/8, /* base uart clock */
103 .fifosize = 32, /* tx fifo size */
104 .ops = &p2001_uart_ops,
105 .flags = UPF_BOOT_AUTOCONF,
106 .line = 0, /* port index */
111 /**************************************************************************
112 * UART interrupt routine
113 **************************************************************************/
115 /* uart interrupt send routine */
116 static void p2001_uart_tx_chars(struct uart_port *port)
118 struct circ_buf *xmit = &port->info->xmit;
119 int count;
121 if (port->x_char) {
122 while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF)
123 barrier();
124 P2001_UART->w.TX1 = port->x_char;
125 port->icount.tx++;
126 port->x_char = 0;
127 return;
129 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
130 tx_enabled(port) = 0;
131 return;
134 count = port->fifosize >> 1;
135 do {
136 while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF)
137 barrier();
138 P2001_UART->w.TX1 = xmit->buf[xmit->tail];
139 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
140 port->icount.tx++;
141 if (uart_circ_empty(xmit))
142 break;
143 } while (--count > 0);
145 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
146 uart_write_wakeup(port);
148 if (uart_circ_empty(xmit))
149 tx_enabled(port) = 0;
151 P2001_UART->w.IRQ_Status |= (1<<0);
154 /* uart interrupt receive routine */
155 static void p2001_uart_rx_chars(struct uart_port *port, struct pt_regs *regs)
157 struct tty_struct *tty = port->info->tty;
158 unsigned int status;
159 unsigned int rxddelta;
160 unsigned int rx;
161 unsigned int max_count = 256;
163 status = P2001_UART->r.IRQ_Status;
164 rxddelta = (P2001_UART->r.STATUS >> 6) & 0x3f;
165 while (rxddelta && max_count--) {
166 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
167 tty->flip.work.func((void *)tty);
168 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
169 printk(KERN_WARNING "TTY_DONT_FLIP set\n");
170 return;
174 rx = P2001_UART->r.RX1;
176 *tty->flip.char_buf_ptr = rx & 0xff;
177 *tty->flip.flag_buf_ptr = TTY_NORMAL;
178 port->icount.rx++;
181 * Note that the error handling code is
182 * out of the main execution path
184 if (status & ((1<<7)|(1<<6)|(1<<9))) {
185 if (status & (1<<7)) { /* RxD_BRK */
186 port->icount.brk++;
187 if (uart_handle_break(port))
188 goto ignore_chars;
189 } else if (status & (1<<6)) /* RxD_FIFO_PAR_ERR */
190 port->icount.parity++;
191 if (status & (1<<9)) /* RxD_LOST */
192 port->icount.overrun++;
194 status &= port->read_status_mask;
196 if (status & (1<<7)) /* RxD_BRK */
197 *tty->flip.flag_buf_ptr = TTY_BREAK;
198 else if (status & (1<<6)) /* RxD_FIFO_PAR_ERR */
199 *tty->flip.flag_buf_ptr = TTY_PARITY;
203 if (uart_handle_sysrq_char(port, ch, regs))
204 goto ignore_chars;
206 if (rx && port->ignore_status_mask == 0) {
207 tty->flip.flag_buf_ptr++;
208 tty->flip.char_buf_ptr++;
209 tty->flip.count++;
211 if ((status & (1<<9)) && /* RxD_LOST */
212 tty->flip.count < TTY_FLIPBUF_SIZE) {
214 * Overrun is special, since it's reported
215 * immediately, and doesn't affect the current
216 * character
218 *tty->flip.char_buf_ptr++ = 0;
219 *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
220 tty->flip.count++;
222 ignore_chars:
223 rxddelta = (P2001_UART->r.STATUS >> 6) & 0x3f;
225 tty_flip_buffer_push(tty);
227 P2001_UART->w.IRQ_Status |= (1<<3) | (1<<6) | (1<<7) | (1<<9);
230 /* uart interrupt routine */
231 static irqreturn_t p2001_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
233 struct uart_port *port = dev_id;
234 unsigned int status;
236 spin_lock(&port->lock);
238 status = P2001_UART->r.IRQ_Status;
239 // TXD_SEND | TXD_LAST_DATA
240 if (status & (1<<0)) // (1<<2)
241 p2001_uart_tx_chars(port);
242 // RXD_DATA | RxD_FIFO_PAR_ERR | RxD_BRK | RxD_LOST
243 if (status & ((1<<3) | (1<<6) | (1<<7) | (1<<9)))
244 p2001_uart_rx_chars(port, regs);
246 //status &= ~((1<<0) | (1<<2) | (1<<3));
247 //if (status & 0x3ff)
248 // printk(KERN_INFO "p2001_uart_interrupt: status=0x%8.8x\n", status);
250 P2001_UART->w.IRQ_Status &= ~0x3ff;
252 spin_unlock(&port->lock);
254 return IRQ_HANDLED;
259 /**************************************************************************
260 * UART Operations
261 **************************************************************************/
263 /* returns if the port transmitter is empty or not. */
264 static unsigned int p2001_uart_ops_tx_empty(struct uart_port *port)
266 unsigned int txddelta = P2001_UART->r.STATUS & 0x3f;
267 return (txddelta > 0) ? 0 : TIOCSER_TEMT;
270 /* sets a new value for the MCR UART register. */
271 static void p2001_uart_ops_set_mctrl(struct uart_port *port, unsigned int mctrl)
273 /* no modem control lines */
276 /* gets the current MCR UART register value. */
277 static unsigned int p2001_uart_ops_get_mctrl(struct uart_port *port)
279 /* no modem control lines */
280 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
283 /* stops the port from sending data. */
284 static void p2001_uart_ops_stop_tx(struct uart_port *port, unsigned int tty_stop)
286 if (tx_enabled(port)) {
287 P2001_UART->w.IRQ_Status &= ~((1<<20) | (1<<22)); // TXD_SEND | TXD_LAST_DATA
288 tx_enabled(port) = 0;
292 /* starts the port sending data. */
293 static void p2001_uart_ops_start_tx(struct uart_port *port, unsigned int tty_start)
295 if (!tx_enabled(port)) {
296 P2001_UART->w.IRQ_Status |= (1<<20) | (1<<22); // TXD_SEND | TXD_LAST_DATA
297 tx_enabled(port) = 1;
299 p2001_uart_tx_chars(port);
302 /* tells the port to send the XOFF character to the host. */
303 #if 0
304 static void p2001_uart_ops_send_xchar(struct uart_port *port, char ch)
306 #warning "p2001_uart_ops_send_xchar is not implemented."
308 #endif
310 /* stops receiving data. */
311 static void p2001_uart_ops_stop_rx(struct uart_port *port)
313 if (rx_enabled(port)) {
314 P2001_UART->w.IRQ_Status &= ~(1<<23); // RXD_DATA
315 rx_enabled(port) = 0;
319 /* enables the modem status interrupts. */
320 static void p2001_uart_ops_enable_ms(struct uart_port *port)
322 /* empty */
325 /* sends the BREAK value over the port. */
326 static void p2001_uart_ops_break_ctl(struct uart_port *port, int ctl)
328 /* no break signal */
331 /* called once each time the open call happens */
332 static int p2001_uart_ops_startup(struct uart_port *port)
334 int ret;
336 tx_enabled(port) = 1;
337 rx_enabled(port) = 1;
339 ret = request_irq(port->irq, p2001_uart_interrupt, 0, p2001_uart_name, port);
341 P2001_UART->w.Clear = 0;
342 // TXD_SEND | TXD_LAST_DATA
343 P2001_UART->w.IRQ_Status |= (1<<20) | (1<<22);
344 // RXD_DATA | RxD_FIFO_PAR_ERR | RxD_BRK | RxD_LOST
345 P2001_UART->w.IRQ_Status |= (1<<23) | (1<<26) | (1<<27) | (1<<29);
347 return ret;
350 /* called when the port is closed */
351 static void p2001_uart_ops_shutdown(struct uart_port *port)
353 free_irq(port->irq, port);
356 /* called whenever the port line settings need to be modified */
357 static void p2001_uart_ops_set_termios(struct uart_port *port, struct termios *new, struct termios *old)
359 unsigned int config;
360 unsigned long flags;
361 unsigned int baud, quot;
364 * Ask the core to calculate the divisor for us.
366 baud = uart_get_baud_rate(port, new, old, 0, port->uartclk); // min:0/max:port->uartclk
367 quot = (port->uartclk * 3)/baud;
369 /* interrupt level */
370 config = (12 << 11) | (12 << 17); /* RXDHIGHWATER = 12, TXDLOWWATER = 12 */
372 /* data bits */
373 switch (new->c_cflag & CSIZE) {
374 case CS5:
375 config |= (5 << 5); /* WORDLENGTH = 5 */
376 break;
377 case CS6:
378 config |= (6 << 5); /* WORDLENGTH = 6 */
379 break;
380 case CS7:
381 config |= (7 << 5); /* WORDLENGTH = 7 */
382 break;
383 default: /* CS8 */
384 config |= (8 << 5); /* WORDLENGTH = 8 */
385 break;
388 /* parity */
389 if (new->c_cflag & PARENB) {
390 if (!(new->c_cflag & PARODD))
391 config |= (1 << 2); /* PARITYMODE = 1 (Even Parity) */
392 else
393 config |= (2 << 2); /* PARITYMODE = 2 (Odd Parity) */
396 /* stop bits */
397 if (new->c_cflag & CSTOPB)
398 config |= (1 << 0); /* STOPBITAW = 1 (1 Stopbit) */
400 /* hardware flow control */
401 if (new->c_cflag & CRTSCTS) {
402 config |= (1 << 10); /* USECTS = 1 */
403 P2001_GPIO->PIN_MUX |= (1<<5);
404 } else {
405 P2001_GPIO->PIN_MUX &= ~(1<<5);
408 spin_lock_irqsave(&port->lock, flags);
411 * Update the per-port timeout.
413 uart_update_timeout(port, new->c_cflag, baud);
415 port->read_status_mask = (1<<9); /* RXD_DATA_LOST */
416 if (new->c_iflag & INPCK)
417 port->read_status_mask |= (1<<6); /* RxD_FIFO_PAR_ERR */
418 if (new->c_iflag & (BRKINT | PARMRK))
419 port->read_status_mask |= (1<<7); /* RxD_BRK */
422 * Characters to ignore
424 port->ignore_status_mask = 0;
425 if (new->c_iflag & IGNPAR)
426 port->ignore_status_mask |= (1<<6); /* RxD_FIFO_PAR_ERR */
427 if (new->c_iflag & IGNBRK) {
428 port->ignore_status_mask |= (1<<7); /* RxD_BRK */
430 * If we're ignoring parity and break indicators,
431 * ignore overruns too (for real raw support).
433 if (new->c_iflag & IGNPAR)
434 port->ignore_status_mask |= (1<<9); /* RxD_LOST */
438 * Ignore all characters if CREAD is not set.
440 if ((new->c_cflag & CREAD) == 0)
441 port->ignore_status_mask |= (1<<3); /* RXD_DATA */
443 /* Set baud rate */
444 P2001_UART->w.Baudrate = (quot<<16)+3;
445 P2001_UART->w.Config = config;
447 spin_unlock_irqrestore(&port->lock, flags);
450 /* power management: power the hardware down */
451 #ifdef CONFIG_PM
452 static void p2001_uart_ops_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
454 #warning "p2001_uart_ops_pm is not implemented."
456 #endif
458 /* power management: power the hardware up */
459 #ifdef CONFIG_PM
460 static int p2001_uart_ops_set_wake(struct uart_port *port, unsigned int state)
462 #warning "p2001_uart_ops_set_wake is not implemented."
464 #endif
467 * Return a string describing the port type
469 static const char *p2001_uart_ops_type(struct uart_port *port)
471 return port->type == PORT_P2001 ? "P2001" : NULL;
475 * Release IO and memory resources used by
476 * the port. This includes iounmap if necessary.
478 static void p2001_uart_ops_release_port(struct uart_port *port)
480 release_mem_region(port->mapbase, 0x30);
484 * Request IO and memory resources used by the
485 * port. This includes iomapping the port if
486 * necessary.
488 static int p2001_uart_ops_request_port(struct uart_port *port)
490 return request_mem_region(port->mapbase, 0x30, p2001_uart_name)
491 != NULL ? 0 : -EBUSY;
495 * Configure/autoconfigure the port.
497 static void p2001_uart_ops_config_port(struct uart_port *port, int flags)
499 if (flags & UART_CONFIG_TYPE && p2001_uart_ops_request_port(port) == 0)
500 port->type = PORT_P2001;
504 * Verify the new serial_struct (for TIOCSSERIAL).
506 static int p2001_uart_ops_verify_port(struct uart_port *port, struct serial_struct *ser)
508 int ret = 0;
509 if (ser->type != PORT_UNKNOWN && ser->type != PORT_P2001)
510 ret = -EINVAL;
511 if (ser->irq != NO_IRQ)
512 ret = -EINVAL;
513 return ret;
516 /* device specific ioctl calls */
517 #if 0
518 static int p2001_uart_ops_ioctl(struct uart_port *port, unsigned int, unsigned long)
520 #warning "p2001_uart_ops_ioctl is not implemented."
522 #endif
525 static struct uart_ops p2001_uart_ops = {
526 .tx_empty = p2001_uart_ops_tx_empty, /* returns if the port transmitter is empty or not. */
527 .set_mctrl = p2001_uart_ops_set_mctrl, /* sets a new value for the MCR UART register. */
528 .get_mctrl = p2001_uart_ops_get_mctrl, /* gets the current MCR UART register value. */
529 .stop_tx = p2001_uart_ops_stop_tx, /* stops the port from sending data. */
530 .start_tx = p2001_uart_ops_start_tx, /* starts the port sending data. */
531 // .send_xchar = p2001_uart_ops_send_xchar, /* tells the port to send the XOFF character to the host. */
532 .stop_rx = p2001_uart_ops_stop_rx, /* stops receiving data. */
533 .enable_ms = p2001_uart_ops_enable_ms, /* enables the modem status interrupts. */
534 .break_ctl = p2001_uart_ops_break_ctl, /* sends the BREAK value over the port. */
535 .startup = p2001_uart_ops_startup, /* called once each time the open call happens */
536 .shutdown = p2001_uart_ops_shutdown, /* called when the port is closed */
537 .set_termios = p2001_uart_ops_set_termios, /* called whenever the port line settings need to be modified */
538 #ifdef CONFIG_PM
539 .pm = p2001_uart_ops_pm, /* power management: power the hardware down */
540 .set_wake = p2001_uart_ops_set_wake, /* power management: power the hardware up */
541 #endif
542 .type = p2001_uart_ops_type, /* Return a string describing the port type */
543 .release_port = p2001_uart_ops_release_port, /* Release the region(s) being used by 'port' */
544 .request_port = p2001_uart_ops_request_port, /* Request the region(s) being used by 'port' */
545 .config_port = p2001_uart_ops_config_port, /* Configure/autoconfigure the port. */
546 .verify_port = p2001_uart_ops_verify_port, /* Verify the new serial_struct (for TIOCSSERIAL). */
547 // .ioctl = p2001_uart_ops_ioctl, /* device specific ioctl calls */
552 /**************************************************************************
553 * Console
554 **************************************************************************/
556 #ifdef CONFIG_P2001_UART_CONSOLE
558 /* the function used to print kernel messages */
559 static void p2001_console_write(struct console *co, const char *s, unsigned int count)
561 int i;
563 for (i = 0; i < count; i++) {
564 while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF)
565 barrier();
566 P2001_UART->w.TX1 = s[i];
567 if (s[i] == '\n') {
568 while ((P2001_UART->r.STATUS & 0x3f) > TX_MIN_BUF)
569 barrier();
570 P2001_UART->w.TX1 = '\r';
575 /* the function is called when the console= command-line argument matches the name for this console structure. */
576 static int __init p2001_console_setup(struct console *co, char *options)
578 struct uart_port *port = &p2001_uart_port;
579 int baud = 57600;
580 int parity = 'n';
581 int bits = 8;
582 int flow = 'n';
584 if (options)
585 uart_parse_options(options, &baud, &parity, &bits, &flow);
587 return uart_set_options(port, co, baud, parity, bits, flow);
591 static struct console p2001_console = {
592 .name = "ttyS", /* the name of the console device is used to parse the console= command line option. */
593 .write = p2001_console_write, /* the function used to print kernel messages */
594 // .read = p2001_console_read, /* ??? */
595 .device = uart_console_device, /* a function that returns the device number for the underlying tty device that is currently acting as a console */
596 // .unblank = p2001_console_unblank, /* the function, if defined, is used to unblank the screen. */
597 .setup = p2001_console_setup, /* the function is called when the console= command-line argument matches the name for this console structure. */
598 .flags = CON_PRINTBUFFER, /* various console flags */
599 .index = -1, /* the number of the device acting as a console in an array of devices. */
600 // .cflag = 0,
601 .data = &p2001_uart_driver,
604 static int __init p2001_console_init(void)
606 register_console(&p2001_console);
607 return 0;
609 console_initcall(p2001_console_init);
610 #endif
614 /**************************************************************************
615 * Module functions
616 **************************************************************************/
618 static int __init p2001_uart_init(void)
620 int ret;
622 printk(version);
623 ret = uart_register_driver(&p2001_uart_driver);
624 if (ret == 0)
625 uart_add_one_port(&p2001_uart_driver, &p2001_uart_port);
627 return ret;
630 static void __exit p2001_uart_exit(void)
632 uart_remove_one_port(&p2001_uart_driver, &p2001_uart_port);
633 uart_unregister_driver(&p2001_uart_driver);
636 module_init(p2001_uart_init);
637 module_exit(p2001_uart_exit);
639 MODULE_AUTHOR("Tobias Lorenz");
640 MODULE_DESCRIPTION("P2001 uart driver");
641 MODULE_LICENSE("GPL");