const: constify remaining dev_pm_ops
[safe/jmp/linux-2.6] / drivers / serial / pxa.c
index 10535f0..56ee082 100644 (file)
@@ -24,7 +24,6 @@
  * with the serial core maintainer satisfaction to appear soon.
  */
 
-#include <linux/config.h>
 
 #if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #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>
-#include <asm/arch/pxa-regs.h>
-
+#include <linux/clk.h>
+#include <linux/io.h>
 
 struct uart_pxa_port {
        struct uart_port        port;
@@ -56,7 +51,7 @@ struct uart_pxa_port {
        unsigned char           lcr;
        unsigned char           mcr;
        unsigned int            lsr_break_flag;
-       unsigned int            cken;
+       struct clk              *clk;
        char                    *name;
 };
 
@@ -99,10 +94,9 @@ static void serial_pxa_stop_rx(struct uart_port *port)
        serial_out(up, UART_IER, up->ier);
 }
 
-static inline void
-receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
+static inline void receive_chars(struct uart_pxa_port *up, int *status)
 {
-       struct tty_struct *tty = up->port.info->tty;
+       struct tty_struct *tty = up->port.state->port.tty;
        unsigned int ch, flag;
        int max_count = 256;
 
@@ -154,7 +148,7 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
                                flag = TTY_FRAME;
                }
 
-               if (uart_handle_sysrq_char(&up->port, ch, regs))
+               if (uart_handle_sysrq_char(&up->port, ch))
                        goto ignore_char;
 
                uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
@@ -167,7 +161,7 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
 
 static void transmit_chars(struct uart_pxa_port *up)
 {
-       struct circ_buf *xmit = &up->port.info->xmit;
+       struct circ_buf *xmit = &up->port.state->xmit;
        int count;
 
        if (up->port.x_char) {
@@ -226,16 +220,15 @@ static inline void check_modem_status(struct uart_pxa_port *up)
        if (status & UART_MSR_DCTS)
                uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
 
-       wake_up_interruptible(&up->port.info->delta_msr_wait);
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
 }
 
 /*
  * This handles the interrupt from one port.
  */
-static inline irqreturn_t
-serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs)
+static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
 {
-       struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id;
+       struct uart_pxa_port *up = dev_id;
        unsigned int iir, lsr;
 
        iir = serial_in(up, UART_IIR);
@@ -243,7 +236,7 @@ serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs)
                return IRQ_NONE;
        lsr = serial_in(up, UART_LSR);
        if (lsr & UART_LSR_DR)
-               receive_chars(up, &lsr, regs);
+               receive_chars(up, &lsr);
        check_modem_status(up);
        if (lsr & UART_LSR_THRE)
                transmit_chars(up);
@@ -269,7 +262,6 @@ static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
        unsigned char status;
        unsigned int ret;
 
-return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
        status = serial_in(up, UART_MSR);
 
        ret = 0;
@@ -355,6 +347,8 @@ static int serial_pxa_startup(struct uart_port *port)
        else
                up->mcr = 0;
 
+       up->port.uartclk = clk_get_rate(up->clk);
+
        /*
         * Allocate the IRQ
         */
@@ -391,7 +385,7 @@ static int serial_pxa_startup(struct uart_port *port)
 
        /*
         * Finally, enable interrupts.  Note: Modem status interrupts
-        * are set via set_termios(), which will be occuring imminently
+        * are set via set_termios(), which will be occurring imminently
         * anyway, so we don't enable them here.
         */
        up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
@@ -437,13 +431,14 @@ static void serial_pxa_shutdown(struct uart_port *port)
 }
 
 static void
-serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
-                      struct termios *old)
+serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
+                      struct ktermios *old)
 {
        struct uart_pxa_port *up = (struct uart_pxa_port *)port;
        unsigned char cval, fcr = 0;
        unsigned long flags;
        unsigned int baud, quot;
+       unsigned int dll;
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
@@ -491,7 +486,7 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
         * Ensure the port will be enabled.
         * This is required especially for serial console.
         */
-       up->ier |= IER_UUE;
+       up->ier |= UART_IER_UUE;
 
        /*
         * Update the per-port timeout.
@@ -535,10 +530,23 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
 
        serial_out(up, UART_IER, up->ier);
 
-       serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       if (termios->c_cflag & CRTSCTS)
+               up->mcr |= UART_MCR_AFE;
+       else
+               up->mcr &= ~UART_MCR_AFE;
+
+       serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
        serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+
+       /*
+        * work around Errata #75 according to Intel(R) PXA27x Processor Family
+        * Specification Update (Nov 2005)
+        */
+       dll = serial_in(up, UART_DLL);
+       WARN_ON(dll != (quot & 0xff));
+
        serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
-       serial_out(up, UART_LCR, cval);         /* reset DLAB */
+       serial_out(up, UART_LCR, cval);                 /* reset DLAB */
        up->lcr = cval;                                 /* Save LCR */
        serial_pxa_set_mctrl(&up->port, up->port.mctrl);
        serial_out(up, UART_FCR, fcr);
@@ -550,9 +558,11 @@ serial_pxa_pm(struct uart_port *port, unsigned int state,
              unsigned int oldstate)
 {
        struct uart_pxa_port *up = (struct uart_pxa_port *)port;
-       pxa_set_cken(up->cken, !state);
+
        if (!state)
-               udelay(1);
+               clk_enable(up->clk);
+       else
+               clk_disable(up->clk);
 }
 
 static void serial_pxa_release_port(struct uart_port *port)
@@ -584,11 +594,11 @@ serial_pxa_type(struct uart_port *port)
        return up->name;
 }
 
