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 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>
L
Linus Torvalds 已提交
25

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

28
#include <mach/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
 * Standard clock functions defined in include/linux/clk.h
38
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
39

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

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

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

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

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

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

	return clk;
}
EXPORT_SYMBOL(clk_get);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

375
/*-------------------------------------------------------------------------*/
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
#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

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

409 410
	arch_clock = custom_clocks;

411 412
	return 0;
}
413

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
#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) */