1/* 2 * linux/arch/arm/mach-sa1100/clock.c 3 */ 4#include <linux/module.h> 5#include <linux/kernel.h> 6#include <linux/list.h> 7#include <linux/errno.h> 8#include <linux/err.h> 9#include <linux/string.h> 10#include <linux/clk.h> 11#include <linux/spinlock.h> 12 13#include <asm/arch/pxa-regs.h> 14#include <asm/hardware.h> 15#include <asm/semaphore.h> 16 17struct clk { 18 struct list_head node; 19 unsigned long rate; 20 struct module *owner; 21 const char *name; 22 unsigned int enabled; 23 void (*enable)(void); 24 void (*disable)(void); 25}; 26 27static LIST_HEAD(clocks); 28static DECLARE_MUTEX(clocks_sem); 29static DEFINE_SPINLOCK(clocks_lock); 30 31struct clk *clk_get(struct device *dev, const char *id) 32{ 33 struct clk *p, *clk = ERR_PTR(-ENOENT); 34 35 down(&clocks_sem); 36 list_for_each_entry(p, &clocks, node) { 37 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { 38 clk = p; 39 break; 40 } 41 } 42 up(&clocks_sem); 43 44 return clk; 45} 46EXPORT_SYMBOL(clk_get); 47 48void clk_put(struct clk *clk) 49{ 50 module_put(clk->owner); 51} 52EXPORT_SYMBOL(clk_put); 53 54int clk_enable(struct clk *clk) 55{ 56 unsigned long flags; 57 58 spin_lock_irqsave(&clocks_lock, flags); 59 if (clk->enabled++ == 0) 60 clk->enable(); 61 spin_unlock_irqrestore(&clocks_lock, flags); 62 return 0; 63} 64EXPORT_SYMBOL(clk_enable); 65 66void clk_disable(struct clk *clk) 67{ 68 unsigned long flags; 69 70 WARN_ON(clk->enabled == 0); 71 72 spin_lock_irqsave(&clocks_lock, flags); 73 if (--clk->enabled == 0) 74 clk->disable(); 75 spin_unlock_irqrestore(&clocks_lock, flags); 76} 77EXPORT_SYMBOL(clk_disable); 78 79unsigned long clk_get_rate(struct clk *clk) 80{ 81 return clk->rate; 82} 83EXPORT_SYMBOL(clk_get_rate); 84 85 86static void clk_gpio27_enable(void) 87{ 88 pxa_gpio_mode(GPIO11_3_6MHz_MD); 89} 90 91static void clk_gpio27_disable(void) 92{ 93} 94 95static struct clk clk_gpio27 = { 96 .name = "GPIO27_CLK", 97 .rate = 3686400, 98 .enable = clk_gpio27_enable, 99 .disable = clk_gpio27_disable, 100}; 101 102int clk_register(struct clk *clk) 103{ 104 down(&clocks_sem); 105 list_add(&clk->node, &clocks); 106 up(&clocks_sem); 107 return 0; 108} 109EXPORT_SYMBOL(clk_register); 110 111void clk_unregister(struct clk *clk) 112{ 113 down(&clocks_sem); 114 list_del(&clk->node); 115 up(&clocks_sem); 116} 117EXPORT_SYMBOL(clk_unregister); 118 119static int __init clk_init(void) 120{ 121 clk_register(&clk_gpio27); 122 return 0; 123} 124arch_initcall(clk_init); 125