Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.26
[pandora-kernel.git] / drivers / serial / pxa.c
index e9c6cb3..b4f7ffb 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
@@ -55,7 +56,7 @@ struct uart_pxa_port {
        unsigned char           lcr;
        unsigned char           mcr;
        unsigned int            lsr_break_flag;
-       unsigned int            cken;
+       struct clk              *clk;
        char                    *name;
 };
 
@@ -351,6 +352,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
         */
@@ -546,9 +549,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)
@@ -580,11 +585,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)
 
 /*
@@ -632,9 +637,11 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch)
 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;
 
+       clk_enable(up->clk);
+
        /*
         *      First save the IER then disable the interrupts
         */
@@ -649,6 +656,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
@@ -662,7 +671,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);
@@ -680,15 +691,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
@@ -714,73 +716,13 @@ struct uart_ops serial_pxa_pops = {
        .verify_port    = serial_pxa_verify_port,
 };
 
-static struct uart_pxa_port serial_pxa_ports[] = {
-     { /* FFUART */
-       .name   = "FFUART",
-       .cken   = CKEN_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   = CKEN_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   = CKEN_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   = CKEN_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",
        .dev_name       = "ttyS",
        .major          = TTY_MAJOR,
        .minor          = 64,
-       .nr             = ARRAY_SIZE(serial_pxa_ports),
+       .nr             = 4,
        .cons           = PXA_CONSOLE,
 };
 
@@ -806,10 +748,68 @@ static int serial_pxa_resume(struct platform_device *dev)
 
 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, "UARTCLK");
+       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);
+
+       /*
+        * Is it worth keeping this?
+        */
+       if (mmres->start == __PREG(FFUART))
+               sport->name = "FFUART";
+       else if (mmres->start == __PREG(BTUART))
+               sport->name = "BTUART";
+       else if (mmres->start == __PREG(STUART))
+               sport->name = "STUART";
+       else if (mmres->start == __PREG(HWUART))
+               sport->name = "HWUART";
+       else
+               sport->name = "???";
+
+       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)
@@ -818,8 +818,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;
 }
@@ -832,6 +833,7 @@ static struct platform_driver serial_pxa_driver = {
        .resume         = serial_pxa_resume,
        .driver         = {
                .name   = "pxa2xx-uart",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -860,4 +862,4 @@ module_init(serial_pxa_init);
 module_exit(serial_pxa_exit);
 
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:pxa2xx-uart");