/* * SuperH clock framework * * Copyright (C) 2005 - 2010 Paul Mundt * * This clock framework is derived from the OMAP version by: * * Copyright (C) 2004 - 2008 Nokia Corporation * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> * * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details.
*/ #define pr_fmt(fmt) "clock: " fmt
int clk_rate_table_find(struct clk *clk, struct cpufreq_frequency_table *freq_table, unsignedlong rate)
{ struct cpufreq_frequency_table *pos; int idx;
cpufreq_for_each_valid_entry_idx(pos, freq_table, idx) if (pos->frequency == rate) return idx;
return -ENOENT;
}
/* Used for clocks that always have same value as the parent clock */ unsignedlong followparent_recalc(struct clk *clk)
{ return clk->parent ? clk->parent->rate : 0;
}
int clk_reparent(struct clk *child, struct clk *parent)
{
list_del_init(&child->sibling); if (parent)
list_add(&child->sibling, &parent->children);
child->parent = parent;
return 0;
}
/* Propagate rate to children */ void propagate_rate(struct clk *tclk)
{ struct clk *clkp;
staticvoid __clk_disable(struct clk *clk)
{ if (WARN(!clk->usecount, "Trying to disable clock %p with 0 usecount\n",
clk)) return;
if (!(--clk->usecount)) { if (likely(allow_disable && clk->ops && clk->ops->disable))
clk->ops->disable(clk); if (likely(clk->parent))
__clk_disable(clk->parent);
}
}
staticint __clk_enable(struct clk *clk)
{ int ret = 0;
if (clk->usecount++ == 0) { if (clk->parent) {
ret = __clk_enable(clk->parent); if (unlikely(ret)) goto err;
}
if (clk->ops && clk->ops->enable) {
ret = clk->ops->enable(clk); if (ret) { if (clk->parent)
__clk_disable(clk->parent); goto err;
}
}
}
return ret;
err:
clk->usecount--; return ret;
}
int clk_enable(struct clk *clk)
{ unsignedlong flags; int ret;
if (!clk) return 0;
spin_lock_irqsave(&clock_lock, flags);
ret = __clk_enable(clk);
spin_unlock_irqrestore(&clock_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(clk_enable);
static LIST_HEAD(root_clks);
/** * 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;
/* * dummy mapping for root clocks with no specified ranges
*/ if (!clk->parent) {
clk->mapping = &dummy_mapping; goto out;
}
/* * If we're on a child clock and it provides no mapping of its * own, inherit the mapping from its root clock.
*/
clkp = lookup_root_clock(clk);
mapping = clkp->mapping;
BUG_ON(!mapping);
}
int clk_set_parent(struct clk *clk, struct clk *parent)
{ unsignedlong flags; int ret = -EINVAL;
if (!parent || !clk) return ret; if (clk->parent == parent) return 0;
spin_lock_irqsave(&clock_lock, flags); if (clk->usecount == 0) { if (clk->ops->set_parent)
ret = clk->ops->set_parent(clk, parent); else
ret = clk_reparent(clk, parent);
if (ret == 0) { if (clk->ops->recalc)
clk->rate = clk->ops->recalc(clk);
pr_debug("set parent of %p to %p (new rate %ld)\n",
clk, clk->parent, clk->rate);
propagate_rate(clk);
}
} else
ret = -EBUSY;
spin_unlock_irqrestore(&clock_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(clk_set_parent);
struct clk *clk_get_parent(struct clk *clk)
{ if (!clk) return NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.