dm table: rework reference counting fix
[safe/jmp/linux-2.6] / drivers / serial / amba-pl011.c
index d84476e..8b2b970 100644 (file)
@@ -22,8 +22,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- *  $Id: amba.c,v 1.41 2002/07/28 10:03:27 rmk Exp $
- *
  * This is a generic driver for ARM AMBA-type serial ports.  They
  * have a lot of 16550-like features, but are not register compatible.
  * Note that although they do have CTS, DCD and DSR inputs, they do
@@ -31,7 +29,6 @@
  * required, these have to be supplied via some other means (eg, GPIO)
  * and hooked into this driver.
  */
-#include <linux/config.h>
 
 #if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 #include <asm/sizes.h>
-#include <asm/hardware/amba.h>
-#include <asm/hardware/clock.h>
-#include <asm/hardware/amba_serial.h>
 
 #define UART_NR                        14
 
@@ -108,27 +105,13 @@ static void pl011_enable_ms(struct uart_port *port)
        writew(uap->im, uap->port.membase + UART011_IMSC);
 }
 
-static void
-#ifdef SUPPORT_SYSRQ
-pl011_rx_chars(struct uart_amba_port *uap, struct pt_regs *regs)
-#else
-pl011_rx_chars(struct uart_amba_port *uap)
-#endif
+static void pl011_rx_chars(struct uart_amba_port *uap)
 {
-       struct tty_struct *tty = uap->port.info->tty;
+       struct tty_struct *tty = uap->port.info->port.tty;
        unsigned int status, ch, flag, max_count = 256;
 
        status = readw(uap->port.membase + UART01x_FR);
        while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       if (tty->low_latency)
-                               tty_flip_buffer_push(tty);
-                       /*
-                        * If this failed then we will throw away the
-                        * bytes but must do so to clear interrupts
-                        */
-               }
-
                ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
                flag = TTY_NORMAL;
                uap->port.icount.rx++;
@@ -160,7 +143,7 @@ pl011_rx_chars(struct uart_amba_port *uap)
                                flag = TTY_FRAME;
                }
 
-               if (uart_handle_sysrq_char(&uap->port, ch & 255, regs))
+               if (uart_handle_sysrq_char(&uap->port, ch & 255))
                        goto ignore_char;
 
                uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
@@ -168,8 +151,9 @@ pl011_rx_chars(struct uart_amba_port *uap)
        ignore_char:
                status = readw(uap->port.membase + UART01x_FR);
        }
+       spin_unlock(&uap->port.lock);
        tty_flip_buffer_push(tty);
-       return;
+       spin_lock(&uap->port.lock);
 }
 
 static void pl011_tx_chars(struct uart_amba_port *uap)
@@ -228,7 +212,7 @@ static void pl011_modem_status(struct uart_amba_port *uap)
        wake_up_interruptible(&uap->port.info->delta_msr_wait);
 }
 
-static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pl011_int(int irq, void *dev_id)
 {
        struct uart_amba_port *uap = dev_id;
        unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
@@ -244,11 +228,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
                               uap->port.membase + UART011_ICR);
 
                        if (status & (UART011_RTIS|UART011_RXIS))
-#ifdef SUPPORT_SYSRQ
-                               pl011_rx_chars(uap, regs);
-#else
                                pl011_rx_chars(uap);
-#endif
                        if (status & (UART011_DSRMIS|UART011_DCDMIS|
                                      UART011_CTSMIS|UART011_RIMIS))
                                pl011_modem_status(uap);
@@ -281,15 +261,15 @@ static unsigned int pl01x_get_mctrl(struct uart_port *port)
        unsigned int result = 0;
        unsigned int status = readw(uap->port.membase + UART01x_FR);
 
-#define BIT(uartbit, tiocmbit)         \
+#define TIOCMBIT(uartbit, tiocmbit)    \
        if (status & uartbit)           \
                result |= tiocmbit
 
-       BIT(UART01x_FR_DCD, TIOCM_CAR);
-       BIT(UART01x_FR_DSR, TIOCM_DSR);
-       BIT(UART01x_FR_CTS, TIOCM_CTS);
-       BIT(UART011_FR_RI, TIOCM_RNG);
-#undef BIT
+       TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
+       TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
+       TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
+       TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+#undef TIOCMBIT
        return result;
 }
 
@@ -300,18 +280,18 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
        cr = readw(uap->port.membase + UART011_CR);
 
-#define        BIT(tiocmbit, uartbit)          \
+#define        TIOCMBIT(tiocmbit, uartbit)             \
        if (mctrl & tiocmbit)           \
                cr |= uartbit;          \
        else                            \
                cr &= ~uartbit
 
