diff options
author | Mike Turquette <mturquette@linaro.org> | 2012-11-11 00:58:41 +0100 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2012-11-12 21:55:50 +0100 |
commit | 32cc002116b866151ca24c6e9110ba8a93754753 (patch) | |
tree | 4a7d3f08bf774ed72d37bd0de541d9dac5e3083e /arch/arm/mach-omap2/clkt_clksel.c | |
parent | ARM: OMAP: hwmod: Fix up hwmod based clkdm accesses (diff) | |
download | linux-32cc002116b866151ca24c6e9110ba8a93754753.tar.xz linux-32cc002116b866151ca24c6e9110ba8a93754753.zip |
ARM: OMAP4: clock: Convert to common clk
Convert all OMAP4 specific platform files to use COMMON clk
and keep all the changes under the CONFIG_COMMON_CLK macro check
so it does not break any existing code. At a later point switch
to COMMON clk and get rid of all old/legacy code.
This converts all apis which will be called directly from COMMON
clk to take a struct clk_hw parameter, and all the internal platform
apis to take a struct clk_hw_omap parameter.
Changes are based off the original patch from Mike Turquette.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
[paul@pwsan.com: created new omap2_clksel_find_parent_index() rather than
modifying omap2_init_clksel_parent(); moved clkhwops_iclk_wait to
clkt_iclk.c to fix OMAP4-only builds; added clk-provider.h include to clock.h
to try to fix some 3430-builds]
[mturquette@ti.com: squash patch for omap2_clkops_{en,dis}able_clkdm;
omap2_dflt_clk_is_enabled should not enable clocks]
Signed-off-by: Mike Turquette <mturquette@ti.com>
[paul@pwsan.com: fix compiler warning; update to apply; added kerneldoc on
non-trivial new functions; added the dpll3xxx clockdomain modifications]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm/mach-omap2/clkt_clksel.c')
-rw-r--r-- | arch/arm/mach-omap2/clkt_clksel.c | 184 |
1 files changed, 179 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c index 53646facda45..03ceb2efd532 100644 --- a/arch/arm/mach-omap2/clkt_clksel.c +++ b/arch/arm/mach-omap2/clkt_clksel.c @@ -41,7 +41,11 @@ #include <linux/kernel.h> #include <linux/errno.h> +#ifdef CONFIG_COMMON_CLK +#include <linux/clk-provider.h> +#else #include <linux/clk.h> +#endif #include <linux/io.h> #include <linux/bug.h> @@ -58,11 +62,18 @@ * the element associated with the supplied parent clock address. * Returns a pointer to the struct clksel on success or NULL on error. */ +#ifdef CONFIG_COMMON_CLK +static const struct clksel *_get_clksel_by_parent(struct clk_hw_omap *clk, +#else static const struct clksel *_get_clksel_by_parent(struct clk *clk, +#endif struct clk *src_clk) { const struct clksel *clks; + if (!src_clk) + return NULL; + for (clks = clk->clksel; clks->parent; clks++) if (clks->parent == src_clk) break; /* Found the requested parent */ @@ -70,7 +81,11 @@ static const struct clksel *_get_clksel_by_parent(struct clk *clk, if (!clks->parent) { /* This indicates a data problem */ WARN(1, "clock: %s: could not find parent clock %s in clksel array\n", +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk), __clk_get_name(src_clk)); +#else __clk_get_name(clk), __clk_get_name(src_clk)); +#endif return NULL; } @@ -92,6 +107,7 @@ static const struct clksel *_get_clksel_by_parent(struct clk *clk, * success (in this latter case, the corresponding register bitfield * value is passed back in the variable pointed to by @field_val) */ +#ifndef CONFIG_COMMON_CLK static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, u32 *field_val) { @@ -134,6 +150,7 @@ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, return max_div; } +#endif /** * _write_clksel_reg() - program a clock's clksel register in hardware @@ -148,7 +165,11 @@ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, * take into account any time the hardware might take to switch the * clock source. */ +#ifdef CONFIG_COMMON_CLK +static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val) +#else static void _write_clksel_reg(struct clk *clk, u32 field_val) +#endif { u32 v; @@ -171,13 +192,22 @@ static void _write_clksel_reg(struct clk *clk, u32 field_val) * before calling. Returns 0 on error or returns the actual integer divisor * upon success. */ +#ifdef CONFIG_COMMON_CLK +static u32 _clksel_to_divisor(struct clk_hw_omap *clk, u32 field_val) +#else static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) +#endif { const struct clksel *clks; const struct clksel_rate *clkr; struct clk *parent; +#ifdef CONFIG_COMMON_CLK + parent = __clk_get_parent(clk->hw.clk); +#else parent = __clk_get_parent(clk); +#endif + clks = _get_clksel_by_parent(clk, parent); if (!clks) return 0; @@ -193,7 +223,12 @@ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) if (!clkr->div) { /* This indicates a data error */ WARN(1, "clock: %s: could not find fieldval %d for parent %s\n", +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk), field_val, + __clk_get_name(parent)); +#else __clk_get_name(clk), field_val, __clk_get_name(parent)); +#endif return 0; } @@ -210,7 +245,11 @@ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) * register field value _before_ left-shifting (i.e., LSB is at bit * 0); or returns 0xFFFFFFFF (~0) upon error. */ +#ifdef CONFIG_COMMON_CLK +static u32 _divisor_to_clksel(struct clk_hw_omap *clk, u32 div) +#else static u32 _divisor_to_clksel(struct clk *clk, u32 div) +#endif { const struct clksel *clks; const struct clksel_rate *clkr; @@ -219,7 +258,11 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div) /* should never happen */ WARN_ON(div == 0); +#ifdef CONFIG_COMMON_CLK + parent = __clk_get_parent(clk->hw.clk); +#else parent = __clk_get_parent(clk); +#endif clks = _get_clksel_by_parent(clk, parent); if (!clks) return ~0; @@ -234,7 +277,12 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div) if (!clkr->div) { pr_err("clock: %s: could not find divisor %d for parent %s\n", +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk), div, + __clk_get_name(parent)); +#else __clk_get_name(clk), div, __clk_get_name(parent)); +#endif return ~0; } @@ -249,7 +297,11 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div) * into the hardware, convert it into the actual divisor value, and * return it; or return 0 on error. */ +#ifdef CONFIG_COMMON_CLK +static u32 _read_divisor(struct clk_hw_omap *clk) +#else static u32 _read_divisor(struct clk *clk) +#endif { u32 v; @@ -277,7 +329,12 @@ static u32 _read_divisor(struct clk *clk) * * Returns the rounded clock rate or returns 0xffffffff on error. */ +#ifdef CONFIG_COMMON_CLK +u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk, + unsigned long target_rate, +#else u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, +#endif u32 *new_div) { unsigned long test_rate; @@ -288,9 +345,14 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, unsigned long parent_rate; const char *clk_name; +#ifdef CONFIG_COMMON_CLK + parent = __clk_get_parent(clk->hw.clk); + clk_name = __clk_get_name(clk->hw.clk); +#else parent = __clk_get_parent(clk); - parent_rate = __clk_get_rate(parent); clk_name = __clk_get_name(clk); +#endif + parent_rate = __clk_get_rate(parent); if (!clk->clksel || !clk->clksel_mask) return ~0; @@ -340,6 +402,63 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, * (i.e., those used in struct clk field function pointers, etc.) */ +#ifdef CONFIG_COMMON_CLK +/** + * omap2_clksel_find_parent_index() - return the array index of the current + * hardware parent of @hw + * @hw: struct clk_hw * to find the current hardware parent of + * + * Given a struct clk_hw pointer @hw to the 'hw' member of a struct + * clk_hw_omap record representing a source-selectable hardware clock, + * read the hardware register and determine what its parent is + * currently set to. Intended to be called only by the common clock + * framework struct clk_hw_ops.get_parent function pointer. Return + * the array index of this parent clock upon success -- there is no + * way to return an error, so if we encounter an error, just WARN() + * and pretend that we know that we're doing. + */ +u8 omap2_clksel_find_parent_index(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + const struct clksel *clks; + const struct clksel_rate *clkr; + u32 r, found = 0; + struct clk *parent; + const char *clk_name; + int ret = 0, f = 0; + + parent = __clk_get_parent(hw->clk); + clk_name = __clk_get_name(hw->clk); + + /* XXX should be able to return an error */ + WARN((!clk->clksel || !clk->clksel_mask), + "clock: %s: attempt to call on a non-clksel clock", clk_name); + + r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; + r >>= __ffs(clk->clksel_mask); + + for (clks = clk->clksel; clks->parent && !found; clks++) { + for (clkr = clks->rates; clkr->div && !found; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + if (clkr->val == r) { + found = 1; + ret = f; + } + } + f++; + } + + /* This indicates a data error */ + WARN(!found, "clock: %s: init parent: could not find regval %0x\n", + clk_name, r); + + return ret; +} + +#else + /** * omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr * @clk: OMAP clock struct ptr to use @@ -393,6 +512,8 @@ void omap2_init_clksel_parent(struct clk *clk) return; } +#endif + /** * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field * @clk: struct clk * @@ -402,6 +523,28 @@ void omap2_init_clksel_parent(struct clk *clk) * function. Returns the clock's current rate, based on its parent's rate * and its current divisor setting in the hardware. */ +#ifdef CONFIG_COMMON_CLK +unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate) +{ + unsigned long rate; + u32 div = 0; + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + + if (!parent_rate) + return 0; + + div = _read_divisor(clk); + if (!div) + rate = parent_rate; + else + rate = parent_rate / div; + + pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__, + __clk_get_name(hw->clk), rate, div); + + return rate; +} +#else unsigned long omap2_clksel_recalc(struct clk *clk) { unsigned long rate; @@ -420,6 +563,7 @@ unsigned long omap2_clksel_recalc(struct clk *clk) return rate; } +#endif /** * omap2_clksel_round_rate() - find rounded rate for the given clock and rate @@ -432,8 +576,15 @@ unsigned long omap2_clksel_recalc(struct clk *clk) * * Returns the rounded clock rate or returns 0xffffffff on error. */ +#ifdef CONFIG_COMMON_CLK +long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) { +#endif u32 new_div; return omap2_clksel_round_rate_div(clk, target_rate, &new_div); @@ -454,8 +605,15 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) * is changed, they will all be affected without any notification. * Returns -EINVAL upon error, or 0 upon success. */ +#ifdef CONFIG_COMMON_CLK +int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) { +#endif u32 field_val, validrate, new_div = 0; if (!clk->clksel || !clk->clksel_mask) @@ -471,11 +629,16 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) _write_clksel_reg(clk, field_val); - clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div; - +#ifdef CONFIG_COMMON_CLK + pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(hw->clk), + __clk_get_rate(hw->clk)); +#else pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(clk), __clk_get_rate(clk)); + clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div; +#endif + return 0; } @@ -499,6 +662,18 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) * affected without any notification. Returns -EINVAL upon error, or * 0 upon success. */ +#ifdef CONFIG_COMMON_CLK +int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + + if (!clk->clksel || !clk->clksel_mask) + return -EINVAL; + + _write_clksel_reg(clk, field_val); + return 0; +} +#else int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) { u32 field_val = 0; @@ -510,7 +685,6 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) parent_div = _get_div_and_fieldval(new_parent, clk, &field_val); if (!parent_div) return -EINVAL; - _write_clksel_reg(clk, field_val); clk_reparent(clk, new_parent); @@ -520,7 +694,6 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) if (parent_div > 0) __clk_get_rate(clk) /= parent_div; - pr_debug("clock: %s: set parent to %s (new rate %ld)\n", __clk_get_name(clk), __clk_get_name(__clk_get_parent(clk)), @@ -528,3 +701,4 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) return 0; } +#endif |