summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/common/sa1111.c41
-rw-r--r--arch/arm/mach-pxa/Makefile2
-rw-r--r--arch/arm/mach-pxa/clock.c124
-rw-r--r--arch/arm/mach-sa1100/Makefile2
-rw-r--r--arch/arm/mach-sa1100/clock.c132
5 files changed, 278 insertions, 23 deletions
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 93352f6097c..5ba1ee04234 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
@@ -36,10 +37,6 @@
#include <asm/hardware/sa1111.h>
-#ifdef CONFIG_ARCH_PXA
-#include <asm/arch/pxa-regs.h>
-#endif
-
extern void __init sa1110_mb_enable(void);
/*
@@ -51,6 +48,7 @@ extern void __init sa1110_mb_enable(void);
*/
struct sa1111 {
struct device *dev;
+ struct clk *clk;
unsigned long phys;
int irq;
spinlock_t lock;
@@ -451,19 +449,7 @@ static void sa1111_wake(struct sa1111 *sachip)
spin_lock_irqsave(&sachip->lock, flags);
-#ifdef CONFIG_ARCH_SA1100
- /*
- * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
- * (SA-1110 Developer's Manual, section 9.1.2.1)
- */
- GAFR |= GPIO_32_768kHz;
- GPDR |= GPIO_32_768kHz;
- TUCR = TUCR_3_6864MHz;
-#elif CONFIG_ARCH_PXA
- pxa_gpio_mode(GPIO11_3_6MHz_MD);
-#else
-#error missing clock setup
-#endif
+ clk_enable(sachip->clk);
/*
* Turn VCO on, and disable PLL Bypass.
@@ -641,6 +627,12 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
memset(sachip, 0, sizeof(struct sa1111));
+ sachip->clk = clk_get(me, "GPIO27_CLK");
+ if (!sachip->clk) {
+ ret = PTR_ERR(sachip->clk);
+ goto err_free;
+ }
+
spin_lock_init(&sachip->lock);
sachip->dev = me;
@@ -656,7 +648,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 out;
+ goto err_clkput;
}
/*
@@ -666,7 +658,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
ret = -ENODEV;
- goto unmap;
+ goto err_unmap;
}
printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
@@ -726,9 +718,11 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
return 0;
- unmap:
+ err_unmap:
iounmap(sachip->base);
- out:
+ err_clkput:
+ clk_put(sachip->clk);
+ err_free:
kfree(sachip);
return ret;
}
@@ -751,6 +745,8 @@ static void __sa1111_remove(struct sa1111 *sachip)
sa1111_writel(0, irqbase + SA1111_WAKEEN0);
sa1111_writel(0, irqbase + SA1111_WAKEEN1);
+ clk_disable(sachip->clk);
+
if (sachip->irq != NO_IRQ) {
set_irq_chained_handler(sachip->irq, NULL);
set_irq_data(sachip->irq, NULL);
@@ -759,6 +755,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
}
iounmap(sachip->base);
+ clk_put(sachip->clk);
kfree(sachip);
}
@@ -857,6 +854,8 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
sa1111_writel(0, sachip->base + SA1111_SKPWM0);
sa1111_writel(0, sachip->base + SA1111_SKPWM1);
+ clk_disable(sachip->clk);
+
spin_unlock_irqrestore(&sachip->lock, flags);
return 0;
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 32526a0a6f8..382644401a4 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -3,7 +3,7 @@
#
# Common support (must be linked before board specific support)
-obj-y += generic.o irq.o dma.o time.o
+obj-y += clock.o generic.o irq.o dma.o time.o
obj-$(CONFIG_PXA25x) += pxa25x.o
obj-$(CONFIG_PXA27x) += pxa27x.o
diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c
new file mode 100644
index 00000000000..8f7c90a0593
--- /dev/null
+++ b/arch/arm/mach-pxa/clock.c
@@ -0,0 +1,124 @@
+/*
+ * linux/arch/arm/mach-sa1100/clock.c
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+struct clk {
+ struct list_head node;
+ unsigned long rate;
+ struct module *owner;
+ const char *name;
+ unsigned int enabled;
+ void (*enable)(void);
+ void (*disable)(void);
+};
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+static DEFINE_SPINLOCK(clocks_lock);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+ down(&clocks_sem);
+ list_for_each_entry(p, &clocks, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+ up(&clocks_sem);
+
+ return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ if (clk->enabled++ == 0)
+ clk->enable();
+ spin_unlock_irqrestore(&clocks_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ WARN_ON(clk->enabled == 0);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ if (--clk->enabled == 0)
+ clk->disable();
+ spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+
+static void clk_gpio27_enable(void)
+{
+ pxa_gpio_mode(GPIO11_3_6MHz_MD);
+}
+
+static void clk_gpio27_disable(void)
+{
+}
+
+static struct clk clk_gpio27 = {
+ .name = "GPIO27_CLK",
+ .rate = 3686400,
+ .enable = clk_gpio27_enable,
+ .disable = clk_gpio27_disable,
+};
+
+int clk_register(struct clk *clk)
+{
+ down(&clocks_sem);
+ list_add(&clk->node, &clocks);
+ up(&clocks_sem);
+ return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+ down(&clocks_sem);
+ list_del(&clk->node);
+ up(&clocks_sem);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static int __init clk_init(void)
+{
+ clk_register(&clk_gpio27);
+ return 0;
+}
+arch_initcall(clk_init);
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index e4a4a3e8aa8..e27f15042a2 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -3,7 +3,7 @@
#
# Common support
-obj-y := generic.o irq.o dma.o time.o
+obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
new file mode 100644
index 00000000000..b1e8fd766c1
--- /dev/null
+++ b/arch/arm/mach-sa1100/clock.c
@@ -0,0 +1,132 @@
+/*
+ * linux/arch/arm/mach-sa1100/clock.c
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/semaphore.h>
+
+struct clk {
+ struct list_head node;
+ unsigned long rate;
+ struct module *owner;
+ const char *name;
+ unsigned int enabled;
+ void (*enable)(void);
+ void (*disable)(void);
+};
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+static DEFINE_SPINLOCK(clocks_lock);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+ down(&clocks_sem);
+ list_for_each_entry(p, &clocks, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+ up(&clocks_sem);
+
+ return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ if (clk->enabled++ == 0)
+ clk->enable();
+ spin_unlock_irqrestore(&clocks_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ WARN_ON(clk->enabled == 0);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ if (--clk->enabled == 0)
+ clk->disable();
+ spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+
+static void clk_gpio27_enable(void)
+{
+ /*
+ * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+ * (SA-1110 Developer's Manual, section 9.1.2.1)
+ */
+ GAFR |= GPIO_32_768kHz;
+ GPDR |= GPIO_32_768kHz;
+ TUCR = TUCR_3_6864MHz;
+}
+
+static void clk_gpio27_disable(void)
+{
+ TUCR = 0;
+ GPDR &= ~GPIO_32_768kHz;
+ GAFR &= ~GPIO_32_768kHz;
+}
+
+static struct clk clk_gpio27 = {
+ .name = "GPIO27_CLK",
+ .rate = 3686400,
+ .enable = clk_gpio27_enable,
+ .disable = clk_gpio27_disable,
+};
+
+int clk_register(struct clk *clk)
+{
+ down(&clocks_sem);
+ list_add(&clk->node, &clocks);
+ up(&clocks_sem);
+ return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+ down(&clocks_sem);
+ list_del(&clk->node);
+ up(&clocks_sem);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static int __init clk_init(void)
+{
+ clk_register(&clk_gpio27);
+ return 0;
+}
+arch_initcall(clk_init);