clock.c 10.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  linux/arch/arm/plat-omap/clock.c
L
Linus Torvalds 已提交
3
 *
4
 *  Copyright (C) 2004 - 2008 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>
25
#include <linux/debugfs.h>
L
Linus Torvalds 已提交
26

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

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

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

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

37
/*-------------------------------------------------------------------------
38
 * Standard clock functions defined in include/linux/clk.h
39
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
40

41 42 43 44
/*
 * 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.
 */
45
struct clk * clk_get(struct device *dev, const char *id)
L
Linus Torvalds 已提交
46 47
{
	struct clk *p, *clk = ERR_PTR(-ENOENT);
48 49 50 51 52 53
	int idno;

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

55
	mutex_lock(&clocks_mutex);
56 57 58 59 60

	list_for_each_entry(p, &clocks, node) {
		if (p->id == idno &&
		    strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
			clk = p;
61
			goto found;
62 63 64
		}
	}

L
Linus Torvalds 已提交
65 66 67 68 69 70
	list_for_each_entry(p, &clocks, node) {
		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
			clk = p;
			break;
		}
	}
71

72
found:
73
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
74 75 76 77 78 79 80 81

	return clk;
}
EXPORT_SYMBOL(clk_get);

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

84 85 86
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

L
Linus Torvalds 已提交
87
	spin_lock_irqsave(&clockfw_lock, flags);
88
	if (arch_clock->clk_enable)
89
		ret = arch_clock->clk_enable(clk);
L
Linus Torvalds 已提交
90
	spin_unlock_irqrestore(&clockfw_lock, flags);
91

L
Linus Torvalds 已提交
92 93 94 95 96 97 98 99
	return ret;
}
EXPORT_SYMBOL(clk_enable);

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

100 101 102
	if (clk == NULL || IS_ERR(clk))
		return;

L
Linus Torvalds 已提交
103
	spin_lock_irqsave(&clockfw_lock, flags);
104 105 106 107 108 109 110
	if (clk->usecount == 0) {
		printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
		       clk->name);
		WARN_ON(1);
		goto out;
	}

111
	if (arch_clock->clk_disable)
112
		arch_clock->clk_disable(clk);
113 114

out:
L
Linus Torvalds 已提交
115 116 117 118 119 120
	spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_disable);

int clk_get_usecount(struct clk *clk)
{
121 122
	unsigned long flags;
	int ret = 0;
L
Linus Torvalds 已提交
123

124 125 126
	if (clk == NULL || IS_ERR(clk))
		return 0;

127 128 129
	spin_lock_irqsave(&clockfw_lock, flags);
	ret = clk->usecount;
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
130

131
	return ret;
L
Linus Torvalds 已提交
132
}
133
EXPORT_SYMBOL(clk_get_usecount);
L
Linus Torvalds 已提交
134

135
unsigned long clk_get_rate(struct clk *clk)
L
Linus Torvalds 已提交
136
{
137 138
	unsigned long flags;
	unsigned long ret = 0;
L
Linus Torvalds 已提交
139

140 141 142
	if (clk == NULL || IS_ERR(clk))
		return 0;

143 144 145
	spin_lock_irqsave(&clockfw_lock, flags);
	ret = clk->rate;
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
146

147
	return ret;
L
Linus Torvalds 已提交
148
}
149
EXPORT_SYMBOL(clk_get_rate);
L
Linus Torvalds 已提交
150

151
void clk_put(struct clk *clk)
152
{
153 154
	if (clk && !IS_ERR(clk))
		module_put(clk->owner);
155
}
156
EXPORT_SYMBOL(clk_put);
157

158
/*-------------------------------------------------------------------------
159
 * Optional clock functions defined in include/linux/clk.h
160
 *-------------------------------------------------------------------------*/
161

L
Linus Torvalds 已提交
162 163
long clk_round_rate(struct clk *clk, unsigned long rate)
{
164 165
	unsigned long flags;
	long ret = 0;
L
Linus Torvalds 已提交
166

167 168 169
	if (clk == NULL || IS_ERR(clk))
		return ret;

170 171 172 173
	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 已提交
174

175
	return ret;
L
Linus Torvalds 已提交
176 177 178
}
EXPORT_SYMBOL(clk_round_rate);

179
int clk_set_rate(struct clk *clk, unsigned long rate)
L
Linus Torvalds 已提交
180
{
181
	unsigned long flags;
182 183 184 185
	int ret = -EINVAL;

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

187 188 189 190
	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 已提交
191

192
	return ret;
L
Linus Torvalds 已提交
193
}
194
EXPORT_SYMBOL(clk_set_rate);
L
Linus Torvalds 已提交
195

196
int clk_set_parent(struct clk *clk, struct clk *parent)
L
Linus Torvalds 已提交
197
{
198
	unsigned long flags;
199 200 201 202
	int ret = -EINVAL;

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

204 205 206 207
	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 已提交
208

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

213
struct clk *clk_get_parent(struct clk *clk)
L
Linus Torvalds 已提交
214
{
215 216
	unsigned long flags;
	struct clk * ret = NULL;
L
Linus Torvalds 已提交
217

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

221 222 223 224
	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 已提交
225 226 227

	return ret;
}
228
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
229

230 231 232
/*-------------------------------------------------------------------------
 * OMAP specific clock functions shared between omap1 and omap2
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
233

234
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
235

236 237 238 239 240
/*
 * 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 已提交
241
{
242
	get_option(&str, &mpurate);
L
Linus Torvalds 已提交
243

244 245
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
246

247 248
	if (mpurate < 1000)
		mpurate *= 1000000;
L
Linus Torvalds 已提交
249

250
	return 1;
L
Linus Torvalds 已提交
251
}
252
__setup("mpurate=", omap_clk_setup);
L
Linus Torvalds 已提交
253

254 255
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc(struct clk *clk)
L
Linus Torvalds 已提交
256
{
257 258 259
	if (clk == NULL || IS_ERR(clk))
		return;

260
	clk->rate = clk->parent->rate;
261 262
	if (unlikely(clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
L
Linus Torvalds 已提交
263 264
}

265 266
/* Propagate rate to children */
void propagate_rate(struct clk * tclk)
L
Linus Torvalds 已提交
267
{
268
	struct clk *clkp;
L
Linus Torvalds 已提交
269

270 271 272
	if (tclk == NULL || IS_ERR(tclk))
		return;

273 274 275 276 277 278
	list_for_each_entry(clkp, &clocks, node) {
		if (likely(clkp->parent != tclk))
			continue;
		if (likely((u32)clkp->recalc))
			clkp->recalc(clkp);
	}
L
Linus Torvalds 已提交
279 280
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
/**
 * 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 已提交
298 299
int clk_register(struct clk *clk)
{
300 301 302
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

303
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
304 305 306
	list_add(&clk->node, &clocks);
	if (clk->init)
		clk->init(clk);
307
	mutex_unlock(&clocks_mutex);
308

L
Linus Torvalds 已提交
309 310 311 312 313 314
	return 0;
}
EXPORT_SYMBOL(clk_register);

void clk_unregister(struct clk *clk)
{
315 316 317
	if (clk == NULL || IS_ERR(clk))
		return;

318
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
319
	list_del(&clk->node);
320
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
321 322 323
}
EXPORT_SYMBOL(clk_unregister);

324
void clk_deny_idle(struct clk *clk)
325
{
326 327
	unsigned long flags;

328 329 330
	if (clk == NULL || IS_ERR(clk))
		return;

331 332 333 334
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_deny_idle)
		arch_clock->clk_deny_idle(clk);
	spin_unlock_irqrestore(&clockfw_lock, flags);
335
}
336
EXPORT_SYMBOL(clk_deny_idle);
L
Linus Torvalds 已提交
337

338
void clk_allow_idle(struct clk *clk)
L
Linus Torvalds 已提交
339
{
340
	unsigned long flags;
L
Linus Torvalds 已提交
341

342 343 344
	if (clk == NULL || IS_ERR(clk))
		return;

345 346 347 348
	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 已提交
349
}
350
EXPORT_SYMBOL(clk_allow_idle);
351

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
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

376
/*-------------------------------------------------------------------------*/
377

378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
#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

403
int __init clk_init(struct clk_functions * custom_clocks)
404
{
405 406 407
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
408 409
	}

410 411
	arch_clock = custom_clocks;

412 413
	return 0;
}
414

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
/*
 *	debugfs support to trace clock tree hierarchy and attributes
 */
static struct dentry *clk_debugfs_root;

static int clk_debugfs_register_one(struct clk *c)
{
	int err;
	struct dentry *d, *child;
	struct clk *pa = c->parent;
	char s[255];
	char *p = s;

	p += sprintf(p, "%s", c->name);
	if (c->id != 0)
		sprintf(p, ":%d", c->id);
	d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
	if (IS_ERR(d))
		return PTR_ERR(d);
	c->dent = d;

	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
	if (IS_ERR(d)) {
		err = PTR_ERR(d);
		goto err_out;
	}
	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
	if (IS_ERR(d)) {
		err = PTR_ERR(d);
		goto err_out;
	}
	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
	if (IS_ERR(d)) {
		err = PTR_ERR(d);
		goto err_out;
	}
	return 0;

err_out:
	d = c->dent;
	list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
		debugfs_remove(child);
	debugfs_remove(c->dent);
	return err;
}

static int clk_debugfs_register(struct clk *c)
{
	int err;
	struct clk *pa = c->parent;

	if (pa && !pa->dent) {
		err = clk_debugfs_register(pa);
		if (err)
			return err;
	}

	if (!c->dent) {
		err = clk_debugfs_register_one(c);
		if (err)
			return err;
	}
	return 0;
}

static int __init clk_debugfs_init(void)
{
	struct clk *c;
	struct dentry *d;
	int err;

	d = debugfs_create_dir("clock", NULL);
	if (IS_ERR(d))
		return PTR_ERR(d);
	clk_debugfs_root = d;

	list_for_each_entry(c, &clocks, node) {
		err = clk_debugfs_register(c);
		if (err)
			goto err_out;
	}
	return 0;
err_out:
	debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
	return err;
}
late_initcall(clk_debugfs_init);

#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */