clock.c 10.0 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
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_set_rate)
		ret = arch_clock->clk_set_rate(clk, rate);
185 186
	if (ret == 0 && (clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
187
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
188

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

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

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

201 202
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_set_parent)
203 204 205
		ret = arch_clock->clk_set_parent(clk, parent);
	if (ret == 0 && (clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
206
	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
	return clk->parent;
L
Linus Torvalds 已提交
215
}
216
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
217

218 219 220
/*-------------------------------------------------------------------------
 * OMAP specific clock functions shared between omap1 and omap2
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
221

222
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
223

224 225 226 227 228
/*
 * 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 已提交
229
{
230
	get_option(&str, &mpurate);
L
Linus Torvalds 已提交
231

232 233
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
234

235 236
	if (mpurate < 1000)
		mpurate *= 1000000;
L
Linus Torvalds 已提交
237

238
	return 1;
L
Linus Torvalds 已提交
239
}
240
__setup("mpurate=", omap_clk_setup);
L
Linus Torvalds 已提交
241

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

248
	clk->rate = clk->parent->rate;
249 250
	if (unlikely(clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
L
Linus Torvalds 已提交
251 252
}

253 254
/* Propagate rate to children */
void propagate_rate(struct clk * tclk)
L
Linus Torvalds 已提交
255
{
256
	struct clk *clkp;
L
Linus Torvalds 已提交
257

258 259 260
	if (tclk == NULL || IS_ERR(tclk))
		return;

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

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

291
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
292 293 294
	list_add(&clk->node, &clocks);
	if (clk->init)
		clk->init(clk);
295
	mutex_unlock(&clocks_mutex);
296

L
Linus Torvalds 已提交
297 298 299 300 301 302
	return 0;
}
EXPORT_SYMBOL(clk_register);

void clk_unregister(struct clk *clk)
{
303 304 305
	if (clk == NULL || IS_ERR(clk))
		return;

306
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
307
	list_del(&clk->node);
308
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
309 310 311
}
EXPORT_SYMBOL(clk_unregister);

312 313 314 315 316 317 318 319 320 321 322
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);

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
/*
 * 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,
};

340 341 342 343 344 345 346 347 348 349 350 351 352
#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

353
/*-------------------------------------------------------------------------*/
354

355 356 357 358 359 360 361 362 363 364
#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) {
365 366 367 368
		if (ck->ops == &clkops_null)
			continue;

		if (ck->usecount > 0 || ck->enable_reg == 0)
369 370 371 372 373 374 375 376 377 378 379 380 381
			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

382
int __init clk_init(struct clk_functions * custom_clocks)
383
{
384 385 386
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
387 388
	}

389 390
	arch_clock = custom_clocks;

391 392
	return 0;
}
393

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

	d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
417 418
	if (!d) {
		err = -ENOMEM;
419 420 421
		goto err_out;
	}
	d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
422 423
	if (!d) {
		err = -ENOMEM;
424 425 426
		goto err_out;
	}
	d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
427 428
	if (!d) {
		err = -ENOMEM;
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
		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);
467 468
	if (!d)
		return -ENOMEM;
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
	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) */