clock.c 9.4 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  linux/arch/arm/plat-omap/clock.c
L
Linus Torvalds 已提交
3
 *
4
 *  Copyright (C) 2004 - 2005 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
 * 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.
 */
13
#include <linux/version.h>
L
Linus Torvalds 已提交
14
#include <linux/kernel.h>
15 16
#include <linux/init.h>
#include <linux/module.h>
L
Linus Torvalds 已提交
17 18 19
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
T
Tim Schmielau 已提交
20
#include <linux/string.h>
21
#include <linux/clk.h>
22
#include <linux/mutex.h>
23
#include <linux/platform_device.h>
L
Linus Torvalds 已提交
24

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

27
#include <asm/arch/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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
#ifdef CONFIG_PM_DEBUG

static void print_parents(struct clk *clk)
{
	struct clk *p;
	int printed = 0;

	list_for_each_entry(p, &clocks, node) {
		if (p->parent == clk && p->usecount) {
			if (!clk->usecount && !printed) {
				printk("MISMATCH: %s\n", clk->name);
				printed = 1;
			}
			printk("\t%-15s\n", p->name);
		}
	}
}

void clk_print_usecounts(void)
{
	unsigned long flags;
	struct clk *p;

	spin_lock_irqsave(&clockfw_lock, flags);
	list_for_each_entry(p, &clocks, node) {
		if (p->usecount)
			printk("%-15s: %d\n", p->name, p->usecount);
		print_parents(p);

	}
	spin_unlock_irqrestore(&clockfw_lock, flags);
}

#endif

70
/*-------------------------------------------------------------------------
71
 * Standard clock functions defined in include/linux/clk.h
72
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
73

74 75 76 77
/*
 * 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.
 */
78
struct clk * clk_get(struct device *dev, const char *id)
L
Linus Torvalds 已提交
79 80
{
	struct clk *p, *clk = ERR_PTR(-ENOENT);
81 82 83 84 85 86
	int idno;

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

88
	mutex_lock(&clocks_mutex);
89 90 91 92 93

	list_for_each_entry(p, &clocks, node) {
		if (p->id == idno &&
		    strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
			clk = p;
94
			goto found;
95 96 97
		}
	}

L
Linus Torvalds 已提交
98 99 100 101 102 103
	list_for_each_entry(p, &clocks, node) {
		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
			clk = p;
			break;
		}
	}
104

105
found:
106
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
107 108 109 110 111 112 113 114

	return clk;
}
EXPORT_SYMBOL(clk_get);

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

117 118 119
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

L
Linus Torvalds 已提交
120
	spin_lock_irqsave(&clockfw_lock, flags);
121
	if (arch_clock->clk_enable)
122
		ret = arch_clock->clk_enable(clk);
L
Linus Torvalds 已提交
123
	spin_unlock_irqrestore(&clockfw_lock, flags);
124

L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132
	return ret;
}
EXPORT_SYMBOL(clk_enable);

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

133 134 135
	if (clk == NULL || IS_ERR(clk))
		return;

L
Linus Torvalds 已提交
136
	spin_lock_irqsave(&clockfw_lock, flags);
137 138 139 140 141 142 143
	if (clk->usecount == 0) {
		printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
		       clk->name);
		WARN_ON(1);
		goto out;
	}

144
	if (arch_clock->clk_disable)
145
		arch_clock->clk_disable(clk);
146 147

out:
L
Linus Torvalds 已提交
148 149 150 151 152 153
	spin_unlock_irqrestore(&clockfw_lock, flags);
}
EXPORT_SYMBOL(clk_disable);

int clk_get_usecount(struct clk *clk)
{
154 155
	unsigned long flags;
	int ret = 0;
L
Linus Torvalds 已提交
156

157 158 159
	if (clk == NULL || IS_ERR(clk))
		return 0;

160 161 162
	spin_lock_irqsave(&clockfw_lock, flags);
	ret = clk->usecount;
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
163

164
	return ret;
L
Linus Torvalds 已提交
165
}
166
EXPORT_SYMBOL(clk_get_usecount);
L
Linus Torvalds 已提交
167

168
unsigned long clk_get_rate(struct clk *clk)
L
Linus Torvalds 已提交
169
{
170 171
	unsigned long flags;
	unsigned long ret = 0;
L
Linus Torvalds 已提交
172

173 174 175
	if (clk == NULL || IS_ERR(clk))
		return 0;

176 177 178
	spin_lock_irqsave(&clockfw_lock, flags);
	ret = clk->rate;
	spin_unlock_irqrestore(&clockfw_lock, flags);
L
Linus Torvalds 已提交
179

180
	return ret;
L
Linus Torvalds 已提交
181
}
182
EXPORT_SYMBOL(clk_get_rate);
L
Linus Torvalds 已提交
183

184
void clk_put(struct clk *clk)
185
{
186 187
	if (clk && !IS_ERR(clk))
		module_put(clk->owner);
188
}
189
EXPORT_SYMBOL(clk_put);
190

191
/*-------------------------------------------------------------------------
192
 * Optional clock functions defined in include/linux/clk.h
193
 *-------------------------------------------------------------------------*/
194

