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

	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
	return clk->parent;
L
Linus Torvalds 已提交
211
}
212
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
213

214 215 216
/*-------------------------------------------------------------------------
 * OMAP specific clock functions shared between omap1 and omap2
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
217

218
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
219

220 221 222 223 224
/*
 * 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 已提交
225
{
226
	get_option(&str, &mpurate);
L
Linus Torvalds 已提交
227

228 229
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
230

231 232
	if (mpurate < 1000)
		mpurate *= 1000000;
L
Linus Torvalds 已提交
233

234
	return 1;
L
Linus Torvalds 已提交
235
}
236
__setup("mpurate=", omap_clk_setup);
L
Linus Torvalds 已提交
237

238 239
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc(struct clk *clk)
L
Linus Torvalds 已提交
240
{
241 242 243
	if (clk == NULL || IS_ERR(clk))
		return;

244
	clk->rate = clk->parent->rate;
245 246
	if (unlikely(clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
L
Linus Torvalds 已提交
247 248
}

249 250
/* Propagate rate to children */
void propagate_rate(struct clk * tclk)
L
Linus Torvalds 已提交
251
{
252
	struct clk *clkp;
L
Linus Torvalds 已提交
253

254 255 256
	if (tclk == NULL || IS_ERR(tclk))
		return;

257 258 259 260 261 262
	list_for_each_entry(clkp, &clocks, node) {
		if (likely(clkp->parent != tclk))
			continue;
		if (likely((u32)clkp->recalc))
			clkp->recalc(clkp);
	}
L
Linus Torvalds 已提交
263 264
}

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
/**
 * 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 已提交
282 283
int clk_register(struct clk *clk)
{
284 285 286
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

287
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
288 289 290
	list_add(&clk->node, &clocks);
	if (clk->init)
		clk->init(clk);
291
	mutex_unlock(&clocks_mutex);
292

L
Linus Torvalds 已提交
293 294 295 296 297 298
	return 0;
}
EXPORT_SYMBOL(clk_register);

void clk_unregister(struct clk *clk)
{
299 300 301
	if (clk == NULL || IS_ERR(clk))
		return;

302
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
303
	list_del(&clk->node);
304
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
305 306 307
}
EXPORT_SYMBOL(clk_unregister);

308 309 310 311 312 313 314 315 316 317 318
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);

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
/*
 * 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,
};

336 337 338 339 340 341 342 343 344 345 346 347 348
#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

349
/*-------------------------------------------------------------------------*/
350

351 352 353 354 355 356 357 358 359 360
#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) {
361 362 363 364
		if (ck->ops == &clkops_null)
			continue;

		if (ck->usecount > 0 || ck->enable_reg == 0)
365 366 367 368 369 370 371 372 373 374 375 376 377
			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

378
int __init clk_init(struct clk_functions * custom_clocks)
379
{
380 381 382
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
383 384
	}

385 386
	arch_clock = custom_clocks;

387 388
	return 0;
}
389

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
#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);
408 409
	if (!d)
		return -ENOMEM;
410 411 412
	c->dent = d;

	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
413 414
	if (!d) {
		err = -ENOMEM;
415 416 417
		goto err_out;
	}
	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
418 419
	if (!d) {
		err = -ENOMEM;
420 421 422
		goto err_out;
	}
	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
423 424
	if (!d) {
		err = -ENOMEM;
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
		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);
463 464
	if (!d)
		return -ENOMEM;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
	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) */