aboutsummaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/pxa.c163
-rw-r--r--drivers/serial/serial_core.c18
2 files changed, 91 insertions, 90 deletions
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index e9c6cb391a23..af3a011b2b24 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -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)
@@ -582,7 +587,7 @@ serial_pxa_type(struct uart_port *port)
#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;
#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;
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index a055f58f342f..a3bd3a3f41f3 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2127,6 +2127,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
spin_unlock_irqrestore(&port->lock, flags);
/*
+ * If this driver supports console, and it hasn't been
+ * successfully registered yet, try to re-register it.
+ * It may be that the port was not available.
+ */
+ if (port->cons && !(port->cons->flags & CON_ENABLED))
+ register_console(port->cons);
+
+ /*
* Power down all ports by default, except the
* console if we have one.
*/
@@ -2286,6 +2294,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
}
state->port = port;
+ state->pm_state = -1;
port->cons = drv->cons;
port->info = state->info;
@@ -2308,15 +2317,6 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
tty_register_device(drv->tty_driver, port->line, port->dev);
/*
- * If this driver supports console, and it hasn't been
- * successfully registered yet, try to re-register it.
- * It may be that the port was not available.
- */
- if (port->type != PORT_UNKNOWN &&
- port->cons && !(port->cons->flags & CON_ENABLED))
- register_console(port->cons);
-
- /*
* Ensure UPF_DEAD is not set.
*/
port->flags &= ~UPF_DEAD;