-       BIT(TIOCM_RTS, UART011_CR_RTS);
-       BIT(TIOCM_DTR, UART011_CR_DTR);
-       BIT(TIOCM_OUT1, UART011_CR_OUT1);
-       BIT(TIOCM_OUT2, UART011_CR_OUT2);
-       BIT(TIOCM_LOOP, UART011_CR_LBE);
-#undef BIT
+       TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
+       TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
+       TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
+       TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
+       TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+#undef TIOCMBIT
 
        writew(cr, uap->port.membase + UART011_CR);
 }
@@ -332,6 +312,32 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+static int pl010_get_poll_char(struct uart_port *port)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+       unsigned int status;
+
+       do {
+               status = readw(uap->port.membase + UART01x_FR);
+       } while (status & UART01x_FR_RXFE);
+
+       return readw(uap->port.membase + UART01x_DR);
+}
+
+static void pl010_put_poll_char(struct uart_port *port,
+                        unsigned char ch)
+{
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               barrier();
+
+       writew(ch, uap->port.membase + UART01x_DR);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
 static int pl011_startup(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -431,8 +437,8 @@ static void pl011_shutdown(struct uart_port *port)
 }
 
 static void
-pl011_set_termios(struct uart_port *port, struct termios *termios,
-                    struct termios *old)
+pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+                    struct ktermios *old)
 {
        unsigned int lcr_h, old_cr;
        unsigned long flags;
@@ -566,7 +572,7 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
        int ret = 0;
        if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
                ret = -EINVAL;
-       if (ser->irq < 0 || ser->irq >= NR_IRQS)
+       if (ser->irq < 0 || ser->irq >= nr_irqs)
                ret = -EINVAL;
        if (ser->baud_base < 9600)
                ret = -EINVAL;
@@ -590,20 +596,22 @@ static struct uart_ops amba_pl011_pops = {
        .request_port   = pl010_request_port,
        .config_port    = pl010_config_port,
        .verify_port    = pl010_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char = pl010_get_poll_char,
+       .poll_put_char = pl010_put_poll_char,
+#endif
 };
 
 static struct uart_amba_port *amba_ports[UART_NR];
 
 #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
 
-static inline void
-pl011_console_write_char(struct uart_amba_port *uap, char ch)
+static void pl011_console_putchar(struct uart_port *port, int ch)
 {
-       unsigned int status;
+       struct uart_amba_port *uap = (struct uart_amba_port *)port;
 
-       do {
-               status = readw(uap->port.membase + UART01x_FR);
-       } while (status & UART01x_FR_TXFF);
+       while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+               barrier();
        writew(ch, uap->port.membase + UART01x_DR);
 }
 
@@ -612,7 +620,6 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct uart_amba_port *uap = amba_ports[co->index];
        unsigned int status, old_cr, new_cr;
-       int i;
 
        clk_enable(uap->clk);
 
@@ -624,14 +631,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
        new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
        writew(new_cr, uap->port.membase + UART011_CR);
 
-       /*
-        *      Now, do each character
-        */
-       for (i = 0; i < count; i++) {
-               pl011_console_write_char(uap, s[i]);
-               if (s[i] == '\n')
-                       pl011_console_write_char(uap, '\r');
-       }
+       uart_console_write(&uap->port, s, count, pl011_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
@@ -690,6 +690,8 @@ static int __init pl011_console_setup(struct console *co, char *options)
        if (co->index >= UART_NR)
                co->index = 0;
        uap = amba_ports[co->index];
+       if (!uap)
+               return -ENODEV;
 
        uap->port.uartclk = clk_get_rate(uap->clk);
 
@@ -742,7 +744,7 @@ static int pl011_probe(struct amba_device *dev, void *id)
                goto out;
        }
 
-       uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+       uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
        if (uap == NULL) {
                ret = -ENOMEM;
                goto out;
@@ -754,17 +756,12 @@ static int pl011_probe(struct amba_device *dev, void *id)
                goto free;
        }
 
-       memset(uap, 0, sizeof(struct uart_amba_port));
-       uap->clk = clk_get(&dev->dev, "UARTCLK");
+       uap->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(uap->clk)) {
                ret = PTR_ERR(uap->clk);
                goto unmap;
        }
 
-       ret = clk_use(uap->clk);
-       if (ret)
-               goto putclk;
-
        uap->port.dev = &dev->dev;
        uap->port.mapbase = dev->res.start;
        uap->port.membase = base;
@@ -782,8 +779,6 @@ static int pl011_probe(struct amba_device *dev, void *id)
        if (ret) {
                amba_set_drvdata(dev, NULL);
                amba_ports[i] = NULL;
-               clk_unuse(uap->clk);
- putclk:
                clk_put(uap->clk);
  unmap:
                iounmap(base);
@@ -808,7 +803,6 @@ static int pl011_remove(struct amba_device *dev)
                        amba_ports[i] = NULL;
 
        iounmap(uap->port.membase);
-       clk_unuse(uap->clk);
        clk_put(uap->clk);
        kfree(uap);
        return 0;