clock.c 9.4 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  linux/arch/arm/plat-omap/clock.c
L
Linus Torvalds 已提交
3
 *
4
 *  Copyright (C) 2004 - 2005 Nokia corporation
L
Linus Torvalds 已提交
5 6
 *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
 *
7 8
 *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
 *
L
Linus Torvalds 已提交
9 10 11 12
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
13
#include <linux/version.h>
L
Linus Torvalds 已提交
14
#include <linux/kernel.h>
15 16
#include <linux/init.h>
#include <linux/module.h>
L
Linus Torvalds 已提交
17 18 19
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
T
Tim Schmielau 已提交
20
#include <linux/string.h>
21
#include <linux/clk.h>
22
#include <linux/mutex.h>
23
#include <linux/platform_device.h>
24
#include <linux/cpufreq.h>
L
Linus Torvalds 已提交
25

26
#include <asm/io.h>
L
Linus Torvalds 已提交
27

28
#include <asm/arch/clock.h>
L
Linus Torvalds 已提交
29

30
static LIST_HEAD(clocks);
31
static DEFINE_MUTEX(clocks_mutex);
32
static DEFINE_SPINLOCK(clockfw_lock);
L
Linus Torvalds 已提交
33

34
static struct clk_functions *arch_clock;
L
Linus Torvalds 已提交
35

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
#ifdef CONFIG_PM_DEBUG

static void print_parents(struct clk *clk)
{
	struct clk *p;
	int printed = 0;

	list_for_each_entry(p, &clocks, node) {
		if (p->parent == clk && p->usecount) {
			if (!clk->usecount && !printed) {
				printk("MISMATCH: %s\n", clk->name);
				printed = 1;
			}
			printk("\t%-15s\n", p->name);
		}
	}
}

void clk_print_usecounts(void)
{
	unsigned long flags;
	struct clk *p;

	spin_lock_irqsave(&clockfw_lock, flags);
	list_for_each_entry(p, &clocks, node) {
		if (p->usecount)
			printk("%-15s: %d\n", p->name, p->usecount);
		print_parents(p);

	}
	spin_unlock_irqrestore(&clockfw_lock, flags);
}

#endif

71
/*-------------------------------------------------------------------------
72
 * Standard clock functions defined in include/linux/clk.h
73
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
74

75 76 77 78
/*
 * Returns a clock. Note that we first try to use device id on the bus
 * and clock name. If this fails, we try to use clock name only.
 */
79
struct clk * clk_get(struct device *dev, const char *id)
L
Linus Torvalds 已提交
80 81
{
	struct clk *p, *clk = ERR_PTR(-ENOENT);
82 83 84 85 86 87
	int idno;

	if (dev == NULL || dev->bus != &platform_bus_type)
		idno = -1;
	else
		idno = to_platform_device(dev)->id;
L
Linus Torvalds 已提交
88

89
	mutex_lock(&clocks_mutex);
90 91 92 93 94

	list_for_each_entry(p, &clocks, node) {
		if (p->id == idno &&
		    strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
			clk = p;
95
			goto found;
96 97 98
		}
	}

L
Linus Torvalds 已提交
99 100 101 102 103 104
	list_for_each_entry(p, &clocks, node) {
		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
			clk = p;
			break;
		}
	}
105

106
found:
107
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
108 109 110 111 112 113 114 115

	return clk;
}
EXPORT_SYMBOL(clk_get);

int clk_enable(struct clk *clk)
{
	unsigned long flags;
116
	int ret = 0;
L
Linus Torvalds 已提交
117

118 119 120
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

L
Linus Torvalds 已提交
121
	spin_lock_irqsave(&clockfw_lock, flags);
122
	if (arch_clock->clk_enable)
123
		ret = arch_clock->clk_enable(clk);
L
Linus Torvalds 已提交
124
	spin_unlock_irqrestore(&clockfw_lock, flags);
125

L
Linus Torvalds 已提交
126 127 128 129 130 131 132 133
	return ret;
}
EXPORT_SYMBOL(clk_enable);

void clk_disable(struct clk *clk)
{
	unsigned long flags;

134 135 136
	if (clk == NULL || IS_ERR(clk))
		return;

L
Linus Torvalds 已提交
137
	spin_lock_irqsave(&clockfw_lock, flags);
138 139 140 141 142 143 144
	if (clk->usecount == 0) {
		printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
		       clk->name);
		WARN_ON(1);
		goto out;
	}

145
	if (arch_clock->clk_disable)
146
		arch_clock->clk_disable(clk);
147 148

out:
L
Linus Torvalds 已提交
149 150 151 152 153 154
	spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_disable);

int clk_get_usecount(struct clk *clk)
{
155 156
	unsigned long flags;
	int ret = 0;
L
Linus Torvalds 已提交
157

158 159 160
	if (clk == NULL || IS_ERR(clk))
		return 0;

161 162 163
	spin_lock_irqsave(&clockfw_lock, flags);
	ret = clk->usecount;
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
164

165
	return ret;
L
Linus Torvalds 已提交
166
}
167
EXPORT_SYMBOL(clk_get_usecount);
L
Linus Torvalds 已提交
168

169
unsigned long clk_get_rate(struct clk *clk)
L
Linus Torvalds 已提交
170
{
171 172
	unsigned long flags;
	unsigned long ret = 0;
L
Linus Torvalds 已提交
173

174 175 176
	if (clk == NULL || IS_ERR(clk))
		return 0;

177 178 179
	spin_lock_irqsave(&clockfw_lock, flags);
	ret = clk->rate;
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
180

181
	return ret;
L
Linus Torvalds 已提交
182
}
183
EXPORT_SYMBOL(clk_get_rate);
L
Linus Torvalds 已提交
184

185
void clk_put(struct clk *clk)
186
{
187 188
	if (clk && !IS_ERR(clk))
		module_put(clk->owner);
189
}
190
EXPORT_SYMBOL(clk_put);
191

192
/*-------------------------------------------------------------------------
193
 * Optional clock functions defined in include/linux/clk.h
194
 *-------------------------------------------------------------------------*/
195

L
Linus Torvalds 已提交
196 197
long clk_round_rate(struct clk *clk, unsigned long rate)
{
198 199
	unsigned long flags;
	long ret = 0;
L
Linus Torvalds 已提交
200

201 202 203
	if (clk == NULL || IS_ERR(clk))
		return ret;

204 205 206 207
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_round_rate)
		ret = arch_clock->clk_round_rate(clk, rate);
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
208

209
	return ret;
L
Linus Torvalds 已提交
210 211 212
}
EXPORT_SYMBOL(clk_round_rate);

213
int clk_set_rate(struct clk *clk, unsigned long rate)
L
Linus Torvalds 已提交
214
{
215
	unsigned long flags;
216 217 218 219
	int ret = -EINVAL;

	if (clk == NULL || IS_ERR(clk))
		return ret;
220

221 222 223 224
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_set_rate)
		ret = arch_clock->clk_set_rate(clk, rate);
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
225

226
	return ret;
L
Linus Torvalds 已提交
227
}
228
EXPORT_SYMBOL(clk_set_rate);
L
Linus Torvalds 已提交
229

230
int clk_set_parent(struct clk *clk, struct clk *parent)
L
Linus Torvalds 已提交
231
{
232
	unsigned long flags;
233 234 235 236
	int ret = -EINVAL;

	if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
		return ret;
L
Linus Torvalds 已提交
237

238 239 240 241
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_set_parent)
		ret =  arch_clock->clk_set_parent(clk, parent);
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
242

243
	return ret;
L
Linus Torvalds 已提交
244
}
245
EXPORT_SYMBOL(clk_set_parent);
L
Linus Torvalds 已提交
246

247
struct clk *clk_get_parent(struct clk *clk)
L
Linus Torvalds 已提交
248
{
249 250
	unsigned long flags;
	struct clk * ret = NULL;
L
Linus Torvalds 已提交
251

252 253 254
	if (clk == NULL || IS_ERR(clk))
		return ret;

255 256 257 258
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_get_parent)
		ret = arch_clock->clk_get_parent(clk);
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
259 260 261

	return ret;
}
262
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
263

264 265 266
/*-------------------------------------------------------------------------
 * OMAP specific clock functions shared between omap1 and omap2
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
267

268
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
269

270 271 272 273 274
/*
 * By default we use the rate set by the bootloader.
 * You can override this with mpurate= cmdline option.
 */
static int __init omap_clk_setup(char *str)
L
Linus Torvalds 已提交
275
{
276
	get_option(&str, &mpurate);
L
Linus Torvalds 已提交
277

278 279
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
280

281 282
	if (mpurate < 1000)
		mpurate *= 1000000;
L
Linus Torvalds 已提交
283

284
	return 1;
L
Linus Torvalds 已提交
285
}
286
__setup("mpurate=", omap_clk_setup);
L
Linus Torvalds 已提交
287

288 289
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc(struct clk *clk)
L
Linus Torvalds 已提交
290
{
291 292 293
	if (clk == NULL || IS_ERR(clk))
		return;

294
	clk->rate = clk->parent->rate;
295 296
	if (unlikely(clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
L
Linus Torvalds 已提交
297 298
}

299 300
/* Propagate rate to children */
void propagate_rate(struct clk * tclk)
L
Linus Torvalds 已提交
301
{
302
	struct clk *clkp;
L
Linus Torvalds 已提交
303

304 305 306
	if (tclk == NULL || IS_ERR(tclk))
		return;

307 308 309 310 311 312
	list_for_each_entry(clkp, &clocks, node) {
		if (likely(clkp->parent != tclk))
			continue;
		if (likely((u32)clkp->recalc))
			clkp->recalc(clkp);
	}
L
Linus Torvalds 已提交
313 314
}

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
/**
 * recalculate_root_clocks - recalculate and propagate all root clocks
 *
 * Recalculates all root clocks (clocks with no parent), which if the
 * clock's .recalc is set correctly, should also propagate their rates.
 * Called at init.
 */
void recalculate_root_clocks(void)
{
	struct clk *clkp;

	list_for_each_entry(clkp, &clocks, node) {
		if (unlikely(!clkp->parent) && likely((u32)clkp->recalc))
			clkp->recalc(clkp);
	}
}

L
Linus Torvalds 已提交
332 333
int clk_register(struct clk *clk)
{
334 335 336
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

337
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
338 339 340
	list_add(&clk->node, &clocks);
	if (clk->init)
		clk->init(clk);
341
	mutex_unlock(&clocks_mutex);
342

L
Linus Torvalds 已提交
343 344 345 346 347 348
	return 0;
}
EXPORT_SYMBOL(clk_register);

void clk_unregister(struct clk *clk)
{
349 350 351
	if (clk == NULL || IS_ERR(clk))
		return;

352
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
353
	list_del(&clk->node);
354
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
355 356 357
}
EXPORT_SYMBOL(clk_unregister);

358
void clk_deny_idle(struct clk *clk)
359
{
360 361
	unsigned long flags;

362 363 364
	if (clk == NULL || IS_ERR(clk))
		return;

365 366 367 368
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_deny_idle)
		arch_clock->clk_deny_idle(clk);
	spin_unlock_irqrestore(&clockfw_lock, flags);
369
}
370
EXPORT_SYMBOL(clk_deny_idle);
L
Linus Torvalds 已提交
371

372
void clk_allow_idle(struct clk *clk)
L
Linus Torvalds 已提交
373
{
374
	unsigned long flags;
L
Linus Torvalds 已提交
375

376 377 378
	if (clk == NULL || IS_ERR(clk))
		return;

379 380 381 382
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_allow_idle)
		arch_clock->clk_allow_idle(clk);
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
383
}
384
EXPORT_SYMBOL(clk_allow_idle);
385

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
void clk_enable_init_clocks(void)
{
	struct clk *clkp;

	list_for_each_entry(clkp, &clocks, node) {
		if (clkp->flags & ENABLE_ON_INIT)
			clk_enable(clkp);
	}
}
EXPORT_SYMBOL(clk_enable_init_clocks);

#ifdef CONFIG_CPU_FREQ
void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
{
	unsigned long flags;

	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_init_cpufreq_table)
		arch_clock->clk_init_cpufreq_table(table);
	spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_init_cpufreq_table);
#endif

410
/*-------------------------------------------------------------------------*/
411

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
#ifdef CONFIG_OMAP_RESET_CLOCKS
/*
 * Disable any unused clocks left on by the bootloader
 */
static int __init clk_disable_unused(void)
{
	struct clk *ck;
	unsigned long flags;

	list_for_each_entry(ck, &clocks, node) {
		if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
			ck->enable_reg == 0)
			continue;

		spin_lock_irqsave(&clockfw_lock, flags);
		if (arch_clock->clk_disable_unused)
			arch_clock->clk_disable_unused(ck);
		spin_unlock_irqrestore(&clockfw_lock, flags);
	}

	return 0;
}
late_initcall(clk_disable_unused);
#endif

437
int __init clk_init(struct clk_functions * custom_clocks)
438
{
439 440 441
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
442 443
	}

444 445
	arch_clock = custom_clocks;

446 447
	return 0;
}
448