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