Skip to content

Commit

Permalink
ARM: OMAP4: clock: Convert to common clk
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mike Turquette authored and Paul Walmsley committed Nov 12, 2012
1 parent f5dd3bb commit 32cc002
Show file tree
Hide file tree
Showing 7 changed files with 868 additions and 19 deletions.
184 changes: 179 additions & 5 deletions arch/arm/mach-omap2/clkt_clksel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -58,19 +62,30 @@
* 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 */

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;
}

Expand All @@ -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)
{
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 *
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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)
Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -520,11 +694,11 @@ 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)),
__clk_get_rate(clk));

return 0;
}
#endif
Loading

0 comments on commit 32cc002

Please sign in to comment.