ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / serial / amba-pl011.c
1 /*
2  *  linux/drivers/char/amba.c
3  *
4  *  Driver for AMBA serial ports
5  *
6  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
7  *
8  *  Copyright 1999 ARM Limited
9  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  *  $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $
26  *
27  * This is a generic driver for ARM AMBA-type serial ports.  They
28  * have a lot of 16550-like features, but are not register compatible.
29  * Note that although they do have CTS, DCD and DSR inputs, they do
30  * not have an RI input, nor do they have DTR or RTS outputs.  If
31  * required, these have to be supplied via some other means (eg, GPIO)
32  * and hooked into this driver.
33  */
34 #include <linux/config.h>
35 #include <linux/module.h>
36 #include <linux/tty.h>
37 #include <linux/ioport.h>
38 #include <linux/init.h>
39 #include <linux/serial.h>
40 #include <linux/console.h>
41 #include <linux/sysrq.h>
42 #include <linux/device.h>
43
44 #include <asm/io.h>
45 #include <asm/irq.h>
46 #include <asm/hardware/amba.h>
47
48 #if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
49 #define SUPPORT_SYSRQ
50 #endif
51
52 #include <linux/serial_core.h>
53
54 #include <asm/hardware/amba_serial.h>
55
56 #define UART_NR                 14
57
58 #define SERIAL_AMBA_MAJOR       204
59 #define SERIAL_AMBA_MINOR       64
60 #define SERIAL_AMBA_NR          UART_NR
61
62 #define AMBA_ISR_PASS_LIMIT     256
63
64 #define UART_DUMMY_RSR_RX       256
65
66 /*
67  * We wrap our port structure around the generic uart_port.
68  */
69 struct uart_amba_port {
70         struct uart_port        port;
71         unsigned int            im;     /* interrupt mask */
72         unsigned int            old_status;
73 };
74
75 static void pl011_stop_tx(struct uart_port *port, unsigned int tty_stop)
76 {
77         struct uart_amba_port *uap = (struct uart_amba_port *)port;
78
79         uap->im &= ~UART011_TXIM;
80         writew(uap->im, uap->port.membase + UART011_IMSC);
81 }
82
83 static void pl011_start_tx(struct uart_port *port, unsigned int tty_start)
84 {
85         struct uart_amba_port *uap = (struct uart_amba_port *)port;
86
87         uap->im |= UART011_TXIM;
88         writew(uap->im, uap->port.membase + UART011_IMSC);
89 }
90
91 static void pl011_stop_rx(struct uart_port *port)
92 {
93         struct uart_amba_port *uap = (struct uart_amba_port *)port;
94
95         uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
96                      UART011_PEIM|UART011_BEIM|UART011_OEIM);
97         writew(uap->im, uap->port.membase + UART011_IMSC);
98 }
99
100 static void pl011_enable_ms(struct uart_port *port)
101 {
102         struct uart_amba_port *uap = (struct uart_amba_port *)port;
103
104         uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
105         writew(uap->im, uap->port.membase + UART011_IMSC);
106 }
107
108 static void
109 #ifdef SUPPORT_SYSRQ
110 pl011_rx_chars(struct uart_amba_port *uap, struct pt_regs *regs)
111 #else
112 pl011_rx_chars(struct uart_amba_port *uap)
113 #endif
114 {
115         struct tty_struct *tty = uap->port.info->tty;
116         unsigned int status, ch, rsr, max_count = 256;
117
118         status = readw(uap->port.membase + UART01x_FR);
119         while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
120                 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
121                         tty->flip.work.func((void *)tty);
122                         if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
123                                 printk(KERN_WARNING "TTY_DONT_FLIP set\n");
124                                 return;
125                         }
126                 }
127
128                 ch = readw(uap->port.membase + UART01x_DR);
129
130                 *tty->flip.char_buf_ptr = ch;
131                 *tty->flip.flag_buf_ptr = TTY_NORMAL;
132                 uap->port.icount.rx++;
133
134                 /*
135                  * Note that the error handling code is
136                  * out of the main execution path
137                  */
138                 rsr = readw(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
139                 if (rsr & UART01x_RSR_ANY) {
140                         if (rsr & UART01x_RSR_BE) {
141                                 rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
142                                 uap->port.icount.brk++;
143                                 if (uart_handle_break(&uap->port))
144                                         goto ignore_char;
145                         } else if (rsr & UART01x_RSR_PE)
146                                 uap->port.icount.parity++;
147                         else if (rsr & UART01x_RSR_FE)
148                                 uap->port.icount.frame++;
149                         if (rsr & UART01x_RSR_OE)
150                                 uap->port.icount.overrun++;
151
152                         rsr &= uap->port.read_status_mask;
153
154                         if (rsr & UART01x_RSR_BE)
155                                 *tty->flip.flag_buf_ptr = TTY_BREAK;
156                         else if (rsr & UART01x_RSR_PE)
157                                 *tty->flip.flag_buf_ptr = TTY_PARITY;
158                         else if (rsr & UART01x_RSR_FE)
159                                 *tty->flip.flag_buf_ptr = TTY_FRAME;
160                 }
161
162                 if (uart_handle_sysrq_char(&uap->port, ch, regs))
163                         goto ignore_char;
164
165                 if ((rsr & uap->port.ignore_status_mask) == 0) {
166                         tty->flip.flag_buf_ptr++;
167                         tty->flip.char_buf_ptr++;
168                         tty->flip.count++;
169                 }
170                 if ((rsr & UART01x_RSR_OE) &&
171                     tty->flip.count < TTY_FLIPBUF_SIZE) {
172                         /*
173                          * Overrun is special, since it's reported
174                          * immediately, and doesn't affect the current
175                          * character
176                          */
177                         *tty->flip.char_buf_ptr++ = 0;
178                         *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
179                         tty->flip.count++;
180                 }
181         ignore_char:
182                 status = readw(uap->port.membase + UART01x_FR);
183         }
184         tty_flip_buffer_push(tty);
185         return;
186 }
187
188 static void pl011_tx_chars(struct uart_amba_port *uap)
189 {
190         struct circ_buf *xmit = &uap->port.info->xmit;
191         int count;
192
193         if (uap->port.x_char) {
194                 writew(uap->port.x_char, uap->port.membase + UART01x_DR);
195                 uap->port.icount.tx++;
196                 uap->port.x_char = 0;
197                 return;
198         }
199         if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
200                 pl011_stop_tx(&uap->port, 0);
201                 return;
202         }
203
204         count = uap->port.fifosize >> 1;
205         do {
206                 writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
207                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
208                 uap->port.icount.tx++;
209                 if (uart_circ_empty(xmit))
210                         break;
211         } while (--count > 0);
212
213         if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
214                 uart_write_wakeup(&uap->port);
215
216         if (uart_circ_empty(xmit))
217                 pl011_stop_tx(&uap->port, 0);
218 }
219
220 static void pl011_modem_status(struct uart_amba_port *uap)
221 {
222         unsigned int status, delta;
223
224         status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
225
226         delta = status ^ uap->old_status;
227         uap->old_status = status;
228
229         if (!delta)
230                 return;
231
232         if (delta & UART01x_FR_DCD)
233                 uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
234
235         if (delta & UART01x_FR_DSR)
236                 uap->port.icount.dsr++;
237
238         if (delta & UART01x_FR_CTS)
239                 uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
240
241         wake_up_interruptible(&uap->port.info->delta_msr_wait);
242 }
243
244 static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
245 {
246         struct uart_amba_port *uap = dev_id;
247         unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
248         int handled = 0;
249
250         spin_lock(&uap->port.lock);
251
252         status = readw(uap->port.membase + UART011_MIS);
253         if (status) {
254                 do {
255                         writew(status & ~(UART011_TXIS|UART011_RTIS|
256                                           UART011_RXIS),
257                                uap->port.membase + UART011_ICR);
258
259                         if (status & (UART011_RTIS|UART011_RXIS))
260 #ifdef SUPPORT_SYSRQ
261                                 pl011_rx_chars(uap, regs);
262 #else
263                                 pl011_rx_chars(uap);
264 #endif
265                         if (status & (UART011_DSRMIS|UART011_DCDMIS|
266                                       UART011_CTSMIS|UART011_RIMIS))
267                                 pl011_modem_status(uap);
268                         if (status & UART011_TXIS)
269                                 pl011_tx_chars(uap);
270
271                         if (pass_counter-- == 0)
272                                 break;
273
274                         status = readw(uap->port.membase + UART011_MIS);
275                 } while (status != 0);
276                 handled = 1;
277         }
278
279         spin_unlock(&uap->port.lock);
280
281         return IRQ_RETVAL(handled);
282 }
283
284 static unsigned int pl01x_tx_empty(struct uart_port *port)
285 {
286         struct uart_amba_port *uap = (struct uart_amba_port *)port;
287         unsigned int status = readw(uap->port.membase + UART01x_FR);
288         return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
289 }
290
291 static unsigned int pl01x_get_mctrl(struct uart_port *port)
292 {
293         struct uart_amba_port *uap = (struct uart_amba_port *)port;
294         unsigned int result = 0;
295         unsigned int status = readw(uap->port.membase + UART01x_FR);
296
297 #define BIT(uartbit, tiocmbit)          \
298         if (status & uartbit)           \
299                 result |= tiocmbit
300
301         BIT(UART01x_FR_DCD, TIOCM_CAR);
302         BIT(UART01x_FR_DSR, TIOCM_DSR);
303         BIT(UART01x_FR_CTS, TIOCM_CTS);
304         BIT(UART011_FR_RI, TIOCM_RNG);
305 #undef BIT
306         return result;
307 }
308
309 static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
310 {
311         struct uart_amba_port *uap = (struct uart_amba_port *)port;
312         unsigned int cr;
313
314         cr = readw(uap->port.membase + UART011_CR);
315
316 #define BIT(tiocmbit, uartbit)          \
317         if (mctrl & tiocmbit)           \
318                 cr |= uartbit;          \
319         else                            \
320                 cr &= ~uartbit
321
322         BIT(TIOCM_RTS, UART011_CR_RTS);
323         BIT(TIOCM_DTR, UART011_CR_DTR);
324         BIT(TIOCM_OUT1, UART011_CR_OUT1);
325         BIT(TIOCM_OUT2, UART011_CR_OUT2);
326         BIT(TIOCM_LOOP, UART011_CR_LBE);
327 #undef BIT
328
329         writew(cr, uap->port.membase + UART011_CR);
330 }
331
332 static void pl011_break_ctl(struct uart_port *port, int break_state)
333 {
334         struct uart_amba_port *uap = (struct uart_amba_port *)port;
335         unsigned long flags;
336         unsigned int lcr_h;
337
338         spin_lock_irqsave(&uap->port.lock, flags);
339         lcr_h = readw(uap->port.membase + UART011_LCRH);
340         if (break_state == -1)
341                 lcr_h |= UART01x_LCRH_BRK;
342         else
343                 lcr_h &= ~UART01x_LCRH_BRK;
344         writew(lcr_h, uap->port.membase + UART011_LCRH);
345         spin_unlock_irqrestore(&uap->port.lock, flags);
346 }
347
348 static int pl011_startup(struct uart_port *port)
349 {
350         struct uart_amba_port *uap = (struct uart_amba_port *)port;
351         unsigned int cr;
352         int retval;
353
354         /*
355          * Allocate the IRQ
356          */
357         retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
358         if (retval)
359                 goto out;
360
361         writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
362                uap->port.membase + UART011_IFLS);
363
364         /*
365          * Provoke TX FIFO interrupt into asserting.
366          */
367         cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
368         writew(cr, uap->port.membase + UART011_CR);
369         writew(0, uap->port.membase + UART011_FBRD);
370         writew(1, uap->port.membase + UART011_IBRD);
371         writew(0, uap->port.membase + UART011_LCRH);
372         writew(0, uap->port.membase + UART01x_DR);
373         while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
374                 barrier();
375
376         cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
377         writew(cr, uap->port.membase + UART011_CR);
378
379         /*
380          * initialise the old status of the modem signals
381          */
382         uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
383
384         /*
385          * Finally, enable interrupts
386          */
387         spin_lock_irq(&uap->port.lock);
388         uap->im = UART011_RXIM | UART011_RTIM;
389         writew(uap->im, uap->port.membase + UART011_IMSC);
390         spin_unlock_irq(&uap->port.lock);
391
392         return 0;
393
394  out:
395         return retval;
396 }
397
398 static void pl011_shutdown(struct uart_port *port)
399 {
400         struct uart_amba_port *uap = (struct uart_amba_port *)port;
401         unsigned long val;
402
403         /*
404          * disable all interrupts
405          */
406         spin_lock_irq(&uap->port.lock);
407         uap->im = 0;
408         writew(uap->im, uap->port.membase + UART011_IMSC);
409         writew(0xffff, uap->port.membase + UART011_ICR);
410         spin_unlock_irq(&uap->port.lock);
411
412         /*
413          * Free the interrupt
414          */
415         free_irq(uap->port.irq, uap);
416
417         /*
418          * disable the port
419          */
420         writew(UART01x_CR_UARTEN | UART011_CR_TXE, uap->port.membase + UART011_CR);
421
422         /*
423          * disable break condition and fifos
424          */
425         val = readw(uap->port.membase + UART011_LCRH);
426         val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
427         writew(val, uap->port.membase + UART011_LCRH);
428 }
429
430 static void
431 pl011_set_termios(struct uart_port *port, struct termios *termios,
432                      struct termios *old)
433 {
434         unsigned int lcr_h, old_cr;
435         unsigned long flags;
436         unsigned int baud, quot;
437
438         /*
439          * Ask the core to calculate the divisor for us.
440          */
441         baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
442         quot = port->uartclk * 4 / baud;
443
444         switch (termios->c_cflag & CSIZE) {
445         case CS5:
446                 lcr_h = UART01x_LCRH_WLEN_5;
447                 break;
448         case CS6:
449                 lcr_h = UART01x_LCRH_WLEN_6;
450                 break;
451         case CS7:
452                 lcr_h = UART01x_LCRH_WLEN_7;
453                 break;
454         default: // CS8
455                 lcr_h = UART01x_LCRH_WLEN_8;
456                 break;
457         }
458         if (termios->c_cflag & CSTOPB)
459                 lcr_h |= UART01x_LCRH_STP2;
460         if (termios->c_cflag & PARENB) {
461                 lcr_h |= UART01x_LCRH_PEN;
462                 if (!(termios->c_cflag & PARODD))
463                         lcr_h |= UART01x_LCRH_EPS;
464         }
465         if (port->fifosize > 1)
466                 lcr_h |= UART01x_LCRH_FEN;
467
468         spin_lock_irqsave(&port->lock, flags);
469
470         /*
471          * Update the per-port timeout.
472          */
473         uart_update_timeout(port, termios->c_cflag, baud);
474
475         port->read_status_mask = UART01x_RSR_OE;
476         if (termios->c_iflag & INPCK)
477                 port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
478         if (termios->c_iflag & (BRKINT | PARMRK))
479                 port->read_status_mask |= UART01x_RSR_BE;
480
481         /*
482          * Characters to ignore
483          */
484         port->ignore_status_mask = 0;
485         if (termios->c_iflag & IGNPAR)
486                 port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
487         if (termios->c_iflag & IGNBRK) {
488                 port->ignore_status_mask |= UART01x_RSR_BE;
489                 /*
490                  * If we're ignoring parity and break indicators,
491                  * ignore overruns too (for real raw support).
492                  */
493                 if (termios->c_iflag & IGNPAR)
494                         port->ignore_status_mask |= UART01x_RSR_OE;
495         }
496
497         /*
498          * Ignore all characters if CREAD is not set.
499          */
500         if ((termios->c_cflag & CREAD) == 0)
501                 port->ignore_status_mask |= UART_DUMMY_RSR_RX;
502
503         if (UART_ENABLE_MS(port, termios->c_cflag))
504                 pl011_enable_ms(port);
505
506         /* first, disable everything */
507         old_cr = readw(port->membase + UART011_CR);
508         writew(0, port->membase + UART011_CR);
509
510         /* Set baud rate */
511         writew(quot & 0x3f, port->membase + UART011_FBRD);
512         writew(quot >> 6, port->membase + UART011_IBRD);
513
514         /*
515          * ----------v----------v----------v----------v-----
516          * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
517          * ----------^----------^----------^----------^-----
518          */
519         writew(lcr_h, port->membase + UART011_LCRH);
520         writew(old_cr, port->membase + UART011_CR);
521
522         spin_unlock_irqrestore(&port->lock, flags);
523 }
524
525 static const char *pl011_type(struct uart_port *port)
526 {
527         return port->type == PORT_AMBA ? "AMBA/PL011" : NULL;
528 }
529
530 /*
531  * Release the memory region(s) being used by 'port'
532  */
533 static void pl010_release_port(struct uart_port *port)
534 {
535         release_mem_region(port->mapbase, SZ_4K);
536 }
537
538 /*
539  * Request the memory region(s) being used by 'port'
540  */
541 static int pl010_request_port(struct uart_port *port)
542 {
543         return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
544                         != NULL ? 0 : -EBUSY;
545 }
546
547 /*
548  * Configure/autoconfigure the port.
549  */
550 static void pl010_config_port(struct uart_port *port, int flags)
551 {
552         if (flags & UART_CONFIG_TYPE) {
553                 port->type = PORT_AMBA;
554                 pl010_request_port(port);
555         }
556 }
557
558 /*
559  * verify the new serial_struct (for TIOCSSERIAL).
560  */
561 static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
562 {
563         int ret = 0;
564         if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
565                 ret = -EINVAL;
566         if (ser->irq < 0 || ser->irq >= NR_IRQS)
567                 ret = -EINVAL;
568         if (ser->baud_base < 9600)
569                 ret = -EINVAL;
570         return ret;
571 }
572
573 static struct uart_ops amba_pl011_pops = {
574         .tx_empty       = pl01x_tx_empty,
575         .set_mctrl      = pl011_set_mctrl,
576         .get_mctrl      = pl01x_get_mctrl,
577         .stop_tx        = pl011_stop_tx,
578         .start_tx       = pl011_start_tx,
579         .stop_rx        = pl011_stop_rx,
580         .enable_ms      = pl011_enable_ms,
581         .break_ctl      = pl011_break_ctl,
582         .startup        = pl011_startup,
583         .shutdown       = pl011_shutdown,
584         .set_termios    = pl011_set_termios,
585         .type           = pl011_type,
586         .release_port   = pl010_release_port,
587         .request_port   = pl010_request_port,
588         .config_port    = pl010_config_port,
589         .verify_port    = pl010_verify_port,
590 };
591
592 static struct uart_amba_port *amba_ports[UART_NR];
593
594 #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
595
596 static inline void
597 pl011_console_write_char(struct uart_port *port, char ch)
598 {
599         unsigned int status;
600
601         do {
602                 status = readw(port->membase + UART01x_FR);
603         } while (status & UART01x_FR_TXFF);
604         writew(ch, port->membase + UART01x_DR);
605 }
606
607 static void
608 pl011_console_write(struct console *co, const char *s, unsigned int count)
609 {
610         struct uart_port *port = &amba_ports[co->index]->port;
611         unsigned int status, old_cr, new_cr;
612         int i;
613
614         /*
615          *      First save the CR then disable the interrupts
616          */
617         old_cr = readw(port->membase + UART011_CR);
618         new_cr = old_cr & ~UART011_CR_CTSEN;
619         new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
620         writew(new_cr, port->membase + UART011_CR);
621
622         /*
623          *      Now, do each character
624          */
625         for (i = 0; i < count; i++) {
626                 pl011_console_write_char(port, s[i]);
627                 if (s[i] == '\n')
628                         pl011_console_write_char(port, '\r');
629         }
630
631         /*
632          *      Finally, wait for transmitter to become empty
633          *      and restore the TCR
634          */
635         do {
636                 status = readw(port->membase + UART01x_FR);
637         } while (status & UART01x_FR_BUSY);
638         writew(old_cr, port->membase + UART011_CR);
639 }
640
641 static void __init
642 pl011_console_get_options(struct uart_port *port, int *baud,
643                              int *parity, int *bits)
644 {
645         if (readw(port->membase + UART011_CR) & UART01x_CR_UARTEN) {
646                 unsigned int lcr_h, ibrd, fbrd;
647
648                 lcr_h = readw(port->membase + UART011_LCRH);
649
650                 *parity = 'n';
651                 if (lcr_h & UART01x_LCRH_PEN) {
652                         if (lcr_h & UART01x_LCRH_EPS)
653                                 *parity = 'e';
654                         else
655                                 *parity = 'o';
656                 }
657
658                 if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
659                         *bits = 7;
660                 else
661                         *bits = 8;
662
663                 ibrd = readw(port->membase + UART011_IBRD);
664                 fbrd = readw(port->membase + UART011_FBRD);
665
666                 *baud = port->uartclk * 4 / (64 * ibrd + fbrd);
667         }
668 }
669
670 static int __init pl011_console_setup(struct console *co, char *options)
671 {
672         struct uart_amba_port *uap;
673         int baud = 38400;
674         int bits = 8;
675         int parity = 'n';
676         int flow = 'n';
677         int ret;
678
679         /*
680          * Check whether an invalid uart number has been specified, and
681          * if so, search for the first available port that does have
682          * console support.
683          */
684         if (co->index >= UART_NR)
685                 co->index = 0;
686         uap = amba_ports[co->index];
687
688         if (options)
689                 uart_parse_options(options, &baud, &parity, &bits, &flow);
690         else
691                 pl011_console_get_options(&uap->port, &baud, &parity, &bits);
692
693         return uart_set_options(&uap->port, co, baud, parity, bits, flow);
694 }
695
696 extern struct uart_driver amba_reg;
697 static struct console amba_console = {
698         .name           = "ttyAMA",
699         .write          = pl011_console_write,
700         .device         = uart_console_device,
701         .setup          = pl011_console_setup,
702         .flags          = CON_PRINTBUFFER,
703         .index          = -1,
704         .data           = &amba_reg,
705 };
706
707 #define AMBA_CONSOLE    (&amba_console)
708 #else
709 #define AMBA_CONSOLE    NULL
710 #endif
711
712 static struct uart_driver amba_reg = {
713         .owner                  = THIS_MODULE,
714         .driver_name            = "ttyAMA",
715         .dev_name               = "ttyAMA",
716         .major                  = SERIAL_AMBA_MAJOR,
717         .minor                  = SERIAL_AMBA_MINOR,
718         .nr                     = UART_NR,
719         .cons                   = AMBA_CONSOLE,
720 };
721
722 static int pl011_probe(struct amba_device *dev, void *id)
723 {
724         struct uart_amba_port *uap;
725         void *base;
726         int i, ret;
727
728         for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
729                 if (amba_ports[i] == NULL)
730                         break;
731
732         if (i == ARRAY_SIZE(amba_ports)) {
733                 ret = -EBUSY;
734                 goto out;
735         }
736
737         uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
738         if (uap == NULL) {
739                 ret = -ENOMEM;
740                 goto out;
741         }
742
743         base = ioremap(dev->res.start, PAGE_SIZE);
744         if (!base) {
745                 ret = -ENOMEM;
746                 goto free;
747         }
748
749         memset(uap, 0, sizeof(struct uart_amba_port));
750         uap->port.dev = &dev->dev;
751         uap->port.mapbase = dev->res.start;
752         uap->port.membase = base;
753         uap->port.iotype = UPIO_MEM;
754         uap->port.irq = dev->irq[0];
755 #if 0 /* FIXME */
756         uap->port.uartclk = 14745600;
757 #else
758         uap->port.uartclk = 24000000;
759 #endif
760         uap->port.fifosize = 16;
761         uap->port.ops = &amba_pl011_pops;
762         uap->port.flags = UPF_BOOT_AUTOCONF;
763         uap->port.line = i;
764
765         amba_ports[i] = uap;
766
767         amba_set_drvdata(dev, uap);
768         ret = uart_add_one_port(&amba_reg, &uap->port);
769         if (ret) {
770                 amba_set_drvdata(dev, NULL);
771                 amba_ports[i] = NULL;
772                 iounmap(base);
773  free:
774                 kfree(uap);
775         }
776  out:
777         return ret;
778 }
779
780 static int pl011_remove(struct amba_device *dev)
781 {
782         struct uart_amba_port *uap = amba_get_drvdata(dev);
783         int i;
784
785         amba_set_drvdata(dev, NULL);
786
787         uart_remove_one_port(&amba_reg, &uap->port);
788
789         for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
790                 if (amba_ports[i] == uap)
791                         amba_ports[i] = NULL;
792
793         iounmap(uap->port.membase);
794         kfree(uap);
795         return 0;
796 }
797
798 static struct amba_id pl011_ids[] __initdata = {
799         {
800                 .id     = 0x00041011,
801                 .mask   = 0x000fffff,
802         },
803         { 0, 0 },
804 };
805
806 static struct amba_driver pl011_driver = {
807         .drv = {
808                 .name   = "uart-pl011",
809         },
810         .id_table       = pl011_ids,
811         .probe          = pl011_probe,
812         .remove         = pl011_remove,
813 };
814
815 static int __init pl011_init(void)
816 {
817         int ret;
818         printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
819
820         ret = uart_register_driver(&amba_reg);
821         if (ret == 0) {
822                 ret = amba_driver_register(&pl011_driver);
823                 if (ret)
824                         uart_unregister_driver(&amba_reg);
825         }
826         return ret;
827 }
828
829 static void __exit pl011_exit(void)
830 {
831         amba_driver_unregister(&pl011_driver);
832         uart_unregister_driver(&amba_reg);
833 }
834
835 module_init(pl011_init);
836 module_exit(pl011_exit);
837
838 MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
839 MODULE_DESCRIPTION("ARM AMBA serial port driver");
840 MODULE_LICENSE("GPL");