vserver 1.9.5.x5
[linux-2.6.git] / drivers / serial / pxa.c
index 42e83fd..68b25b2 100644 (file)
  */
 
 #include <linux/config.h>
+
+#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/serial_reg.h>
 #include <linux/circ_buf.h>
-#include <linux/serial.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
-
-#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
+#include <asm/arch/pxa-regs.h>
 
 
 struct uart_pxa_port {
@@ -101,25 +103,20 @@ static inline void
 receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
 {
        struct tty_struct *tty = up->port.info->tty;
-       unsigned char ch;
+       unsigned int ch, flag;
        int max_count = 256;
 
        do {
                if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+                       if (tty->low_latency)
+                               tty_flip_buffer_push(tty);
                        /*
-                        * FIXME: Deadlock can happen here if we're a
-                        * low-latency port.  We're holding the per-port
-                        * spinlock, and we call flush_to_ldisc->
-                        * n_tty_receive_buf->n_tty_receive_char->
-                        * opost->uart_put_char.
+                        * If this failed then we will throw away the
+                        * bytes but must do so to clear interrupts
                         */
-                       tty->flip.work.func((void *)tty);
-                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                               return; // if TTY_DONT_FLIP is set
                }
                ch = serial_in(up, UART_RX);
-               *tty->flip.char_buf_ptr = ch;
-               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               flag = TTY_NORMAL;
                up->port.icount.rx++;
 
                if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
@@ -158,18 +155,16 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
                        }
 #endif
                        if (*status & UART_LSR_BI) {
-                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                               flag = TTY_BREAK;
                        } else if (*status & UART_LSR_PE)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (*status & UART_LSR_FE)
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
                }
                if (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto ignore_char;
                if ((*status & up->port.ignore_status_mask) == 0) {
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, ch, flag);
                }
                if ((*status & UART_LSR_OE) &&
                    tty->flip.count < TTY_FLIPBUF_SIZE) {
@@ -178,10 +173,7 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
                         * immediately, and doesn't affect the current
                         * character.
                         */
-                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
-                       tty->flip.flag_buf_ptr++;
-                       tty->flip.char_buf_ptr++;
-                       tty->flip.count++;
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                }
        ignore_char:
                *status = serial_in(up, UART_LSR);
@@ -386,9 +378,6 @@ static int serial_pxa_startup(struct uart_port *port)
        if (retval)
                return retval;
 
-       CKEN |= up->cken;
-       udelay(1);
-
        /*
         * Clear the FIFO buffers and disable them.
         * (they will be reenabled in set_termios())
@@ -461,8 +450,6 @@ static void serial_pxa_shutdown(struct uart_port *port)
                                  UART_FCR_CLEAR_RCVR |
                                  UART_FCR_CLEAR_XMIT);
        serial_out(up, UART_FCR, 0);
-
-       CKEN &= ~up->cken;
 }
 
 static void
@@ -576,11 +563,10 @@ static void
 serial_pxa_pm(struct uart_port *port, unsigned int state,
              unsigned int oldstate)
 {
-       if (state) {
-               /* sleep */
-       } else {
-               /* wake */
-       }
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+       pxa_set_cken(up->cken, !state);
+       if (!state)
+               udelay(1);
 }
 
 static void serial_pxa_release_port(struct uart_port *port)
@@ -760,13 +746,12 @@ static struct uart_pxa_port serial_pxa_ports[] = {
        .cken   = CKEN6_FFUART,
        .port   = {
                .type           = PORT_PXA,
-               .iotype         = SERIAL_IO_MEM,
+               .iotype         = UPIO_MEM,
                .membase        = (void *)&FFUART,
                .mapbase        = __PREG(FFUART),
                .irq            = IRQ_FFUART,
                .uartclk        = 921600 * 16,
                .fifosize       = 64,
-               .flags          = ASYNC_SKIP_TEST,
                .ops            = &serial_pxa_pops,
                .line           = 0,
        },
@@ -775,13 +760,12 @@ static struct uart_pxa_port serial_pxa_ports[] = {
        .cken   = CKEN7_BTUART,
        .port   = {
                .type           = PORT_PXA,
-               .iotype         = SERIAL_IO_MEM,
+               .iotype         = UPIO_MEM,
                .membase        = (void *)&BTUART,
                .mapbase        = __PREG(BTUART),
                .irq            = IRQ_BTUART,
                .uartclk        = 921600 * 16,
                .fifosize       = 64,
-               .flags          = ASYNC_SKIP_TEST,
                .ops            = &serial_pxa_pops,
                .line           = 1,
        },
@@ -790,13 +774,12 @@ static struct uart_pxa_port serial_pxa_ports[] = {
        .cken   = CKEN5_STUART,
        .port   = {
                .type           = PORT_PXA,
-               .iotype         = SERIAL_IO_MEM,
+               .iotype         = UPIO_MEM,
                .membase        = (void *)&STUART,
                .mapbase        = __PREG(STUART),
                .irq            = IRQ_STUART,
                .uartclk        = 921600 * 16,
                .fifosize       = 64,
-               .flags          = ASYNC_SKIP_TEST,
                .ops            = &serial_pxa_pops,
                .line           = 2,
        },
@@ -814,22 +797,76 @@ static struct uart_driver serial_pxa_reg = {
        .cons           = PXA_CONSOLE,
 };
 
-static int __init serial_pxa_init(void)
+static int serial_pxa_suspend(struct device *_dev, u32 state, u32 level)
+{
+        struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+
+        if (sport && level == SUSPEND_DISABLE)
+                uart_suspend_port(&serial_pxa_reg, &sport->port);
+
+        return 0;
+}
+
+static int serial_pxa_resume(struct device *_dev, u32 level)
+{
+        struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+
+        if (sport && level == RESUME_ENABLE)
+                uart_resume_port(&serial_pxa_reg, &sport->port);
+
+        return 0;
+}
+
+static int serial_pxa_probe(struct device *_dev)
+{
+       struct platform_device *dev = to_platform_device(_dev);
+
+       serial_pxa_ports[dev->id].port.dev = _dev;
+       uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
+       dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]);
+       return 0;
+}
+
+static int serial_pxa_remove(struct device *_dev)
+{
+       struct uart_pxa_port *sport = dev_get_drvdata(_dev);
+
+       dev_set_drvdata(_dev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&serial_pxa_reg, &sport->port);
+
+       return 0;
+}
+
+static struct device_driver serial_pxa_driver = {
+        .name           = "pxa2xx-uart",
+        .bus            = &platform_bus_type,
+        .probe          = serial_pxa_probe,
+        .remove         = serial_pxa_remove,
+
+       .suspend        = serial_pxa_suspend,
+       .resume         = serial_pxa_resume,
+};
+
+int __init serial_pxa_init(void)
 {
-       int i, ret;
+       int ret;
 
        ret = uart_register_driver(&serial_pxa_reg);
-       if (ret)
+       if (ret != 0)
                return ret;
 
-       for (i = 0; i < ARRAY_SIZE(serial_pxa_ports); i++)
-               uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[i].port);
+       ret = driver_register(&serial_pxa_driver);
+       if (ret != 0)
+               uart_unregister_driver(&serial_pxa_reg);
 
-       return 0;
+       return ret;
 }
 
-static void __exit serial_pxa_exit(void)
+void __exit serial_pxa_exit(void)
 {
+        driver_unregister(&serial_pxa_driver);
        uart_unregister_driver(&serial_pxa_reg);
 }