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@xxxxxx> --- arch/arm/mach-omap2/clkt_clksel.c | 144 +++++++++++++++++++++++++- arch/arm/mach-omap2/clkt_dpll.c | 54 ++++++++++- arch/arm/mach-omap2/clkt_iclk.c | 4 + arch/arm/mach-omap2/clock.c | 200 +++++++++++++++++++++++++++++++++++-- arch/arm/mach-omap2/clock.h | 60 +++++++++++- arch/arm/mach-omap2/dpll3xxx.c | 198 ++++++++++++++++++++++++++++++++++++- arch/arm/mach-omap2/dpll44xx.c | 37 +++++++ 7 files changed, 681 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c index 1c054ba..c99222a 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> @@ -60,11 +64,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 */ @@ -74,7 +85,11 @@ static const struct clksel *_get_clksel_by_parent(struct clk *clk, WARN(1, "clock: Could not find parent clock %s in clksel array " "of clock %s\n", __clk_get_name(src_clk), +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk)); +#else __clk_get_name(clk)); +#endif return NULL; } @@ -96,6 +111,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) { @@ -138,6 +154,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 @@ -152,7 +169,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; @@ -175,13 +196,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; @@ -198,7 +228,11 @@ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) /* This indicates a data error */ WARN(1, "clock: Could not find fieldval %d for clock %s parent " "%s\n", field_val, +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk), +#else __clk_get_name(clk), +#endif __clk_get_name(parent)); return 0; } @@ -216,7 +250,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; @@ -225,7 +263,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; @@ -241,7 +283,11 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div) if (!clkr->div) { pr_err("clock: Could not find divisor %d for clock %s parent " "%s\n", div, +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk), +#else __clk_get_name(clk), +#endif __clk_get_name(parent)); return ~0; } @@ -257,7 +303,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; @@ -285,7 +335,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; @@ -296,9 +351,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; @@ -358,8 +418,14 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, * to. Update @clk's .parent field with the appropriate clk ptr. No * return value. */ +#ifdef CONFIG_COMMON_CLK +u8 omap2_init_clksel_parent(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else void omap2_init_clksel_parent(struct clk *clk) { +#endif const struct clksel *clks; const struct clksel_rate *clkr; u32 r, found = 0; @@ -367,10 +433,17 @@ void omap2_init_clksel_parent(struct clk *clk) const char *clk_name; if (!clk->clksel || !clk->clksel_mask) +#ifdef CONFIG_COMMON_CLK + return -EINVAL; + + parent = __clk_get_parent(hw->clk); + clk_name = __clk_get_name(hw->clk); +#else return; parent = __clk_get_parent(clk); clk_name = __clk_get_name(clk); +#endif r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; r >>= __ffs(clk->clksel_mask); @@ -389,9 +462,14 @@ void omap2_init_clksel_parent(struct clk *clk) ((parent) ? __clk_get_name(parent) : "NULL")); +#ifdef CONFIG_COMMON_CLK + }; + return r; +#else clk_reparent(clk, clks->parent); }; found = 1; +#endif } } } @@ -400,7 +478,11 @@ void omap2_init_clksel_parent(struct clk *clk) WARN(!found, "clock: %s: init parent: could not find regval %0x\n", clk_name, r); +#ifdef CONFIG_COMMON_CLK + return -ENODEV; +#else return; +#endif } /** @@ -412,6 +494,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; @@ -431,6 +535,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 @@ -443,8 +548,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); @@ -465,8 +577,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) @@ -482,12 +601,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; - pr_debug("clock: %s: set rate to %ld\n", +#ifdef CONFIG_COMMON_CLK + __clk_get_name(hw->clk), + __clk_get_rate(hw->clk)); +#else __clk_get_name(clk), __clk_get_rate(clk)); + clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div; +#endif return 0; } @@ -511,6 +634,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; @@ -522,7 +657,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); @@ -532,7 +666,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)), @@ -540,3 +673,4 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) return 0; } +#endif diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index 6a8a012..e84512f 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -16,7 +16,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 <asm/div64.h> @@ -78,7 +82,11 @@ * (assuming that it is counting N upwards), or -2 if the enclosing loop * should skip to the next iteration (again assuming N is increasing). */ +#ifdef CONFIG_COMMON_CLK +static int _dpll_test_fint(struct clk_hw_omap *clk, u8 n) +#else static int _dpll_test_fint(struct clk *clk, u8 n) +#endif { struct dpll_data *dd; long fint, fint_min, fint_max; @@ -87,7 +95,11 @@ static int _dpll_test_fint(struct clk *clk, u8 n) dd = clk->dpll_data; /* DPLL divider must result in a valid jitter correction val */ +#ifdef CONFIG_COMMON_CLK + fint = __clk_get_rate(__clk_get_parent(clk->hw.clk)) / n; +#else fint = __clk_get_rate(__clk_get_parent(clk)) / n; +#endif if (cpu_is_omap24xx()) { /* Should not be called for OMAP2, so warn if it is called */ @@ -188,15 +200,24 @@ static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, } /* Public functions */ - +#ifdef CONFIG_COMMON_CLK +u8 omap2_init_dpll_parent(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else void omap2_init_dpll_parent(struct clk *clk) { +#endif u32 v; struct dpll_data *dd; dd = clk->dpll_data; if (!dd) +#ifdef CONFIG_COMMON_CLK + return -EINVAL; +#else return; +#endif v = __raw_readl(dd->control_reg); v &= dd->enable_mask; @@ -206,18 +227,34 @@ void omap2_init_dpll_parent(struct clk *clk) if (cpu_is_omap24xx()) { if (v == OMAP2XXX_EN_DPLL_LPBYPASS || v == OMAP2XXX_EN_DPLL_FRBYPASS) +#ifdef CONFIG_COMMON_CLK + return 1; +#else clk_reparent(clk, dd->clk_bypass); +#endif } else if (cpu_is_omap34xx()) { if (v == OMAP3XXX_EN_DPLL_LPBYPASS || v == OMAP3XXX_EN_DPLL_FRBYPASS) +#ifdef CONFIG_COMMON_CLK + return 1; +#else clk_reparent(clk, dd->clk_bypass); +#endif } else if (cpu_is_omap44xx()) { if (v == OMAP4XXX_EN_DPLL_LPBYPASS || v == OMAP4XXX_EN_DPLL_FRBYPASS || v == OMAP4XXX_EN_DPLL_MNBYPASS) +#ifdef CONFIG_COMMON_CLK + return 1; +#else clk_reparent(clk, dd->clk_bypass); +#endif } +#ifdef CONFIG_COMMON_CLK + return 0; +#else return; +#endif } /** @@ -234,7 +271,11 @@ void omap2_init_dpll_parent(struct clk *clk) * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 * if the clock @clk is not a DPLL. */ +#ifdef CONFIG_COMMON_CLK +unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) +#else u32 omap2_get_dpll_rate(struct clk *clk) +#endif { long long dpll_clk; u32 dpll_mult, dpll_div, v; @@ -290,8 +331,15 @@ u32 omap2_get_dpll_rate(struct clk *clk) * (expensive) function again. Returns ~0 if the target rate cannot * be rounded, or the rounded rate upon success. */ +#ifdef CONFIG_COMMON_CLK +long omap2_dpll_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_dpll_round_rate(struct clk *clk, unsigned long target_rate) { +#endif int m, n, r, scaled_max_m; unsigned long scaled_rt_rp; unsigned long new_rate = 0; @@ -305,7 +353,11 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) dd = clk->dpll_data; ref_rate = __clk_get_rate(dd->clk_ref); +#ifdef CONFIG_COMMON_CLK + clk_name = __clk_get_name(hw->clk); +#else clk_name = __clk_get_name(clk); +#endif pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n", clk_name, target_rate); diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c index 3d43fba..7787fbb 100644 --- a/arch/arm/mach-omap2/clkt_iclk.c +++ b/arch/arm/mach-omap2/clkt_iclk.c @@ -11,7 +11,11 @@ #undef DEBUG #include <linux/kernel.h> +#ifdef CONFIG_COMMON_CLK +#include <linux/clk-provider.h> +#else #include <linux/clk.h> +#endif #include <linux/io.h> #include <plat/clock.h> diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index aa00f72..42cdd9f 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -19,7 +19,11 @@ #include <linux/errno.h> #include <linux/err.h> #include <linux/delay.h> +#ifdef CONFIG_COMMON_CLK +#include <linux/clk-provider.h> +#else #include <linux/clk.h> +#endif #include <linux/io.h> #include <linux/bitops.h> #include <trace/events/power.h> @@ -45,6 +49,30 @@ u16 cpu_mask; */ static bool clkdm_control = true; +#ifdef CONFIG_COMMON_CLK + +/* + * Used for clocks that have the same value as the parent clock, + * divided by some factor + */ +unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hw_omap *oclk; + + if (!hw) { + pr_warning("%s: hw is NULL\n", __func__); + return -EINVAL; + } + + oclk = to_clk_hw_omap(hw); + + WARN_ON(!oclk->fixed_div); + + return parent_rate / oclk->fixed_div; +} +#endif + /* * OMAP2+ specific clock functions */ @@ -61,7 +89,11 @@ static bool clkdm_control = true; * belong in the clock code and will be moved in the medium term to * module-dependent code. No return value. */ +#ifdef CONFIG_COMMON_CLK +static void _omap2_module_wait_ready(struct clk_hw_omap *clk) +#else static void _omap2_module_wait_ready(struct clk *clk) +#endif { void __iomem *companion_reg, *idlest_reg; u8 other_bit, idlest_bit, idlest_val; @@ -74,9 +106,12 @@ static void _omap2_module_wait_ready(struct clk *clk) } clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); - omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), idlest_val, +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk)); +#else __clk_get_name(clk)); +#endif } /* Public functions */ @@ -89,15 +124,25 @@ static void _omap2_module_wait_ready(struct clk *clk) * clockdomain pointer, and save it into the struct clk. Intended to be * called during clk_register(). No return value. */ +#ifdef CONFIG_COMMON_CLK +void omap2_init_clk_clkdm(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else void omap2_init_clk_clkdm(struct clk *clk) { +#endif struct clockdomain *clkdm; const char *clk_name; if (!clk->clkdm_name) return; +#ifdef CONFIG_COMMON_CLK + clk_name = __clk_get_name(hw->clk); +#else clk_name = __clk_get_name(clk); +#endif clkdm = clkdm_lookup(clk->clkdm_name); if (clkdm) { @@ -144,8 +189,12 @@ void __init omap2_clk_disable_clkdm_control(void) * associate this type of code with per-module data structures to * avoid this issue, and remove the casts. No return value. */ -void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, - u8 *other_bit) +#ifdef CONFIG_COMMON_CLK +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, +#else +void omap2_clk_dflt_find_companion(struct clk *clk, +#endif + void __iomem **other_reg, u8 *other_bit) { u32 r; @@ -173,8 +222,12 @@ void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, * register address ID (e.g., that CM_FCLKEN2 corresponds to * CM_IDLEST2). This is not true for all modules. No return value. */ -void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, - u8 *idlest_bit, u8 *idlest_val) +#ifdef CONFIG_COMMON_CLK +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, +#else +void omap2_clk_dflt_find_idlest(struct clk *clk, +#endif + void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val) { u32 r; @@ -196,6 +249,133 @@ void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, } +#ifdef CONFIG_COMMON_CLK +int omap2_dflt_clk_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + u32 v; + int ret = 0; + + clk = to_clk_hw_omap(hw); + + if (clkdm_control && clk->clkdm) { + ret = clkdm_clk_enable(clk->clkdm, hw->clk); + if (ret) { + WARN(1, "%s: could not enable %s's clockdomain %s: %d\n", + __func__, __clk_get_name(hw->clk), + clk->clkdm->name, ret); + return ret; + } + } + + if (unlikely(clk->enable_reg == NULL)) { + pr_err("%s: %s missing enable_reg\n", __func__, + __clk_get_name(hw->clk)); + ret = -EINVAL; + goto err; + } + + /* FIXME should not have INVERT_ENABLE bit here */ + v = __raw_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v &= ~(1 << clk->enable_bit); + else + v |= (1 << clk->enable_bit); + __raw_writel(v, clk->enable_reg); + v = __raw_readl(clk->enable_reg); /* OCP barrier */ + + if (clk->ops && clk->ops->find_idlest) + _omap2_module_wait_ready(clk); + + return 0; + +err: + if (clkdm_control && clk->clkdm) + clkdm_clk_disable(clk->clkdm, hw->clk); + return ret; +} + +void omap2_dflt_clk_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + u32 v; + + clk = to_clk_hw_omap(hw); + if (!clk->enable_reg) { + /* + * 'independent' here refers to a clock which is not + * controlled by its parent. + */ + pr_err("%s: independent clock %s has no enable_reg\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + v = __raw_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v |= (1 << clk->enable_bit); + else + v &= ~(1 << clk->enable_bit); + __raw_writel(v, clk->enable_reg); + /* No OCP barrier needed here since it is a disable operation */ + + if (clkdm_control && clk->clkdm) + clkdm_clk_disable(clk->clkdm, hw->clk); +} + +int omap2_dflt_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + u32 regval32, v; + + v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0; + + regval32 = __raw_readl(clk->enable_reg); + if ((regval32 & (1 << clk->enable_bit)) == v) + return 0; + + omap2_dflt_clk_enable(hw); + + return 1; +} + +int __initdata mpurate; + +/* + * 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) +{ + get_option(&str, &mpurate); + + if (!mpurate) + return 1; + + if (mpurate < 1000) + mpurate *= 1000000; + + return 1; +} +__setup("mpurate=", omap_clk_setup); + +const struct clk_hw_omap_ops clkhwops_omap3_dpll = { + .allow_idle = omap3_dpll_allow_idle, + .deny_idle = omap3_dpll_deny_idle, +}; + +const struct clk_hw_omap_ops clkhwops_iclk_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap2_clk_dflt_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +const struct clk_hw_omap_ops clkhwops_wait = { + .find_idlest = omap2_clk_dflt_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; +#else int omap2_dflt_clk_enable(struct clk *clk) { u32 v; @@ -446,6 +626,8 @@ void omap2_clk_disable_unused(struct clk *clk) } #endif +#endif /* CONFIG_COMMON_CLK */ + /** * omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument * @mpurate_ck_name: clk name of the clock to change rate @@ -476,13 +658,15 @@ int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name) r = clk_set_rate(mpurate_ck, mpurate); if (IS_ERR_VALUE(r)) { WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n", - mpurate_ck->name, mpurate, r); + mpurate_ck_name, mpurate, r); clk_put(mpurate_ck); return -EINVAL; } calibrate_delay(); +#ifndef CONFIG_COMMON_CLK recalculate_root_clocks(); +#endif clk_put(mpurate_ck); @@ -530,8 +714,8 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name, (clk_get_rate(mpu_ck) / 1000000)); } +#ifndef CONFIG_COMMON_CLK /* Common data */ - struct clk_functions omap2_clk_functions = { .clk_enable = omap2_clk_enable, .clk_disable = omap2_clk_disable, @@ -540,4 +724,4 @@ struct clk_functions omap2_clk_functions = { .clk_set_parent = omap2_clk_set_parent, .clk_disable_unused = omap2_clk_disable_unused, }; - +#endif diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index a1bb23a..2219271 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -54,6 +54,26 @@ void omap2_clk_disable(struct clk *clk); long omap2_clk_round_rate(struct clk *clk, unsigned long rate); int omap2_clk_set_rate(struct clk *clk, unsigned long rate); int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent); +#ifdef CONFIG_COMMON_CLK +long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); +unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); +int omap3_noncore_dpll_enable(struct clk_hw *hw); +void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); +void omap3_dpll_allow_idle(struct clk_hw_omap *clk); +void omap3_dpll_deny_idle(struct clk_hw_omap *clk); +unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, unsigned long parent_rate); +int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk); +void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); +void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); +unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, + unsigned long parent_rate); +long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); +#else long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate); unsigned long omap3_dpll_recalc(struct clk *clk); unsigned long omap3_clkoutx2_recalc(struct clk *clk); @@ -68,17 +88,32 @@ void omap4_dpllmx_allow_gatectrl(struct clk *clk); void omap4_dpllmx_deny_gatectrl(struct clk *clk); long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate); unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk); +#endif #ifdef CONFIG_OMAP_RESET_CLOCKS void omap2_clk_disable_unused(struct clk *clk); #else #define omap2_clk_disable_unused NULL #endif - +#ifdef CONFIG_COMMON_CLK +void omap2_init_clk_clkdm(struct clk_hw *clk); +#else void omap2_init_clk_clkdm(struct clk *clk); +#endif void __init omap2_clk_disable_clkdm_control(void); /* clkt_clksel.c public functions */ +#ifdef CONFIG_COMMON_CLK +u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk, unsigned long target_rate, + u32 *new_div); +u8 omap2_init_clksel_parent(struct clk_hw *hw); +unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate); +long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); +int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); +#else u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, u32 *new_div); void omap2_init_clksel_parent(struct clk *clk); @@ -86,13 +121,19 @@ unsigned long omap2_clksel_recalc(struct clk *clk); long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); +#endif /* clkt_iclk.c public functions */ extern void omap2_clkt_iclk_allow_idle(struct clk *clk); extern void omap2_clkt_iclk_deny_idle(struct clk *clk); +#ifdef CONFIG_COMMON_CLK +u8 omap2_init_dpll_parent(struct clk_hw *hw); +unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); +#else u32 omap2_get_dpll_rate(struct clk *clk); void omap2_init_dpll_parent(struct clk *clk); +#endif int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); @@ -121,12 +162,22 @@ static inline void omap4_clk_prepare_for_reboot(void) } #endif +#ifdef CONFIG_COMMON_CLK +int omap2_dflt_clk_enable(struct clk_hw *hw); +void omap2_dflt_clk_disable(struct clk_hw *hw); +int omap2_dflt_clk_is_enabled(struct clk_hw *hw); +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val); +#else int omap2_dflt_clk_enable(struct clk *clk); void omap2_dflt_clk_disable(struct clk *clk); void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, u8 *other_bit); void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val); +#endif int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name); void omap2_clk_print_new_rates(const char *hfclkin_ck_name, const char *core_ck_name, @@ -146,6 +197,13 @@ extern const struct clksel_rate gpt_sys_rates[]; extern const struct clksel_rate gfx_l3_rates[]; extern const struct clksel_rate dsp_ick_rates[]; +#ifdef CONFIG_COMMON_CLK +extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; +extern const struct clk_hw_omap_ops clkhwops_iclk_wait; +extern const struct clk_hw_omap_ops clkhwops_wait; +extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; +#endif + extern const struct clkops clkops_omap2_iclk_dflt_wait; extern const struct clkops clkops_omap2_iclk_dflt; extern const struct clkops clkops_omap2_iclk_idle_only; diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index d390f40..d6b2d39 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -44,7 +44,11 @@ /* Private functions */ /* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */ +#ifdef CONFIG_COMMON_CLK +static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits) +#else static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits) +#endif { const struct dpll_data *dd; u32 v; @@ -58,7 +62,11 @@ static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits) } /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ +#ifdef CONFIG_COMMON_CLK +static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state) +#else static int _omap3_wait_dpll_status(struct clk *clk, u8 state) +#endif { const struct dpll_data *dd; int i = 0; @@ -66,7 +74,11 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state) const char *clk_name; dd = clk->dpll_data; +#ifdef CONFIG_COMMON_CLK + clk_name = __clk_get_name(clk->hw.clk); +#else clk_name = __clk_get_name(clk); +#endif state <<= __ffs(dd->idlest_mask); @@ -90,7 +102,11 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state) } /* From 3430 TRM ES2 4.7.6.2 */ +#ifdef CONFIG_COMMON_CLK +static u16 _omap3_dpll_compute_freqsel(struct clk_hw_omap *clk, u8 n) +#else static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n) +#endif { unsigned long fint; u16 f = 0; @@ -135,12 +151,20 @@ static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n) * locked successfully, return 0; if the DPLL did not lock in the time * allotted, or DPLL3 was passed in, return -EINVAL. */ +#ifdef CONFIG_COMMON_CLK +static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk) +#else static int _omap3_noncore_dpll_lock(struct clk *clk) +#endif { u8 ai; int r; +#ifdef CONFIG_COMMON_CLK + pr_debug("clock: locking DPLL %s\n", __clk_get_name(clk->hw.clk)); +#else pr_debug("clock: locking DPLL %s\n", __clk_get_name(clk)); +#endif ai = omap3_dpll_autoidle_read(clk); @@ -170,7 +194,11 @@ static int _omap3_noncore_dpll_lock(struct clk *clk) * DPLL3 was passed in, or the DPLL does not support low-power bypass, * return -EINVAL. */ +#ifdef CONFIG_COMMON_CLK +static int _omap3_noncore_dpll_bypass(struct clk_hw_omap *clk) +#else static int _omap3_noncore_dpll_bypass(struct clk *clk) +#endif { int r; u8 ai; @@ -179,7 +207,11 @@ static int _omap3_noncore_dpll_bypass(struct clk *clk) return -EINVAL; pr_debug("clock: configuring DPLL %s for low-power bypass\n", +#ifdef CONFIG_COMMON_CLK + __clk_get_name(clk->hw.clk)); +#else __clk_get_name(clk)); +#endif ai = omap3_dpll_autoidle_read(clk); @@ -202,14 +234,22 @@ static int _omap3_noncore_dpll_bypass(struct clk *clk) * code. If DPLL3 was passed in, or the DPLL does not support * low-power stop, return -EINVAL; otherwise, return 0. */ +#ifdef CONFIG_COMMON_CLK +static int _omap3_noncore_dpll_stop(struct clk_hw_omap *clk) +#else static int _omap3_noncore_dpll_stop(struct clk *clk) +#endif { u8 ai; if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP))) return -EINVAL; +#ifdef CONFIG_COMMON_CLK + pr_debug("clock: stopping DPLL %s\n", __clk_get_name(clk->hw.clk)); +#else pr_debug("clock: stopping DPLL %s\n", __clk_get_name(clk)); +#endif ai = omap3_dpll_autoidle_read(clk); @@ -233,11 +273,19 @@ static int _omap3_noncore_dpll_stop(struct clk *clk) * XXX This code is not needed for 3430/AM35xx; can it be optimized * out in non-multi-OMAP builds for those chips? */ +#ifdef CONFIG_COMMON_CLK +static void _lookup_dco(struct clk_hw_omap *clk, u8 *dco, u16 m, u8 n) +#else static void _lookup_dco(struct clk *clk, u8 *dco, u16 m, u8 n) +#endif { unsigned long fint, clkinp; /* watch out for overflow */ +#ifdef CONFIG_COMMON_CLK + clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk)); +#else clkinp = __clk_get_rate(__clk_get_parent(clk)); +#endif fint = (clkinp / n) * m; if (fint < 1000000000) @@ -258,12 +306,20 @@ static void _lookup_dco(struct clk *clk, u8 *dco, u16 m, u8 n) * XXX This code is not needed for 3430/AM35xx; can it be optimized * out in non-multi-OMAP builds for those chips? */ +#ifdef CONFIG_COMMON_CLK +static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n) +#else static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n) +#endif { unsigned long clkinp, sd; /* watch out for overflow */ int mod1, mod2; +#ifdef CONFIG_COMMON_CLK + clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk)); +#else clkinp = __clk_get_rate(__clk_get_parent(clk)); +#endif /* * target sigma-delta to near 250MHz @@ -290,7 +346,11 @@ static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n) * Program the DPLL with the supplied M, N values, and wait for the DPLL to * lock.. Returns -EINVAL upon error, or 0 upon success. */ +#ifdef CONFIG_COMMON_CLK +static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n, u16 freqsel) +#else static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) +#endif { struct dpll_data *dd = clk->dpll_data; u8 dco, sd_div; @@ -347,8 +407,14 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) * * Recalculate and propagate the DPLL rate. */ +#ifdef CONFIG_COMMON_CLK +unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else unsigned long omap3_dpll_recalc(struct clk *clk) { +#endif return omap2_get_dpll_rate(clk); } @@ -368,8 +434,14 @@ unsigned long omap3_dpll_recalc(struct clk *clk) * support low-power stop, or if the DPLL took too long to enter * bypass or lock, return -EINVAL; otherwise, return 0. */ +#ifdef CONFIG_COMMON_CLK +int omap3_noncore_dpll_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else int omap3_noncore_dpll_enable(struct clk *clk) { +#endif int r; struct dpll_data *dd; struct clk *parent; @@ -378,15 +450,23 @@ int omap3_noncore_dpll_enable(struct clk *clk) if (!dd) return -EINVAL; +#ifdef CONFIG_COMMON_CLK + parent = __clk_get_parent(hw->clk); + + if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) { +#else parent = __clk_get_parent(clk); if (__clk_get_rate(clk) == __clk_get_rate(dd->clk_bypass)) { +#endif WARN_ON(parent != dd->clk_bypass); r = _omap3_noncore_dpll_bypass(clk); } else { WARN_ON(parent != dd->clk_ref); r = _omap3_noncore_dpll_lock(clk); } + +#ifndef CONFIG_COMMON_CLK /* *FIXME: this is dubious - if clk->rate has changed, what about * propagating? @@ -394,6 +474,7 @@ int omap3_noncore_dpll_enable(struct clk *clk) if (!r) clk->rate = (clk->recalc) ? clk->recalc(clk) : omap2_get_dpll_rate(clk); +#endif return r; } @@ -405,8 +486,14 @@ int omap3_noncore_dpll_enable(struct clk *clk) * Instructs a non-CORE DPLL to enter low-power stop. This function is * intended for use in struct clkops. No return value. */ +#ifdef CONFIG_COMMON_CLK +void omap3_noncore_dpll_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else void omap3_noncore_dpll_disable(struct clk *clk) { +#endif _omap3_noncore_dpll_stop(clk); } @@ -424,6 +511,77 @@ void omap3_noncore_dpll_disable(struct clk *clk) * target rate if it hasn't been done already, then program and lock * the DPLL. Returns -EINVAL upon error, or 0 upon success. */ +#ifdef CONFIG_COMMON_CLK +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct clk *new_parent = NULL; + u16 freqsel = 0; + struct dpll_data *dd; + int ret; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + __clk_prepare(dd->clk_bypass); + clk_enable(dd->clk_bypass); + __clk_prepare(dd->clk_ref); + clk_enable(dd->clk_ref); + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + pr_debug("%s: %s: set rate: entering bypass.\n", + __func__, __clk_get_name(hw->clk)); + + ret = _omap3_noncore_dpll_bypass(clk); + if (!ret) + new_parent = dd->clk_bypass; + } else { + if (dd->last_rounded_rate != rate) + rate = __clk_round_rate(hw->clk, rate); + + if (dd->last_rounded_rate == 0) + return -EINVAL; + + /* No freqsel on OMAP4 and OMAP3630 */ + if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { + freqsel = _omap3_dpll_compute_freqsel(clk, + dd->last_rounded_n); + if (!freqsel) + WARN_ON(1); + } + + pr_debug("%s: %s: set rate: locking rate to %lu.\n", + __func__, __clk_get_name(hw->clk), rate); + + ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, + dd->last_rounded_n, freqsel); + if (!ret) + new_parent = dd->clk_ref; + } + /* + * FIXME - this is all wrong. common code handles reparenting and + * migrating prepare/enable counts. dplls should be a multiplexer + * clock and this should be a set_parent operation so that all of that + * stuff is inherited for free + */ + + if (!ret) + __clk_reparent(hw->clk, new_parent); + + clk_disable(dd->clk_ref); + __clk_unprepare(dd->clk_ref); + clk_disable(dd->clk_bypass); + __clk_unprepare(dd->clk_bypass); + + return 0; +} +#else int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) { struct clk *new_parent = NULL; @@ -500,6 +658,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) return 0; } +#endif /* DPLL autoidle read/set code */ @@ -511,7 +670,11 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) * -EINVAL if passed a null pointer or if the struct clk does not * appear to refer to a DPLL. */ +#ifdef CONFIG_COMMON_CLK +u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) +#else u32 omap3_dpll_autoidle_read(struct clk *clk) +#endif { const struct dpll_data *dd; u32 v; @@ -540,7 +703,11 @@ u32 omap3_dpll_autoidle_read(struct clk *clk) * OMAP3430. The DPLL will enter low-power stop when its downstream * clocks are gated. No return value. */ +#ifdef CONFIG_COMMON_CLK +void omap3_dpll_allow_idle(struct clk_hw_omap *clk) +#else void omap3_dpll_allow_idle(struct clk *clk) +#endif { const struct dpll_data *dd; u32 v; @@ -551,8 +718,10 @@ void omap3_dpll_allow_idle(struct clk *clk) dd = clk->dpll_data; if (!dd->autoidle_reg) { +#ifndef CONFIG_COMMON_CLK pr_debug("clock: DPLL %s: autoidle not supported\n", __clk_get_name(clk)); +#endif return; } @@ -574,7 +743,11 @@ void omap3_dpll_allow_idle(struct clk *clk) * * Disable DPLL automatic idle control. No return value. */ +#ifdef CONFIG_COMMON_CLK +void omap3_dpll_deny_idle(struct clk_hw_omap *clk) +#else void omap3_dpll_deny_idle(struct clk *clk) +#endif { const struct dpll_data *dd; u32 v; @@ -585,8 +758,10 @@ void omap3_dpll_deny_idle(struct clk *clk) dd = clk->dpll_data; if (!dd->autoidle_reg) { +#ifndef CONFIG_COMMON_CLK pr_debug("clock: DPLL %s: autoidle not supported\n", __clk_get_name(clk)); +#endif return; } @@ -606,6 +781,26 @@ void omap3_dpll_deny_idle(struct clk *clk) * Using parent clock DPLL data, look up DPLL state. If locked, set our * rate to the dpll_clk * 2; otherwise, just use dpll_clk. */ +#ifdef CONFIG_COMMON_CLK +unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, unsigned long parent_rate) +{ + const struct dpll_data *dd; + unsigned long rate; + u32 v; + struct clk_hw_omap *pclk = NULL; + struct clk *parent; + + /* Walk up the parents of clk, looking for a DPLL */ + do { + do { + parent = __clk_get_parent(hw->clk); + hw = __clk_get_hw(parent); + } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC)); + if (!hw) + break; + pclk = to_clk_hw_omap(hw); + } while (pclk && !pclk->dpll_data); +#else unsigned long omap3_clkoutx2_recalc(struct clk *clk) { const struct dpll_data *dd; @@ -619,6 +814,8 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk) while (pclk && !pclk->dpll_data) pclk = __clk_get_parent(pclk); + parent_rate = __clk_get_rate(__clk_get_parent(clk)); +#endif /* clk does not have a DPLL as a parent? */ WARN_ON(!pclk); @@ -626,7 +823,6 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk) WARN_ON(!dd->enable_mask); - parent_rate = __clk_get_rate(__clk_get_parent(clk)); v = __raw_readl(dd->control_reg) & dd->enable_mask; v >>= __ffs(dd->enable_mask); if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 9c6a296..fbf94d2 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -23,7 +23,11 @@ #include "cm-regbits-44xx.h" /* Supported only on OMAP4 */ +#ifdef CONFIG_COMMON_CLK +int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk) +#else int omap4_dpllmx_gatectrl_read(struct clk *clk) +#endif { u32 v; u32 mask; @@ -42,7 +46,11 @@ int omap4_dpllmx_gatectrl_read(struct clk *clk) return v; } +#ifdef CONFIG_COMMON_CLK +void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) +#else void omap4_dpllmx_allow_gatectrl(struct clk *clk) +#endif { u32 v; u32 mask; @@ -60,7 +68,11 @@ void omap4_dpllmx_allow_gatectrl(struct clk *clk) __raw_writel(v, clk->clksel_reg); } +#ifdef CONFIG_COMMON_CLK +void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) +#else void omap4_dpllmx_deny_gatectrl(struct clk *clk) +#endif { u32 v; u32 mask; @@ -78,10 +90,17 @@ void omap4_dpllmx_deny_gatectrl(struct clk *clk) __raw_writel(v, clk->clksel_reg); } +#ifdef CONFIG_COMMON_CLK +const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { + .allow_idle = omap4_dpllmx_allow_gatectrl, + .deny_idle = omap4_dpllmx_deny_gatectrl, +}; +#else const struct clkops clkops_omap4_dpllmx_ops = { .allow_idle = omap4_dpllmx_allow_gatectrl, .deny_idle = omap4_dpllmx_deny_gatectrl, }; +#endif /** * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit @@ -92,8 +111,15 @@ const struct clkops clkops_omap4_dpllmx_ops = { * OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers) * upon success, or 0 upon error. */ +#ifdef CONFIG_COMMON_CLK +unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); +#else unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk) { +#endif u32 v; unsigned long rate; struct dpll_data *dd; @@ -125,8 +151,15 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk) * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or * ~0 if an error occurred in omap2_dpll_round_rate(). */ +#ifdef CONFIG_COMMON_CLK +long omap4_dpll_regm4xen_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 omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) { +#endif u32 v; struct dpll_data *dd; long r; @@ -142,7 +175,11 @@ long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) if (v) target_rate = target_rate / OMAP4430_REGM4XEN_MULT; +#ifdef CONFIG_COMMON_CLK + r = omap2_dpll_round_rate(hw, target_rate, NULL); +#else r = omap2_dpll_round_rate(clk, target_rate); +#endif if (r == ~0) return r; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html