L
Linus Torvalds 已提交
195 196
long clk_round_rate(struct clk *clk, unsigned long rate)
{
197 198
	unsigned long flags;
	long ret = 0;
L
Linus Torvalds 已提交
199

200 201 202
	if (clk == NULL || IS_ERR(clk))
		return ret;

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

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

212
int clk_set_rate(struct clk *clk, unsigned long rate)
L
Linus Torvalds 已提交
213
{
214
	unsigned long flags;
215 216 217 218
	int ret = -EINVAL;

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

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

225
	return ret;
L
Linus Torvalds 已提交
226
}
227
EXPORT_SYMBOL(clk_set_rate);
L
Linus Torvalds 已提交
228

229
int clk_set_parent(struct clk *clk, struct clk *parent)
L
Linus Torvalds 已提交
230
{
231
	unsigned long flags;
232 233 234 235
	int ret = -EINVAL;

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

237 238 239 240
	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 已提交
241

242
	return ret;
L
Linus Torvalds 已提交
243
}
244
EXPORT_SYMBOL(clk_set_parent);
L
Linus Torvalds 已提交
245

246
struct clk *clk_get_parent(struct clk *clk)
L
Linus Torvalds 已提交
247
{
248 249
	unsigned long flags;
	struct clk * ret = NULL;
L
Linus Torvalds 已提交
250

251 252 253
	if (clk == NULL || IS_ERR(clk))
		return ret;

254 255 256 257
	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 已提交
258 259 260

	return ret;
}
261
EXPORT_SYMBOL(clk_get_parent);
L
Linus Torvalds 已提交
262

263 264 265
/*-------------------------------------------------------------------------
 * OMAP specific clock functions shared between omap1 and omap2
 *-------------------------------------------------------------------------*/
L
Linus Torvalds 已提交
266

267
unsigned int __initdata mpurate;
L
Linus Torvalds 已提交
268

269 270 271 272 273
/*
 * 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 已提交
274
{
275
	get_option(&str, &mpurate);
L
Linus Torvalds 已提交
276

277 278
	if (!mpurate)
		return 1;
L
Linus Torvalds 已提交
279

280 281
	if (mpurate < 1000)
		mpurate *= 1000000;
L
Linus Torvalds 已提交
282

283
	return 1;
L
Linus Torvalds 已提交
284
}
285
__setup("mpurate=", omap_clk_setup);
L
Linus Torvalds 已提交
286

287 288
/* Used for clocks that always have same value as the parent clock */
void followparent_recalc(struct clk *clk)
L
Linus Torvalds 已提交
289
{
290 291 292
	if (clk == NULL || IS_ERR(clk))
		return;

293
	clk->rate = clk->parent->rate;
294 295
	if (unlikely(clk->flags & RATE_PROPAGATES))
		propagate_rate(clk);
L
Linus Torvalds 已提交
296 297
}

298 299
/* Propagate rate to children */
void propagate_rate(struct clk * tclk)
L
Linus Torvalds 已提交
300
{
301
	struct clk *clkp;
L
Linus Torvalds 已提交
302

303 304 305
	if (tclk == NULL || IS_ERR(tclk))
		return;

306 307 308 309 310 311
	list_for_each_entry(clkp, &clocks, node) {
		if (likely(clkp->parent != tclk))
			continue;
		if (likely((u32)clkp->recalc))
			clkp->recalc(clkp);
	}
L
Linus Torvalds 已提交
312 313
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
/**
 * 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 已提交
331 332
int clk_register(struct clk *clk)
{
333 334 335
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

336
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
337 338 339
	list_add(&clk->node, &clocks);
	if (clk->init)
		clk->init(clk);
340
	mutex_unlock(&clocks_mutex);
341

L
Linus Torvalds 已提交
342 343 344 345 346 347
	return 0;
}
EXPORT_SYMBOL(clk_register);

void clk_unregister(struct clk *clk)
{
348 349 350
	if (clk == NULL || IS_ERR(clk))
		return;

351
	mutex_lock(&clocks_mutex);
L
Linus Torvalds 已提交
352
	list_del(&clk->node);
353
	mutex_unlock(&clocks_mutex);
L
Linus Torvalds 已提交
354 355 356
}
EXPORT_SYMBOL(clk_unregister);

357
void clk_deny_idle(struct clk *clk)
358
{
359 360
	unsigned long flags;

361 362 363
	if (clk == NULL || IS_ERR(clk))
		return;

364 365 366 367
	spin_lock_irqsave(&clockfw_lock, flags);
	if (arch_clock->clk_deny_idle)
		arch_clock->clk_deny_idle(clk);
	spin_unlock_irqrestore(&clockfw_lock, flags);
368
}
369
EXPORT_SYMBOL(clk_deny_idle);
L
Linus Torvalds 已提交
370

371
void clk_allow_idle(struct clk *clk)
L
Linus Torvalds 已提交
372
{
373
	unsigned long flags;
L
Linus Torvalds 已提交
374

375 376 377
	if (clk == NULL || IS_ERR(clk))
		return;

378 379 380 381
	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 已提交
382
}
383
EXPORT_SYMBOL(clk_allow_idle);
384

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
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

409
/*-------------------------------------------------------------------------*/
410

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
#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

436
int __init clk_init(struct clk_functions * custom_clocks)
437
{
438 439 440
	if (!custom_clocks) {
		printk(KERN_ERR "No custom clock functions registered\n");
		BUG();
441 442
	}

443 444
	arch_clock = custom_clocks;

445 446
	return 0;
}
447