summary refs log tree commit diff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-27 08:41:50 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-27 08:41:50 +0200
commit18974369cfe23acf16d0fb79e0d1fba7a9a95ec0 (patch)
tree22367984dbd4c79e9635035e268c428444c40e76
parent7e0a6fd5a4723c79cc46c9541e343092302e0e5b (diff)
parent196a57c2749119be4732cc2b2adb8aafcb4fcb14 (diff)
downloadlinux-18974369cfe23acf16d0fb79e0d1fba7a9a95ec0.tar.gz
Merge branch 'clk' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-2.6-arm
* 'clk' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-2.6-arm:
  ARM: 7131/1: clkdev: Add Common Macro for clk_lookup
  clk: spi-pl022: convert to clk_prepare()/clk_unprepare()
  clk: timer-sp: convert to clk_prepare()/clk_unprepare()
  clk: sa1111: convert to clk_prepare()/clk_unprepare()
  clk: mmci: convert to clk_prepare()/clk_unprepare()
  clk: amba-pl011: convert to clk_prepare()/clk_unprepare()
  clk: amba-pl010: convert to clk_prepare()/clk_unprepare()
  clk: amba-clcd: convert to clk_prepare()/clk_unprepare()
  clk: amba bus: convert to clk_prepare()/clk_unprepare()
  clk: provide prepare/unprepare functions
-rw-r--r--arch/arm/common/sa1111.c9
-rw-r--r--arch/arm/common/timer-sp.c9
-rw-r--r--drivers/amba/bus.c11
-rw-r--r--drivers/mmc/host/mmci.c9
-rw-r--r--drivers/spi/spi-pl022.c10
-rw-r--r--drivers/tty/serial/amba-pl010.c14
-rw-r--r--drivers/tty/serial/amba-pl011.c14
-rw-r--r--drivers/video/amba-clcd.c9
-rw-r--r--include/linux/clk.h43
-rw-r--r--include/linux/clkdev.h7
10 files changed, 129 insertions, 6 deletions
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 0569de6acfba..61691cdbdcf2 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 41df47875122..2393b5bc96fa 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 84bdaace56c8..bd230e801131 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 5e142b7f5ecf..7be8db0f9f7d 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 3520cf955b95..1ab2fa0d37fd 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 c0d10c4ddb73..efdf92c3a352 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 f5f6831b0a64..00233af1acc4 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 cf03ad067147..2cda6ba0939b 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 1d37f42ac294..7213b52b2c0e 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 457bcb0a310a..d9a4fd028c9d 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, ...);