brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 7a73f5e Raw
625 lines · c
1/*2 * SuperH clock framework3 *4 *  Copyright (C) 2005 - 2010  Paul Mundt5 *6 * This clock framework is derived from the OMAP version by:7 *8 *	Copyright (C) 2004 - 2008 Nokia Corporation9 *	Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>10 *11 *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>12 *13 * This file is subject to the terms and conditions of the GNU General Public14 * License.  See the file "COPYING" in the main directory of this archive15 * for more details.16 */17#define pr_fmt(fmt) "clock: " fmt18 19#include <linux/kernel.h>20#include <linux/init.h>21#include <linux/module.h>22#include <linux/mutex.h>23#include <linux/list.h>24#include <linux/syscore_ops.h>25#include <linux/seq_file.h>26#include <linux/err.h>27#include <linux/io.h>28#include <linux/cpufreq.h>29#include <linux/clk.h>30#include <linux/sh_clk.h>31 32static LIST_HEAD(clock_list);33static DEFINE_SPINLOCK(clock_lock);34static DEFINE_MUTEX(clock_list_sem);35 36/* clock disable operations are not passed on to hardware during boot */37static int allow_disable;38 39void clk_rate_table_build(struct clk *clk,40			  struct cpufreq_frequency_table *freq_table,41			  int nr_freqs,42			  struct clk_div_mult_table *src_table,43			  unsigned long *bitmap)44{45	unsigned long mult, div;46	unsigned long freq;47	int i;48 49	clk->nr_freqs = nr_freqs;50 51	for (i = 0; i < nr_freqs; i++) {52		div = 1;53		mult = 1;54 55		if (src_table->divisors && i < src_table->nr_divisors)56			div = src_table->divisors[i];57 58		if (src_table->multipliers && i < src_table->nr_multipliers)59			mult = src_table->multipliers[i];60 61		if (!div || !mult || (bitmap && !test_bit(i, bitmap)))62			freq = CPUFREQ_ENTRY_INVALID;63		else64			freq = clk->parent->rate * mult / div;65 66		freq_table[i].driver_data = i;67		freq_table[i].frequency = freq;68	}69 70	/* Termination entry */71	freq_table[i].driver_data = i;72	freq_table[i].frequency = CPUFREQ_TABLE_END;73}74 75struct clk_rate_round_data;76 77struct clk_rate_round_data {78	unsigned long rate;79	unsigned int min, max;80	long (*func)(unsigned int, struct clk_rate_round_data *);81	void *arg;82};83 84#define for_each_frequency(pos, r, freq)			\85	for (pos = r->min, freq = r->func(pos, r);		\86	     pos <= r->max; pos++, freq = r->func(pos, r))	\87		if (unlikely(freq == 0))			\88			;					\89		else90 91static long clk_rate_round_helper(struct clk_rate_round_data *rounder)92{93	unsigned long rate_error, rate_error_prev = ~0UL;94	unsigned long highest, lowest, freq;95	long rate_best_fit = -ENOENT;96	int i;97 98	highest = 0;99	lowest = ~0UL;100 101	for_each_frequency(i, rounder, freq) {102		if (freq > highest)103			highest = freq;104		if (freq < lowest)105			lowest = freq;106 107		rate_error = abs(freq - rounder->rate);108		if (rate_error < rate_error_prev) {109			rate_best_fit = freq;110			rate_error_prev = rate_error;111		}112 113		if (rate_error == 0)114			break;115	}116 117	if (rounder->rate >= highest)118		rate_best_fit = highest;119	if (rounder->rate <= lowest)120		rate_best_fit = lowest;121 122	return rate_best_fit;123}124 125static long clk_rate_table_iter(unsigned int pos,126				struct clk_rate_round_data *rounder)127{128	struct cpufreq_frequency_table *freq_table = rounder->arg;129	unsigned long freq = freq_table[pos].frequency;130 131	if (freq == CPUFREQ_ENTRY_INVALID)132		freq = 0;133 134	return freq;135}136 137long clk_rate_table_round(struct clk *clk,138			  struct cpufreq_frequency_table *freq_table,139			  unsigned long rate)140{141	struct clk_rate_round_data table_round = {142		.min	= 0,143		.max	= clk->nr_freqs - 1,144		.func	= clk_rate_table_iter,145		.arg	= freq_table,146		.rate	= rate,147	};148 149	if (clk->nr_freqs < 1)150		return -ENOSYS;151 152	return clk_rate_round_helper(&table_round);153}154 155static long clk_rate_div_range_iter(unsigned int pos,156				    struct clk_rate_round_data *rounder)157{158	return clk_get_rate(rounder->arg) / pos;159}160 161long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,162			      unsigned int div_max, unsigned long rate)163{164	struct clk_rate_round_data div_range_round = {165		.min	= div_min,166		.max	= div_max,167		.func	= clk_rate_div_range_iter,168		.arg	= clk_get_parent(clk),169		.rate	= rate,170	};171 172	return clk_rate_round_helper(&div_range_round);173}174 175static long clk_rate_mult_range_iter(unsigned int pos,176				      struct clk_rate_round_data *rounder)177{178	return clk_get_rate(rounder->arg) * pos;179}180 181long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min,182			       unsigned int mult_max, unsigned long rate)183{184	struct clk_rate_round_data mult_range_round = {185		.min	= mult_min,186		.max	= mult_max,187		.func	= clk_rate_mult_range_iter,188		.arg	= clk_get_parent(clk),189		.rate	= rate,190	};191 192	return clk_rate_round_helper(&mult_range_round);193}194 195int clk_rate_table_find(struct clk *clk,196			struct cpufreq_frequency_table *freq_table,197			unsigned long rate)198{199	struct cpufreq_frequency_table *pos;200	int idx;201 202	cpufreq_for_each_valid_entry_idx(pos, freq_table, idx)203		if (pos->frequency == rate)204			return idx;205 206	return -ENOENT;207}208 209/* Used for clocks that always have same value as the parent clock */210unsigned long followparent_recalc(struct clk *clk)211{212	return clk->parent ? clk->parent->rate : 0;213}214 215int clk_reparent(struct clk *child, struct clk *parent)216{217	list_del_init(&child->sibling);218	if (parent)219		list_add(&child->sibling, &parent->children);220	child->parent = parent;221 222	return 0;223}224 225/* Propagate rate to children */226void propagate_rate(struct clk *tclk)227{228	struct clk *clkp;229 230	list_for_each_entry(clkp, &tclk->children, sibling) {231		if (clkp->ops && clkp->ops->recalc)232			clkp->rate = clkp->ops->recalc(clkp);233 234		propagate_rate(clkp);235	}236}237 238static void __clk_disable(struct clk *clk)239{240	if (WARN(!clk->usecount, "Trying to disable clock %p with 0 usecount\n",241		 clk))242		return;243 244	if (!(--clk->usecount)) {245		if (likely(allow_disable && clk->ops && clk->ops->disable))246			clk->ops->disable(clk);247		if (likely(clk->parent))248			__clk_disable(clk->parent);249	}250}251 252void clk_disable(struct clk *clk)253{254	unsigned long flags;255 256	if (!clk)257		return;258 259	spin_lock_irqsave(&clock_lock, flags);260	__clk_disable(clk);261	spin_unlock_irqrestore(&clock_lock, flags);262}263EXPORT_SYMBOL_GPL(clk_disable);264 265static int __clk_enable(struct clk *clk)266{267	int ret = 0;268 269	if (clk->usecount++ == 0) {270		if (clk->parent) {271			ret = __clk_enable(clk->parent);272			if (unlikely(ret))273				goto err;274		}275 276		if (clk->ops && clk->ops->enable) {277			ret = clk->ops->enable(clk);278			if (ret) {279				if (clk->parent)280					__clk_disable(clk->parent);281				goto err;282			}283		}284	}285 286	return ret;287err:288	clk->usecount--;289	return ret;290}291 292int clk_enable(struct clk *clk)293{294	unsigned long flags;295	int ret;296 297	if (!clk)298		return 0;299 300	spin_lock_irqsave(&clock_lock, flags);301	ret = __clk_enable(clk);302	spin_unlock_irqrestore(&clock_lock, flags);303 304	return ret;305}306EXPORT_SYMBOL_GPL(clk_enable);307 308static LIST_HEAD(root_clks);309 310/**311 * recalculate_root_clocks - recalculate and propagate all root clocks312 *313 * Recalculates all root clocks (clocks with no parent), which if the314 * clock's .recalc is set correctly, should also propagate their rates.315 * Called at init.316 */317void recalculate_root_clocks(void)318{319	struct clk *clkp;320 321	list_for_each_entry(clkp, &root_clks, sibling) {322		if (clkp->ops && clkp->ops->recalc)323			clkp->rate = clkp->ops->recalc(clkp);324		propagate_rate(clkp);325	}326}327 328static struct clk_mapping dummy_mapping;329 330static struct clk *lookup_root_clock(struct clk *clk)331{332	while (clk->parent)333		clk = clk->parent;334 335	return clk;336}337 338static int clk_establish_mapping(struct clk *clk)339{340	struct clk_mapping *mapping = clk->mapping;341 342	/*343	 * Propagate mappings.344	 */345	if (!mapping) {346		struct clk *clkp;347 348		/*349		 * dummy mapping for root clocks with no specified ranges350		 */351		if (!clk->parent) {352			clk->mapping = &dummy_mapping;353			goto out;354		}355 356		/*357		 * If we're on a child clock and it provides no mapping of its358		 * own, inherit the mapping from its root clock.359		 */360		clkp = lookup_root_clock(clk);361		mapping = clkp->mapping;362		BUG_ON(!mapping);363	}364 365	/*366	 * Establish initial mapping.367	 */368	if (!mapping->base && mapping->phys) {369		kref_init(&mapping->ref);370 371		mapping->base = ioremap(mapping->phys, mapping->len);372		if (unlikely(!mapping->base))373			return -ENXIO;374	} else if (mapping->base) {375		/*376		 * Bump the refcount for an existing mapping377		 */378		kref_get(&mapping->ref);379	}380 381	clk->mapping = mapping;382out:383	clk->mapped_reg = clk->mapping->base;384	clk->mapped_reg += (phys_addr_t)clk->enable_reg - clk->mapping->phys;385	return 0;386}387 388static void clk_destroy_mapping(struct kref *kref)389{390	struct clk_mapping *mapping;391 392	mapping = container_of(kref, struct clk_mapping, ref);393 394	iounmap(mapping->base);395}396 397static void clk_teardown_mapping(struct clk *clk)398{399	struct clk_mapping *mapping = clk->mapping;400 401	/* Nothing to do */402	if (mapping == &dummy_mapping)403		goto out;404 405	kref_put(&mapping->ref, clk_destroy_mapping);406	clk->mapping = NULL;407out:408	clk->mapped_reg = NULL;409}410 411int clk_register(struct clk *clk)412{413	int ret;414 415	if (IS_ERR_OR_NULL(clk))416		return -EINVAL;417 418	/*419	 * trap out already registered clocks420	 */421	if (clk->node.next || clk->node.prev)422		return 0;423 424	mutex_lock(&clock_list_sem);425 426	INIT_LIST_HEAD(&clk->children);427	clk->usecount = 0;428 429	ret = clk_establish_mapping(clk);430	if (unlikely(ret))431		goto out_unlock;432 433	if (clk->parent)434		list_add(&clk->sibling, &clk->parent->children);435	else436		list_add(&clk->sibling, &root_clks);437 438	list_add(&clk->node, &clock_list);439 440#ifdef CONFIG_SH_CLK_CPG_LEGACY441	if (clk->ops && clk->ops->init)442		clk->ops->init(clk);443#endif444 445out_unlock:446	mutex_unlock(&clock_list_sem);447 448	return ret;449}450EXPORT_SYMBOL_GPL(clk_register);451 452void clk_unregister(struct clk *clk)453{454	mutex_lock(&clock_list_sem);455	list_del(&clk->sibling);456	list_del(&clk->node);457	clk_teardown_mapping(clk);458	mutex_unlock(&clock_list_sem);459}460EXPORT_SYMBOL_GPL(clk_unregister);461 462void clk_enable_init_clocks(void)463{464	struct clk *clkp;465 466	list_for_each_entry(clkp, &clock_list, node)467		if (clkp->flags & CLK_ENABLE_ON_INIT)468			clk_enable(clkp);469}470 471unsigned long clk_get_rate(struct clk *clk)472{473	if (!clk)474		return 0;475 476	return clk->rate;477}478EXPORT_SYMBOL_GPL(clk_get_rate);479 480int clk_set_rate(struct clk *clk, unsigned long rate)481{482	int ret = -EOPNOTSUPP;483	unsigned long flags;484 485	if (!clk)486		return 0;487 488	spin_lock_irqsave(&clock_lock, flags);489 490	if (likely(clk->ops && clk->ops->set_rate)) {491		ret = clk->ops->set_rate(clk, rate);492		if (ret != 0)493			goto out_unlock;494	} else {495		clk->rate = rate;496		ret = 0;497	}498 499	if (clk->ops && clk->ops->recalc)500		clk->rate = clk->ops->recalc(clk);501 502	propagate_rate(clk);503 504out_unlock:505	spin_unlock_irqrestore(&clock_lock, flags);506 507	return ret;508}509EXPORT_SYMBOL_GPL(clk_set_rate);510 511int clk_set_parent(struct clk *clk, struct clk *parent)512{513	unsigned long flags;514	int ret = -EINVAL;515 516	if (!parent || !clk)517		return ret;518	if (clk->parent == parent)519		return 0;520 521	spin_lock_irqsave(&clock_lock, flags);522	if (clk->usecount == 0) {523		if (clk->ops->set_parent)524			ret = clk->ops->set_parent(clk, parent);525		else526			ret = clk_reparent(clk, parent);527 528		if (ret == 0) {529			if (clk->ops->recalc)530				clk->rate = clk->ops->recalc(clk);531			pr_debug("set parent of %p to %p (new rate %ld)\n",532				 clk, clk->parent, clk->rate);533			propagate_rate(clk);534		}535	} else536		ret = -EBUSY;537	spin_unlock_irqrestore(&clock_lock, flags);538 539	return ret;540}541EXPORT_SYMBOL_GPL(clk_set_parent);542 543struct clk *clk_get_parent(struct clk *clk)544{545	if (!clk)546		return NULL;547 548	return clk->parent;549}550EXPORT_SYMBOL_GPL(clk_get_parent);551 552long clk_round_rate(struct clk *clk, unsigned long rate)553{554	if (!clk)555		return 0;556 557	if (likely(clk->ops && clk->ops->round_rate)) {558		unsigned long flags, rounded;559 560		spin_lock_irqsave(&clock_lock, flags);561		rounded = clk->ops->round_rate(clk, rate);562		spin_unlock_irqrestore(&clock_lock, flags);563 564		return rounded;565	}566 567	return clk_get_rate(clk);568}569EXPORT_SYMBOL_GPL(clk_round_rate);570 571#ifdef CONFIG_PM572static void clks_core_resume(void)573{574	struct clk *clkp;575 576	list_for_each_entry(clkp, &clock_list, node) {577		if (likely(clkp->usecount && clkp->ops)) {578			unsigned long rate = clkp->rate;579 580			if (likely(clkp->ops->set_parent))581				clkp->ops->set_parent(clkp,582					clkp->parent);583			if (likely(clkp->ops->set_rate))584				clkp->ops->set_rate(clkp, rate);585			else if (likely(clkp->ops->recalc))586				clkp->rate = clkp->ops->recalc(clkp);587		}588	}589}590 591static struct syscore_ops clks_syscore_ops = {592	.resume = clks_core_resume,593};594 595static int __init clk_syscore_init(void)596{597	register_syscore_ops(&clks_syscore_ops);598 599	return 0;600}601subsys_initcall(clk_syscore_init);602#endif603 604static int __init clk_late_init(void)605{606	unsigned long flags;607	struct clk *clk;608 609	/* disable all clocks with zero use count */610	mutex_lock(&clock_list_sem);611	spin_lock_irqsave(&clock_lock, flags);612 613	list_for_each_entry(clk, &clock_list, node)614		if (!clk->usecount && clk->ops && clk->ops->disable)615			clk->ops->disable(clk);616 617	/* from now on allow clock disable operations */618	allow_disable = 1;619 620	spin_unlock_irqrestore(&clock_lock, flags);621	mutex_unlock(&clock_list_sem);622	return 0;623}624late_initcall(clk_late_init);625