diff options
-rw-r--r-- | arch/arm/common/sa1111.c | 9 | ||||
-rw-r--r-- | arch/arm/common/timer-sp.c | 9 | ||||
-rw-r--r-- | drivers/amba/bus.c | 11 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.c | 9 | ||||
-rw-r--r-- | drivers/spi/spi-pl022.c | 10 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl010.c | 14 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 14 | ||||
-rw-r--r-- | drivers/video/amba-clcd.c | 9 | ||||
-rw-r--r-- | include/linux/clk.h | 43 | ||||
-rw-r--r-- | include/linux/clkdev.h | 7 |
10 files changed, 129 insertions, 6 deletions
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 0569de6acfb..61691cdbdcf 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -718,6 +718,10 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) goto err_free; } + ret = clk_prepare(sachip->clk); + if (ret) + goto err_clkput; + spin_lock_init(&sachip->lock); sachip->dev = me; @@ -733,7 +737,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) sachip->base = ioremap(mem->start, PAGE_SIZE * 2); if (!sachip->base) { ret = -ENOMEM; - goto err_clkput; + goto err_clk_unprep; } /* @@ -809,6 +813,8 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) err_unmap: iounmap(sachip->base); + err_clk_unprep: + clk_unprepare(sachip->clk); err_clkput: clk_put(sachip->clk); err_free: @@ -835,6 +841,7 @@ static void __sa1111_remove(struct sa1111 *sachip) sa1111_writel(0, irqbase + SA1111_WAKEEN1); clk_disable(sachip->clk); + clk_unprepare(sachip->clk); if (sachip->irq != NO_IRQ) { irq_set_chained_handler(sachip->irq, NULL); diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 41df4787512..2393b5bc96f 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -41,9 +41,17 @@ static long __init sp804_get_clock_rate(const char *name) return PTR_ERR(clk); } + err = clk_prepare(clk); + if (err) { + pr_err("sp804: %s clock failed to prepare: %d\n", name, err); + clk_put(clk); + return err; + } + err = clk_enable(clk); if (err) { pr_err("sp804: %s clock failed to enable: %d\n", name, err); + clk_unprepare(clk); clk_put(clk); return err; } @@ -52,6 +60,7 @@ static long __init sp804_get_clock_rate(const char *name) if (rate < 0) { pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); clk_disable(clk); + clk_unprepare(clk); clk_put(clk); } diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 84bdaace56c..bd230e80113 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -460,9 +460,17 @@ static int amba_get_enable_pclk(struct amba_device *pcdev) if (IS_ERR(pclk)) return PTR_ERR(pclk); + ret = clk_prepare(pclk); + if (ret) { + clk_put(pclk); + return ret; + } + ret = clk_enable(pclk); - if (ret) + if (ret) { + clk_unprepare(pclk); clk_put(pclk); + } return ret; } @@ -472,6 +480,7 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) struct clk *pclk = pcdev->pclk; clk_disable(pclk); + clk_unprepare(pclk); clk_put(pclk); } diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5e142b7f5ec..7be8db0f9f7 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1160,10 +1160,14 @@ static int __devinit mmci_probe(struct amba_device *dev, goto host_free; } - ret = clk_enable(host->clk); + ret = clk_prepare(host->clk); if (ret) goto clk_free; + ret = clk_enable(host->clk); + if (ret) + goto clk_unprep; + host->plat = plat; host->variant = variant; host->mclk = clk_get_rate(host->clk); @@ -1351,6 +1355,8 @@ static int __devinit mmci_probe(struct amba_device *dev, iounmap(host->base); clk_disable: clk_disable(host->clk); + clk_unprep: + clk_unprepare(host->clk); clk_free: clk_put(host->clk); host_free: @@ -1398,6 +1404,7 @@ static int __devexit mmci_remove(struct amba_device *dev) iounmap(host->base); clk_disable(host->clk); + clk_unprepare(host->clk); clk_put(host->clk); if (host->vcc) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 3520cf955b9..1ab2fa0d37f 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2187,6 +2187,13 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); goto err_no_clk; } + + status = clk_prepare(pl022->clk); + if (status) { + dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n"); + goto err_clk_prep; + } + /* Disable SSP */ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); @@ -2238,6 +2245,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022_dma_remove(pl022); free_irq(adev->irq[0], pl022); err_no_irq: + clk_unprepare(pl022->clk); + err_clk_prep: clk_put(pl022->clk); err_no_clk: iounmap(pl022->virtbase); @@ -2271,6 +2280,7 @@ pl022_remove(struct amba_device *adev) pl022_dma_remove(pl022); free_irq(adev->irq[0], pl022); clk_disable(pl022->clk); + clk_unprepare(pl022->clk); clk_put(pl022->clk); iounmap(pl022->virtbase); amba_release_regions(adev); diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index c0d10c4ddb7..efdf92c3a35 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -312,12 +312,16 @@ static int pl010_startup(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; + retval = clk_prepare(uap->clk); + if (retval) + goto out; + /* * Try to enable the clock producer. */ retval = clk_enable(uap->clk); if (retval) - goto out; + goto clk_unprep; uap->port.uartclk = clk_get_rate(uap->clk); @@ -343,6 +347,8 @@ static int pl010_startup(struct uart_port *port) clk_dis: clk_disable(uap->clk); + clk_unprep: + clk_unprepare(uap->clk); out: return retval; } @@ -370,6 +376,7 @@ static void pl010_shutdown(struct uart_port *port) * Shut down the clock producer */ clk_disable(uap->clk); + clk_unprepare(uap->clk); } static void @@ -626,6 +633,7 @@ static int __init pl010_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + int ret; /* * Check whether an invalid uart number has been specified, and @@ -638,6 +646,10 @@ static int __init pl010_console_setup(struct console *co, char *options) if (!uap) return -ENODEV; + ret = clk_prepare(uap->clk); + if (ret) + return ret; + uap->port.uartclk = clk_get_rate(uap->clk); if (options) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index f5f6831b0a6..00233af1acc 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1367,12 +1367,16 @@ static int pl011_startup(struct uart_port *port) unsigned int cr; int retval; + retval = clk_prepare(uap->clk); + if (retval) + goto out; + /* * Try to enable the clock producer. */ retval = clk_enable(uap->clk); if (retval) - goto out; + goto clk_unprep; uap->port.uartclk = clk_get_rate(uap->clk); @@ -1446,6 +1450,8 @@ static int pl011_startup(struct uart_port *port) clk_dis: clk_disable(uap->clk); + clk_unprep: + clk_unprepare(uap->clk); out: return retval; } @@ -1497,6 +1503,7 @@ static void pl011_shutdown(struct uart_port *port) * Shut down the clock producer */ clk_disable(uap->clk); + clk_unprepare(uap->clk); if (uap->port.dev->platform_data) { struct amba_pl011_data *plat; @@ -1800,6 +1807,7 @@ static int __init pl011_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + int ret; /* * Check whether an invalid uart number has been specified, and @@ -1812,6 +1820,10 @@ static int __init pl011_console_setup(struct console *co, char *options) if (!uap) return -ENODEV; + ret = clk_prepare(uap->clk); + if (ret) + return ret; + if (uap->port.dev->platform_data) { struct amba_pl011_data *plat; diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index cf03ad06714..2cda6ba0939 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -447,6 +447,10 @@ static int clcdfb_register(struct clcd_fb *fb) goto out; } + ret = clk_prepare(fb->clk); + if (ret) + goto free_clk; + fb->fb.device = &fb->dev->dev; fb->fb.fix.mmio_start = fb->dev->res.start; @@ -456,7 +460,7 @@ static int clcdfb_register(struct clcd_fb *fb) if (!fb->regs) { printk(KERN_ERR "CLCD: unable to remap registers\n"); ret = -ENOMEM; - goto free_clk; + goto clk_unprep; } fb->fb.fbops = &clcdfb_ops; @@ -530,6 +534,8 @@ static int clcdfb_register(struct clcd_fb *fb) fb_dealloc_cmap(&fb->fb.cmap); unmap: iounmap(fb->regs); + clk_unprep: + clk_unprepare(fb->clk); free_clk: clk_put(fb->clk); out: @@ -595,6 +601,7 @@ static int clcdfb_remove(struct amba_device *dev) if (fb->fb.cmap.len) fb_dealloc_cmap(&fb->fb.cmap); iounmap(fb->regs); + clk_unprepare(fb->clk); clk_put(fb->clk); fb->board->remove(fb); diff --git a/include/linux/clk.h b/include/linux/clk.h index 1d37f42ac29..7213b52b2c0 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -11,6 +11,8 @@ #ifndef __LINUX_CLK_H #define __LINUX_CLK_H +#include <linux/kernel.h> + struct device; /* @@ -41,11 +43,31 @@ struct clk; struct clk *clk_get(struct device *dev, const char *id); /** + * clk_prepare - prepare a clock source + * @clk: clock source + * + * This prepares the clock source for use. + * + * Must not be called from within atomic context. + */ +#ifdef CONFIG_HAVE_CLK_PREPARE +int clk_prepare(struct clk *clk); +#else +static inline int clk_prepare(struct clk *clk) +{ + might_sleep(); + return 0; +} +#endif + +/** * clk_enable - inform the system when the clock source should be running. * @clk: clock source * * If the clock can not be enabled/disabled, this should return success. * + * May be called from atomic contexts. + * * Returns success (0) or negative errno. */ int clk_enable(struct clk *clk); @@ -57,6 +79,8 @@ int clk_enable(struct clk *clk); * Inform the system that a clock source is no longer required by * a driver and may be shut down. * + * May be called from atomic contexts. + * * Implementation detail: if the clock source is shared between * multiple drivers, clk_enable() calls must be balanced by the * same number of clk_disable() calls for the clock source to be @@ -64,6 +88,25 @@ int clk_enable(struct clk *clk); */ void clk_disable(struct clk *clk); + +/** + * clk_unprepare - undo preparation of a clock source + * @clk: clock source + * + * This undoes a previously prepared clock. The caller must balance + * the number of prepare and unprepare calls. + * + * Must not be called from within atomic context. + */ +#ifdef CONFIG_HAVE_CLK_PREPARE +void clk_unprepare(struct clk *clk); +#else +static inline void clk_unprepare(struct clk *clk) +{ + might_sleep(); +} +#endif + /** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index 457bcb0a310..d9a4fd028c9 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -24,6 +24,13 @@ struct clk_lookup { struct clk *clk; }; +#define CLKDEV_INIT(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = c, \ + } + struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...); |