clock.c 10.8 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 13
 * 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.
 */
#include <linux/kernel.h>
14 15
#include <linux/init.h>
#include <linux/module.h>
L
Linus Torvalds 已提交
16 17 18
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
T
Tim Schmielau 已提交
19
#include <linux/string.h>
20
#include <linux/clk.h>
21
#include <linux/mutex.h>
22
#include <linux/platform_device.h>
23
#include <linux/cpufreq.h>
24
#include <linux/debugfs.h>
25
#include <linux/io.h>
L
Linus Torvalds 已提交
26

27
#include <mach/clock.h>
L
Linus Torvalds 已提交
28

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

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

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

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

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

53
	mutex_lock(&clocks_mutex);
54 55 56 57 58

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

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

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

	return clk;
}
EXPORT_SYMBOL(clk_get);

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

82 83 84
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

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

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

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

98 99 100
	if (clk == NULL || IS_ERR(clk))
		return;

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

109
	if (arch_clock->clk_disable)
110
		arch_clock->clk_disable(clk);
111 112

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

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

122 123 124
	if (clk == NULL || IS_ERR(clk))
		return 0;

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

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

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

138 139 140
	if (clk == NULL || IS_ERR(clk))
		return 0;

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

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

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

156
/*-------------------------------------------------------------------------
157
 * Optional clock functions defined in include/linux/clk.h
158
 *-------------------------------------------------------------------------*/
159

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

165 166 167
	if (clk == NULL || IS_ERR(clk))
		return ret;

168 169 170 171
	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 已提交
172

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

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

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

185 186 187 188
	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 已提交
189

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

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

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

202 203 204 205
	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 已提交
206

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

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

216 217 218
	if (clk == NULL || IS_ERR(clk))
		return ret;

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

	return ret;
}
226
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
227

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

232
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
233

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

242 243
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
244

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

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

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

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

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

268 269 270
	if (tclk == NULL || IS_ERR(tclk))
		return;

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

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

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

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

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

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

322
void clk_deny_idle(struct clk *clk)
323
{
324 325
	unsigned long flags;

326 327 328
	if (clk == NULL || IS_ERR(clk))
		return;

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

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

340 341 342
	if (clk == NULL || IS_ERR(clk))
		return;

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

350 351 352 353 354 355 356 357 358 359 360
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);

361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
/*
 * Low level helpers
 */
static int clkll_enable_null(struct clk *clk)
{
	return 0;
}

static void clkll_disable_null(struct clk *clk)
{
}

const struct clkops clkops_null = {
	.enable		= clkll_enable_null,
	.disable	= clkll_disable_null,
};

378 379 380 381 382 383 384 385 386 387 388 389 390
#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

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) {
403 404 405 406
		if (ck->ops == &clkops_null)
			continue;

		if (ck->usecount > 0 || ck->enable_reg == 0)
407 408 409 410 411 412 413 414 415 416 417 418 419
			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

420
int __init clk_init(struct clk_functions * custom_clocks)
421
{
422 423 424
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
425 426
	}

427 428
	arch_clock = custom_clocks;

429 430
	return 0;
}
431

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
#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);
450 451
	if (!d)
		return -ENOMEM;
452 453 454
	c->dent = d;

	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
455 456
	if (!d) {
		err = -ENOMEM;
457 458 459
		goto err_out;
	}
	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
460 461
	if (!d) {
		err = -ENOMEM;
462 463 464
		goto err_out;
	}
	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
465 466
	if (!d) {
		err = -ENOMEM;
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
		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);
505 506
	if (!d)
		return -ENOMEM;
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
	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) */