-#ifdef CONFIG_SERIAL_PXA_CONSOLE
-
-static struct uart_pxa_port serial_pxa_ports[];
+static struct uart_pxa_port *serial_pxa_ports[4];
 static struct uart_driver serial_pxa_reg;
 
+#ifdef CONFIG_SERIAL_PXA_CONSOLE
+
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
 /*
@@ -619,6 +629,14 @@ static inline void wait_for_xmitr(struct uart_pxa_port *up)
        }
 }
 
+static void serial_pxa_console_putchar(struct uart_port *port, int ch)
+{
+       struct uart_pxa_port *up = (struct uart_pxa_port *)port;
+
+       wait_for_xmitr(up);
+       serial_out(up, UART_TX, ch);
+}
+
 /*
  * Print a string to the serial port trying not to disturb
  * any possible real use of the port...
@@ -628,9 +646,10 @@ static inline void wait_for_xmitr(struct uart_pxa_port *up)
 static void
 serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 {
-       struct uart_pxa_port *up = &serial_pxa_ports[co->index];
+       struct uart_pxa_port *up = serial_pxa_ports[co->index];
        unsigned int ier;
-       int i;
+
+       clk_enable(up->clk);
 
        /*
         *      First save the IER then disable the interrupts
@@ -638,22 +657,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
        ier = serial_in(up, UART_IER);
        serial_out(up, UART_IER, UART_IER_UUE);
 
-       /*
-        *      Now, do each character
-        */
-       for (i = 0; i < count; i++, s++) {
-               wait_for_xmitr(up);
-
-               /*
-                *      Send the character out.
-                *      If a LF, also do CR...
-                */
-               serial_out(up, UART_TX, *s);
-               if (*s == 10) {
-                       wait_for_xmitr(up);
-                       serial_out(up, UART_TX, 13);
-               }
-       }
+       uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
@@ -661,6 +665,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
         */
        wait_for_xmitr(up);
        serial_out(up, UART_IER, ier);
+
+       clk_disable(up->clk);
 }
 
 static int __init
@@ -674,7 +680,9 @@ serial_pxa_console_setup(struct console *co, char *options)
 
        if (co->index == -1 || co->index >= serial_pxa_reg.nr)
                co->index = 0;
-               up = &serial_pxa_ports[co->index];
+       up = serial_pxa_ports[co->index];
+       if (!up)
+               return -ENODEV;
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -692,15 +700,6 @@ static struct console serial_pxa_console = {
        .data           = &serial_pxa_reg,
 };
 
-static int __init
-serial_pxa_console_init(void)
-{
-       register_console(&serial_pxa_console);
-       return 0;
-}
-
-console_initcall(serial_pxa_console_init);
-
 #define PXA_CONSOLE    &serial_pxa_console
 #else
 #define PXA_CONSOLE    NULL
@@ -726,80 +725,20 @@ struct uart_ops serial_pxa_pops = {
        .verify_port    = serial_pxa_verify_port,
 };
 
-static struct uart_pxa_port serial_pxa_ports[] = {
-     { /* FFUART */
-       .name   = "FFUART",
-       .cken   = CKEN6_FFUART,
-       .port   = {
-               .type           = PORT_PXA,
-               .iotype         = UPIO_MEM,
-               .membase        = (void *)&FFUART,
-               .mapbase        = __PREG(FFUART),
-               .irq            = IRQ_FFUART,
-               .uartclk        = 921600 * 16,
-               .fifosize       = 64,
-               .ops            = &serial_pxa_pops,
-               .line           = 0,
-       },
-  }, { /* BTUART */
-       .name   = "BTUART",
-       .cken   = CKEN7_BTUART,
-       .port   = {
-               .type           = PORT_PXA,
-               .iotype         = UPIO_MEM,
-               .membase        = (void *)&BTUART,
-               .mapbase        = __PREG(BTUART),
-               .irq            = IRQ_BTUART,
-               .uartclk        = 921600 * 16,
-               .fifosize       = 64,
-               .ops            = &serial_pxa_pops,
-               .line           = 1,
-       },
-  }, { /* STUART */
-       .name   = "STUART",
-       .cken   = CKEN5_STUART,
-       .port   = {
-               .type           = PORT_PXA,
-               .iotype         = UPIO_MEM,
-               .membase        = (void *)&STUART,
-               .mapbase        = __PREG(STUART),
-               .irq            = IRQ_STUART,
-               .uartclk        = 921600 * 16,
-               .fifosize       = 64,
-               .ops            = &serial_pxa_pops,
-               .line           = 2,
-       },
-  }, {  /* HWUART */
-       .name   = "HWUART",
-       .cken   = CKEN4_HWUART,
-       .port = {
-               .type           = PORT_PXA,
-               .iotype         = UPIO_MEM,
-               .membase        = (void *)&HWUART,
-               .mapbase        = __PREG(HWUART),
-               .irq            = IRQ_HWUART,
-               .uartclk        = 921600 * 16,
-               .fifosize       = 64,
-               .ops            = &serial_pxa_pops,
-               .line           = 3,
-       },
-  }
-};
-
 static struct uart_driver serial_pxa_reg = {
        .owner          = THIS_MODULE,
        .driver_name    = "PXA serial",
-       .devfs_name     = "tts/",
        .dev_name       = "ttyS",
        .major          = TTY_MAJOR,
        .minor          = 64,
-       .nr             = ARRAY_SIZE(serial_pxa_ports),
+       .nr             = 4,
        .cons           = PXA_CONSOLE,
 };
 
-static int serial_pxa_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM
+static int serial_pxa_suspend(struct device *dev)
 {
-        struct uart_pxa_port *sport = platform_get_drvdata(dev);
+        struct uart_pxa_port *sport = dev_get_drvdata(dev);
 
         if (sport)
                 uart_suspend_port(&serial_pxa_reg, &sport->port);
@@ -807,9 +746,9 @@ static int serial_pxa_suspend(struct platform_device *dev, pm_message_t state)
         return 0;
 }
 
-static int serial_pxa_resume(struct platform_device *dev)
+static int serial_pxa_resume(struct device *dev)
 {
-        struct uart_pxa_port *sport = platform_get_drvdata(dev);
+        struct uart_pxa_port *sport = dev_get_drvdata(dev);
 
         if (sport)
                 uart_resume_port(&serial_pxa_reg, &sport->port);
@@ -817,12 +756,72 @@ static int serial_pxa_resume(struct platform_device *dev)
         return 0;
 }
 
+static const struct dev_pm_ops serial_pxa_pm_ops = {
+       .suspend        = serial_pxa_suspend,
+       .resume         = serial_pxa_resume,
+};
+#endif
+
 static int serial_pxa_probe(struct platform_device *dev)
 {
-       serial_pxa_ports[dev->id].port.dev = &dev->dev;
-       uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
-       platform_set_drvdata(dev, &serial_pxa_ports[dev->id]);
+       struct uart_pxa_port *sport;
+       struct resource *mmres, *irqres;
+       int ret;
+
+       mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+       if (!mmres || !irqres)
+               return -ENODEV;
+
+       sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
+       if (!sport)
+               return -ENOMEM;
+
+       sport->clk = clk_get(&dev->dev, NULL);
+       if (IS_ERR(sport->clk)) {
+               ret = PTR_ERR(sport->clk);
+               goto err_free;
+       }
+
+       sport->port.type = PORT_PXA;
+       sport->port.iotype = UPIO_MEM;
+       sport->port.mapbase = mmres->start;
+       sport->port.irq = irqres->start;
+       sport->port.fifosize = 64;
+       sport->port.ops = &serial_pxa_pops;
+       sport->port.line = dev->id;
+       sport->port.dev = &dev->dev;
+       sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+       sport->port.uartclk = clk_get_rate(sport->clk);
+
+       switch (dev->id) {
+       case 0: sport->name = "FFUART"; break;
+       case 1: sport->name = "BTUART"; break;
+       case 2: sport->name = "STUART"; break;
+       case 3: sport->name = "HWUART"; break;
+       default:
+               sport->name = "???";
+               break;
+       }
+
+       sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);
+       if (!sport->port.membase) {
+               ret = -ENOMEM;
+               goto err_clk;
+       }
+
+       serial_pxa_ports[dev->id] = sport;
+
+       uart_add_one_port(&serial_pxa_reg, &sport->port);
+       platform_set_drvdata(dev, sport);
+
        return 0;
+
+ err_clk:
+       clk_put(sport->clk);
+ err_free:
+       kfree(sport);
+       return ret;
 }
 
 static int serial_pxa_remove(struct platform_device *dev)
@@ -831,8 +830,9 @@ static int serial_pxa_remove(struct platform_device *dev)
 
        platform_set_drvdata(dev, NULL);
 
-       if (sport)
-               uart_remove_one_port(&serial_pxa_reg, &sport->port);
+       uart_remove_one_port(&serial_pxa_reg, &sport->port);
+       clk_put(sport->clk);
+       kfree(sport);
 
        return 0;
 }
@@ -841,10 +841,12 @@ static struct platform_driver serial_pxa_driver = {
         .probe          = serial_pxa_probe,
         .remove         = serial_pxa_remove,
 
-       .suspend        = serial_pxa_suspend,
-       .resume         = serial_pxa_resume,
        .driver         = {
                .name   = "pxa2xx-uart",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &serial_pxa_pm_ops,
+#endif
        },
 };
 
@@ -873,4 +875,4 @@ module_init(serial_pxa_init);
 module_exit(serial_pxa_exit);
 
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:pxa2xx-uart");