Commit ed519ded authored by Russell King's avatar Russell King Committed by Russell King

[ARM] Convert AMBA PL010 driver to use the clk infrastructure

Convert the AMBA PL010 serial driver to use the clock infrastructure
to allow EP93xx platforms to properly gate the clock to the UARTs.
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 1b0646a0
...@@ -27,6 +27,10 @@ struct clk { ...@@ -27,6 +27,10 @@ struct clk {
u32 enable_mask; u32 enable_mask;
}; };
static struct clk clk_uart = {
.name = "UARTCLK",
.rate = 14745600,
};
static struct clk clk_pll1 = { static struct clk clk_pll1 = {
.name = "pll1", .name = "pll1",
}; };
...@@ -50,6 +54,7 @@ static struct clk clk_usb_host = { ...@@ -50,6 +54,7 @@ static struct clk clk_usb_host = {
static struct clk *clocks[] = { static struct clk *clocks[] = {
&clk_uart,
&clk_pll1, &clk_pll1,
&clk_f, &clk_f,
&clk_h, &clk_h,
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/serial.h> #include <linux/amba/serial.h>
#include <linux/clk.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -70,6 +71,7 @@ ...@@ -70,6 +71,7 @@
*/ */
struct uart_amba_port { struct uart_amba_port {
struct uart_port port; struct uart_port port;
struct clk *clk;
struct amba_device *dev; struct amba_device *dev;
struct amba_pl010_data *data; struct amba_pl010_data *data;
unsigned int old_status; unsigned int old_status;
...@@ -312,12 +314,21 @@ static int pl010_startup(struct uart_port *port) ...@@ -312,12 +314,21 @@ static int pl010_startup(struct uart_port *port)
struct uart_amba_port *uap = (struct uart_amba_port *)port; struct uart_amba_port *uap = (struct uart_amba_port *)port;
int retval; int retval;
/*
* Try to enable the clock producer.
*/
retval = clk_enable(uap->clk);
if (retval)
goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
/* /*
* Allocate the IRQ * Allocate the IRQ
*/ */
retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap); retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
if (retval) if (retval)
return retval; goto clk_dis;
/* /*
* initialise the old status of the modem signals * initialise the old status of the modem signals
...@@ -331,6 +342,11 @@ static int pl010_startup(struct uart_port *port) ...@@ -331,6 +342,11 @@ static int pl010_startup(struct uart_port *port)
uap->port.membase + UART010_CR); uap->port.membase + UART010_CR);
return 0; return 0;
clk_dis:
clk_disable(uap->clk);
out:
return retval;
} }
static void pl010_shutdown(struct uart_port *port) static void pl010_shutdown(struct uart_port *port)
...@@ -351,6 +367,11 @@ static void pl010_shutdown(struct uart_port *port) ...@@ -351,6 +367,11 @@ static void pl010_shutdown(struct uart_port *port)
writel(readb(uap->port.membase + UART010_LCRH) & writel(readb(uap->port.membase + UART010_LCRH) &
~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
uap->port.membase + UART010_LCRH); uap->port.membase + UART010_LCRH);
/*
* Shut down the clock producer
*/
clk_disable(uap->clk);
} }
static void static void
...@@ -540,6 +561,8 @@ pl010_console_write(struct console *co, const char *s, unsigned int count) ...@@ -540,6 +561,8 @@ pl010_console_write(struct console *co, const char *s, unsigned int count)
struct uart_amba_port *uap = amba_ports[co->index]; struct uart_amba_port *uap = amba_ports[co->index];
unsigned int status, old_cr; unsigned int status, old_cr;
clk_enable(uap->clk);
/* /*
* First save the CR then disable the interrupts * First save the CR then disable the interrupts
*/ */
...@@ -557,6 +580,8 @@ pl010_console_write(struct console *co, const char *s, unsigned int count) ...@@ -557,6 +580,8 @@ pl010_console_write(struct console *co, const char *s, unsigned int count)
barrier(); barrier();
} while (status & UART01x_FR_BUSY); } while (status & UART01x_FR_BUSY);
writel(old_cr, uap->port.membase + UART010_CR); writel(old_cr, uap->port.membase + UART010_CR);
clk_disable(uap->clk);
} }
static void __init static void __init
...@@ -605,6 +630,8 @@ static int __init pl010_console_setup(struct console *co, char *options) ...@@ -605,6 +630,8 @@ static int __init pl010_console_setup(struct console *co, char *options)
if (!uap) if (!uap)
return -ENODEV; return -ENODEV;
uap->port.uartclk = clk_get_rate(uap->clk);
if (options) if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow); uart_parse_options(options, &baud, &parity, &bits, &flow);
else else
...@@ -666,12 +693,17 @@ static int pl010_probe(struct amba_device *dev, void *id) ...@@ -666,12 +693,17 @@ static int pl010_probe(struct amba_device *dev, void *id)
goto free; goto free;
} }
uap->clk = clk_get(&dev->dev, "UARTCLK");
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
goto unmap;
}
uap->port.dev = &dev->dev; uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start; uap->port.mapbase = dev->res.start;
uap->port.membase = base; uap->port.membase = base;
uap->port.iotype = UPIO_MEM; uap->port.iotype = UPIO_MEM;
uap->port.irq = dev->irq[0]; uap->port.irq = dev->irq[0];
uap->port.uartclk = 14745600;
uap->port.fifosize = 16; uap->port.fifosize = 16;
uap->port.ops = &amba_pl010_pops; uap->port.ops = &amba_pl010_pops;
uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.flags = UPF_BOOT_AUTOCONF;
...@@ -686,6 +718,8 @@ static int pl010_probe(struct amba_device *dev, void *id) ...@@ -686,6 +718,8 @@ static int pl010_probe(struct amba_device *dev, void *id)
if (ret) { if (ret) {
amba_set_drvdata(dev, NULL); amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL; amba_ports[i] = NULL;
clk_put(uap->clk);
unmap:
iounmap(base); iounmap(base);
free: free:
kfree(uap); kfree(uap);
...@@ -708,6 +742,7 @@ static int pl010_remove(struct amba_device *dev) ...@@ -708,6 +742,7 @@ static int pl010_remove(struct amba_device *dev)
amba_ports[i] = NULL; amba_ports[i] = NULL;
iounmap(uap->port.membase); iounmap(uap->port.membase);
clk_put(uap->clk);
kfree(uap); kfree(uap);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment