clock.c 10.1 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

	list_for_each_entry(p, &clocks, node) {
R
Russell King 已提交
56
		if (p->id == idno && strcmp(id, p->name) == 0) {
57
			clk = p;
58
			goto found;
59 60 61
		}
	}

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

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

	return clk;
}
EXPORT_SYMBOL(clk_get);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

148
void clk_put(struct clk *clk)
149 150
{
}
151
EXPORT_SYMBOL(clk_put);
152

153
/*-------------------------------------------------------------------------
154
 * Optional clock functions defined in include/linux/clk.h
155
 *-------------------------------------------------------------------------*/
156

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

162 163 164
	if (clk == NULL || IS_ERR(clk))
		return ret;

165 166 167 168
	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 已提交
169

170
	return ret;
L
Linus Torvalds 已提交
171 172 173
}
EXPORT_SYMBOL(clk_round_rate);

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

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

182 183 184 185
	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 已提交
186

187
	return ret;
L
Linus Torvalds 已提交
188
}
189
EXPORT_SYMBOL(clk_set_rate);
L
Linus Torvalds 已提交
190

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

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

199 200 201 202
	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 已提交
203

204
	return ret;
L
Linus Torvalds 已提交
205
}
206
EXPORT_SYMBOL(clk_set_parent);
L
Linus Torvalds 已提交
207

208
struct clk *clk_get_parent(struct clk *clk)
L
Linus Torvalds 已提交
209
{
210 211
	unsigned long flags;
	struct clk * ret = NULL;
L
Linus Torvalds 已提交
212

213 214 215
	if (clk == NULL || IS_ERR(clk))
		return ret;

216 217 218 219
	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 已提交
220 221 222

	return ret;
}
223
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
224

225 226 227
/*-------------------------------------------------------------------------
 * OMAP specific clock functions shared between omap1 and omap2
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
228

229
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
230

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

239 240
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
241

242 243
	if (mpurate < 1000)
		mpurate *= 1000000;
L
Linus Torvalds 已提交
244

245
	return 1;
L
Linus Torvalds 已提交
246
}
247
__setup("mpurate=", omap_clk_setup);
L
Linus Torvalds 已提交
248

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

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

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

265 266 267
	if (tclk == NULL || IS_ERR(tclk))
		return;

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

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

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

L
Linus Torvalds 已提交
304 305 306 307 308 309
	return 0;
}
EXPORT_SYMBOL(clk_register);

void clk_unregister(struct clk *clk)
{
310 311 312
	if (clk == NULL || IS_ERR(clk))
		return;

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

319 320 321 322 323 324 325 326 327 328 329
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);

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
/*
 * 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,
};

347 348 349 350 351 352 353 354 355 356 357 358 359
#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

360
/*-------------------------------------------------------------------------*/
361

362 363 364 365 366 367 368 369 370 371
#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) {
372 373 374 375
		if (ck->ops == &clkops_null)
			continue;

		if (ck->usecount > 0 || ck->enable_reg == 0)
376 377 378 379 380 381 382 383 384 385 386 387 388
			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

389
int __init clk_init(struct clk_functions * custom_clocks)
390
{
391 392 393
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
394 395
	}

396 397
	arch_clock = custom_clocks;

398 399
	return 0;
}
400

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
#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);
419 420
	if (!d)
		return -ENOMEM;
421 422 423
	c->dent = d;

	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
424 425
	if (!d) {
		err = -ENOMEM;
426 427 428
		goto err_out;
	}
	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
429 430
	if (!d) {
		err = -ENOMEM;
431 432 433
		goto err_out;
	}
	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
434 435
	if (!d) {
		err = -ENOMEM;
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
		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);
474 475
	if (!d)
		return -ENOMEM;
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
	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) */