]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/arm/plat-omap/clock.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[mirror_ubuntu-bionic-kernel.git] / arch / arm / plat-omap / clock.c
CommitLineData
1da177e4 1/*
b9158556 2 * linux/arch/arm/plat-omap/clock.c
1da177e4 3 *
1a8bfa1e 4 * Copyright (C) 2004 - 2005 Nokia corporation
1da177e4
LT
5 * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
6 *
1a8bfa1e
TL
7 * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
8 *
1da177e4
LT
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
1a8bfa1e
TL
13#include <linux/version.h>
14#include <linux/config.h>
1da177e4 15#include <linux/kernel.h>
1a8bfa1e
TL
16#include <linux/init.h>
17#include <linux/module.h>
1da177e4
LT
18#include <linux/list.h>
19#include <linux/errno.h>
20#include <linux/err.h>
4e57b681 21#include <linux/string.h>
f8ce2547 22#include <linux/clk.h>
1da177e4 23
bb13b5fd 24#include <asm/io.h>
1da177e4 25#include <asm/semaphore.h>
1da177e4 26
1a8bfa1e 27#include <asm/arch/clock.h>
1da177e4 28
1a8bfa1e 29LIST_HEAD(clocks);
1da177e4 30static DECLARE_MUTEX(clocks_sem);
1a8bfa1e 31DEFINE_SPINLOCK(clockfw_lock);
1da177e4 32
1a8bfa1e 33static struct clk_functions *arch_clock;
1da177e4 34
1a8bfa1e
TL
35/*-------------------------------------------------------------------------
36 * Standard clock functions defined in asm/hardware/clock.h
37 *-------------------------------------------------------------------------*/
1da177e4 38
1a8bfa1e 39struct clk * clk_get(struct device *dev, const char *id)
1da177e4
LT
40{
41 struct clk *p, *clk = ERR_PTR(-ENOENT);
42
43 down(&clocks_sem);
44 list_for_each_entry(p, &clocks, node) {
45 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
46 clk = p;
47 break;
48 }
49 }
50 up(&clocks_sem);
51
52 return clk;
53}
54EXPORT_SYMBOL(clk_get);
55
1da177e4
LT
56int clk_enable(struct clk *clk)
57{
58 unsigned long flags;
1a8bfa1e 59 int ret = 0;
1da177e4
LT
60
61 spin_lock_irqsave(&clockfw_lock, flags);
1a8bfa1e
TL
62 if (clk->enable)
63 ret = clk->enable(clk);
64 else if (arch_clock->clk_enable)
65 ret = arch_clock->clk_enable(clk);
66 else
67 printk(KERN_ERR "Could not enable clock %s\n", clk->name);
1da177e4 68 spin_unlock_irqrestore(&clockfw_lock, flags);
1a8bfa1e 69
1da177e4
LT
70 return ret;
71}
72EXPORT_SYMBOL(clk_enable);
73
1da177e4
LT
74void clk_disable(struct clk *clk)
75{
76 unsigned long flags;
77
78 spin_lock_irqsave(&clockfw_lock, flags);
1a8bfa1e
TL
79 if (clk->disable)
80 clk->disable(clk);
81 else if (arch_clock->clk_disable)
82 arch_clock->clk_disable(clk);
83 else
84 printk(KERN_ERR "Could not disable clock %s\n", clk->name);
1da177e4
LT
85 spin_unlock_irqrestore(&clockfw_lock, flags);
86}
87EXPORT_SYMBOL(clk_disable);
88
1da177e4
LT
89int clk_use(struct clk *clk)
90{
91 unsigned long flags;
92 int ret = 0;
93
94 spin_lock_irqsave(&clockfw_lock, flags);
1a8bfa1e
TL
95 if (arch_clock->clk_use)
96 ret = arch_clock->clk_use(clk);
1da177e4 97 spin_unlock_irqrestore(&clockfw_lock, flags);
1a8bfa1e 98
1da177e4
LT
99 return ret;
100}
101EXPORT_SYMBOL(clk_use);
102
1da177e4
LT
103void clk_unuse(struct clk *clk)
104{
105 unsigned long flags;
106
107 spin_lock_irqsave(&clockfw_lock, flags);
1a8bfa1e
TL
108 if (arch_clock->clk_unuse)
109 arch_clock->clk_unuse(clk);
1da177e4
LT
110 spin_unlock_irqrestore(&clockfw_lock, flags);
111}
112EXPORT_SYMBOL(clk_unuse);
113
1da177e4
LT
114int clk_get_usecount(struct clk *clk)
115{
1a8bfa1e
TL
116 unsigned long flags;
117 int ret = 0;
1da177e4 118
1a8bfa1e
TL
119 spin_lock_irqsave(&clockfw_lock, flags);
120 ret = clk->usecount;
121 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4 122
1a8bfa1e 123 return ret;
1da177e4 124}
1a8bfa1e 125EXPORT_SYMBOL(clk_get_usecount);
1da177e4 126
1a8bfa1e 127unsigned long clk_get_rate(struct clk *clk)
1da177e4 128{
1a8bfa1e
TL
129 unsigned long flags;
130 unsigned long ret = 0;
1da177e4 131
1a8bfa1e
TL
132 spin_lock_irqsave(&clockfw_lock, flags);
133 ret = clk->rate;
134 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4 135
1a8bfa1e 136 return ret;
1da177e4 137}
1a8bfa1e 138EXPORT_SYMBOL(clk_get_rate);
1da177e4 139
1a8bfa1e 140void clk_put(struct clk *clk)
bb13b5fd 141{
1a8bfa1e
TL
142 if (clk && !IS_ERR(clk))
143 module_put(clk->owner);
bb13b5fd 144}
1a8bfa1e 145EXPORT_SYMBOL(clk_put);
bb13b5fd 146
1a8bfa1e
TL
147/*-------------------------------------------------------------------------
148 * Optional clock functions defined in asm/hardware/clock.h
149 *-------------------------------------------------------------------------*/
bb13b5fd 150
1da177e4
LT
151long clk_round_rate(struct clk *clk, unsigned long rate)
152{
1a8bfa1e
TL
153 unsigned long flags;
154 long ret = 0;
1da177e4 155
1a8bfa1e
TL
156 spin_lock_irqsave(&clockfw_lock, flags);
157 if (arch_clock->clk_round_rate)
158 ret = arch_clock->clk_round_rate(clk, rate);
159 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4 160
1a8bfa1e 161 return ret;
1da177e4
LT
162}
163EXPORT_SYMBOL(clk_round_rate);
164
1a8bfa1e 165int clk_set_rate(struct clk *clk, unsigned long rate)
1da177e4 166{
1a8bfa1e
TL
167 unsigned long flags;
168 int ret = 0;
bb13b5fd 169
1a8bfa1e
TL
170 spin_lock_irqsave(&clockfw_lock, flags);
171 if (arch_clock->clk_set_rate)
172 ret = arch_clock->clk_set_rate(clk, rate);
173 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4 174
1a8bfa1e 175 return ret;
1da177e4 176}
1a8bfa1e 177EXPORT_SYMBOL(clk_set_rate);
1da177e4 178
1a8bfa1e 179int clk_set_parent(struct clk *clk, struct clk *parent)
1da177e4 180{
1a8bfa1e
TL
181 unsigned long flags;
182 int ret = 0;
1da177e4 183
1a8bfa1e
TL
184 spin_lock_irqsave(&clockfw_lock, flags);
185 if (arch_clock->clk_set_parent)
186 ret = arch_clock->clk_set_parent(clk, parent);
187 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4 188
1a8bfa1e 189 return ret;
1da177e4 190}
1a8bfa1e 191EXPORT_SYMBOL(clk_set_parent);
1da177e4 192
1a8bfa1e 193struct clk *clk_get_parent(struct clk *clk)
1da177e4 194{
1a8bfa1e
TL
195 unsigned long flags;
196 struct clk * ret = NULL;
1da177e4 197
1a8bfa1e
TL
198 spin_lock_irqsave(&clockfw_lock, flags);
199 if (arch_clock->clk_get_parent)
200 ret = arch_clock->clk_get_parent(clk);
201 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4
LT
202
203 return ret;
204}
1a8bfa1e 205EXPORT_SYMBOL(clk_get_parent);
1da177e4 206
1a8bfa1e
TL
207/*-------------------------------------------------------------------------
208 * OMAP specific clock functions shared between omap1 and omap2
209 *-------------------------------------------------------------------------*/
1da177e4 210
1a8bfa1e 211unsigned int __initdata mpurate;
1da177e4 212
1a8bfa1e
TL
213/*
214 * By default we use the rate set by the bootloader.
215 * You can override this with mpurate= cmdline option.
216 */
217static int __init omap_clk_setup(char *str)
1da177e4 218{
1a8bfa1e 219 get_option(&str, &mpurate);
1da177e4 220
1a8bfa1e
TL
221 if (!mpurate)
222 return 1;
1da177e4 223
1a8bfa1e
TL
224 if (mpurate < 1000)
225 mpurate *= 1000000;
1da177e4 226
1a8bfa1e 227 return 1;
1da177e4 228}
1a8bfa1e 229__setup("mpurate=", omap_clk_setup);
1da177e4 230
1a8bfa1e
TL
231/* Used for clocks that always have same value as the parent clock */
232void followparent_recalc(struct clk *clk)
1da177e4 233{
1a8bfa1e 234 clk->rate = clk->parent->rate;
1da177e4
LT
235}
236
1a8bfa1e
TL
237/* Propagate rate to children */
238void propagate_rate(struct clk * tclk)
1da177e4 239{
1a8bfa1e 240 struct clk *clkp;
1da177e4 241
1a8bfa1e
TL
242 list_for_each_entry(clkp, &clocks, node) {
243 if (likely(clkp->parent != tclk))
244 continue;
245 if (likely((u32)clkp->recalc))
246 clkp->recalc(clkp);
247 }
1da177e4
LT
248}
249
1da177e4
LT
250int clk_register(struct clk *clk)
251{
252 down(&clocks_sem);
253 list_add(&clk->node, &clocks);
254 if (clk->init)
255 clk->init(clk);
256 up(&clocks_sem);
1a8bfa1e 257
1da177e4
LT
258 return 0;
259}
260EXPORT_SYMBOL(clk_register);
261
262void clk_unregister(struct clk *clk)
263{
264 down(&clocks_sem);
265 list_del(&clk->node);
266 up(&clocks_sem);
267}
268EXPORT_SYMBOL(clk_unregister);
269
1a8bfa1e 270void clk_deny_idle(struct clk *clk)
bb13b5fd 271{
1a8bfa1e
TL
272 unsigned long flags;
273
274 spin_lock_irqsave(&clockfw_lock, flags);
275 if (arch_clock->clk_deny_idle)
276 arch_clock->clk_deny_idle(clk);
277 spin_unlock_irqrestore(&clockfw_lock, flags);
bb13b5fd 278}
1a8bfa1e 279EXPORT_SYMBOL(clk_deny_idle);
1da177e4 280
1a8bfa1e 281void clk_allow_idle(struct clk *clk)
1da177e4 282{
1a8bfa1e 283 unsigned long flags;
1da177e4 284
1a8bfa1e
TL
285 spin_lock_irqsave(&clockfw_lock, flags);
286 if (arch_clock->clk_allow_idle)
287 arch_clock->clk_allow_idle(clk);
288 spin_unlock_irqrestore(&clockfw_lock, flags);
1da177e4 289}
1a8bfa1e 290EXPORT_SYMBOL(clk_allow_idle);
bb13b5fd 291
1a8bfa1e 292/*-------------------------------------------------------------------------*/
bb13b5fd 293
1a8bfa1e 294int __init clk_init(struct clk_functions * custom_clocks)
bb13b5fd 295{
1a8bfa1e
TL
296 if (!custom_clocks) {
297 printk(KERN_ERR "No custom clock functions registered\n");
298 BUG();
bb13b5fd
TL
299 }
300
1a8bfa1e
TL
301 arch_clock = custom_clocks;
302
bb13b5fd
TL
303 return 0;
304}