mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-14 06:35:12 +00:00
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>
This commit is contained in:
parent
f5dd3bb53c
commit
32cc002116
7 changed files with 868 additions and 19 deletions
|
@ -41,7 +41,11 @@
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#else
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#endif
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
|
|
||||||
|
@ -58,11 +62,18 @@
|
||||||
* the element associated with the supplied parent clock address.
|
* the element associated with the supplied parent clock address.
|
||||||
* Returns a pointer to the struct clksel on success or NULL on error.
|
* 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,
|
static const struct clksel *_get_clksel_by_parent(struct clk *clk,
|
||||||
|
#endif
|
||||||
struct clk *src_clk)
|
struct clk *src_clk)
|
||||||
{
|
{
|
||||||
const struct clksel *clks;
|
const struct clksel *clks;
|
||||||
|
|
||||||
|
if (!src_clk)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (clks = clk->clksel; clks->parent; clks++)
|
for (clks = clk->clksel; clks->parent; clks++)
|
||||||
if (clks->parent == src_clk)
|
if (clks->parent == src_clk)
|
||||||
break; /* Found the requested parent */
|
break; /* Found the requested parent */
|
||||||
|
@ -70,7 +81,11 @@ static const struct clksel *_get_clksel_by_parent(struct clk *clk,
|
||||||
if (!clks->parent) {
|
if (!clks->parent) {
|
||||||
/* This indicates a data problem */
|
/* This indicates a data problem */
|
||||||
WARN(1, "clock: %s: could not find parent clock %s in clksel array\n",
|
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));
|
__clk_get_name(clk), __clk_get_name(src_clk));
|
||||||
|
#endif
|
||||||
return NULL;
|
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
|
* success (in this latter case, the corresponding register bitfield
|
||||||
* value is passed back in the variable pointed to by @field_val)
|
* 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,
|
static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
|
||||||
u32 *field_val)
|
u32 *field_val)
|
||||||
{
|
{
|
||||||
|
@ -134,6 +150,7 @@ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
|
||||||
|
|
||||||
return max_div;
|
return max_div;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _write_clksel_reg() - program a clock's clksel register in hardware
|
* _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
|
* take into account any time the hardware might take to switch the
|
||||||
* clock source.
|
* 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)
|
static void _write_clksel_reg(struct clk *clk, u32 field_val)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
u32 v;
|
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
|
* before calling. Returns 0 on error or returns the actual integer divisor
|
||||||
* upon success.
|
* 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)
|
static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct clksel *clks;
|
const struct clksel *clks;
|
||||||
const struct clksel_rate *clkr;
|
const struct clksel_rate *clkr;
|
||||||
struct clk *parent;
|
struct clk *parent;
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
parent = __clk_get_parent(clk->hw.clk);
|
||||||
|
#else
|
||||||
parent = __clk_get_parent(clk);
|
parent = __clk_get_parent(clk);
|
||||||
|
#endif
|
||||||
|
|
||||||
clks = _get_clksel_by_parent(clk, parent);
|
clks = _get_clksel_by_parent(clk, parent);
|
||||||
if (!clks)
|
if (!clks)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -193,7 +223,12 @@ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
|
||||||
if (!clkr->div) {
|
if (!clkr->div) {
|
||||||
/* This indicates a data error */
|
/* This indicates a data error */
|
||||||
WARN(1, "clock: %s: could not find fieldval %d for parent %s\n",
|
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));
|
__clk_get_name(clk), field_val, __clk_get_name(parent));
|
||||||
|
#endif
|
||||||
return 0;
|
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
|
* register field value _before_ left-shifting (i.e., LSB is at bit
|
||||||
* 0); or returns 0xFFFFFFFF (~0) upon error.
|
* 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)
|
static u32 _divisor_to_clksel(struct clk *clk, u32 div)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct clksel *clks;
|
const struct clksel *clks;
|
||||||
const struct clksel_rate *clkr;
|
const struct clksel_rate *clkr;
|
||||||
|
@ -219,7 +258,11 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div)
|
||||||
/* should never happen */
|
/* should never happen */
|
||||||
WARN_ON(div == 0);
|
WARN_ON(div == 0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
parent = __clk_get_parent(clk->hw.clk);
|
||||||
|
#else
|
||||||
parent = __clk_get_parent(clk);
|
parent = __clk_get_parent(clk);
|
||||||
|
#endif
|
||||||
clks = _get_clksel_by_parent(clk, parent);
|
clks = _get_clksel_by_parent(clk, parent);
|
||||||
if (!clks)
|
if (!clks)
|
||||||
return ~0;
|
return ~0;
|
||||||
|
@ -234,7 +277,12 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div)
|
||||||
|
|
||||||
if (!clkr->div) {
|
if (!clkr->div) {
|
||||||
pr_err("clock: %s: could not find divisor %d for parent %s\n",
|
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));
|
__clk_get_name(clk), div, __clk_get_name(parent));
|
||||||
|
#endif
|
||||||
return ~0;
|
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
|
* into the hardware, convert it into the actual divisor value, and
|
||||||
* return it; or return 0 on error.
|
* 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)
|
static u32 _read_divisor(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
|
|
||||||
|
@ -277,7 +329,12 @@ static u32 _read_divisor(struct clk *clk)
|
||||||
*
|
*
|
||||||
* Returns the rounded clock rate or returns 0xffffffff on error.
|
* 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,
|
u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
|
||||||
|
#endif
|
||||||
u32 *new_div)
|
u32 *new_div)
|
||||||
{
|
{
|
||||||
unsigned long test_rate;
|
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;
|
unsigned long parent_rate;
|
||||||
const char *clk_name;
|
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 = __clk_get_parent(clk);
|
||||||
parent_rate = __clk_get_rate(parent);
|
|
||||||
clk_name = __clk_get_name(clk);
|
clk_name = __clk_get_name(clk);
|
||||||
|
#endif
|
||||||
|
parent_rate = __clk_get_rate(parent);
|
||||||
|
|
||||||
if (!clk->clksel || !clk->clksel_mask)
|
if (!clk->clksel || !clk->clksel_mask)
|
||||||
return ~0;
|
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.)
|
* (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
|
* omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr
|
||||||
* @clk: OMAP clock struct ptr to use
|
* @clk: OMAP clock struct ptr to use
|
||||||
|
@ -393,6 +512,8 @@ void omap2_init_clksel_parent(struct clk *clk)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
|
* omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
|
||||||
* @clk: struct clk *
|
* @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
|
* function. Returns the clock's current rate, based on its parent's rate
|
||||||
* and its current divisor setting in the hardware.
|
* 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 omap2_clksel_recalc(struct clk *clk)
|
||||||
{
|
{
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
@ -420,6 +563,7 @@ unsigned long omap2_clksel_recalc(struct clk *clk)
|
||||||
|
|
||||||
return rate;
|
return rate;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* omap2_clksel_round_rate() - find rounded rate for the given clock and rate
|
* 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.
|
* 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)
|
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
u32 new_div;
|
u32 new_div;
|
||||||
|
|
||||||
return omap2_clksel_round_rate_div(clk, target_rate, &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.
|
* is changed, they will all be affected without any notification.
|
||||||
* Returns -EINVAL upon error, or 0 upon success.
|
* 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)
|
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
u32 field_val, validrate, new_div = 0;
|
u32 field_val, validrate, new_div = 0;
|
||||||
|
|
||||||
if (!clk->clksel || !clk->clksel_mask)
|
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);
|
_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),
|
pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(clk),
|
||||||
__clk_get_rate(clk));
|
__clk_get_rate(clk));
|
||||||
|
|
||||||
|
clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
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
|
* affected without any notification. Returns -EINVAL upon error, or
|
||||||
* 0 upon success.
|
* 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)
|
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
|
||||||
{
|
{
|
||||||
u32 field_val = 0;
|
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);
|
parent_div = _get_div_and_fieldval(new_parent, clk, &field_val);
|
||||||
if (!parent_div)
|
if (!parent_div)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
_write_clksel_reg(clk, field_val);
|
_write_clksel_reg(clk, field_val);
|
||||||
|
|
||||||
clk_reparent(clk, new_parent);
|
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)
|
if (parent_div > 0)
|
||||||
__clk_get_rate(clk) /= parent_div;
|
__clk_get_rate(clk) /= parent_div;
|
||||||
|
|
||||||
pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
|
pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
|
||||||
__clk_get_name(clk),
|
__clk_get_name(clk),
|
||||||
__clk_get_name(__clk_get_parent(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#else
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#endif
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
|
@ -76,7 +80,11 @@
|
||||||
* (assuming that it is counting N upwards), or -2 if the enclosing loop
|
* (assuming that it is counting N upwards), or -2 if the enclosing loop
|
||||||
* should skip to the next iteration (again assuming N is increasing).
|
* 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)
|
static int _dpll_test_fint(struct clk *clk, u8 n)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct dpll_data *dd;
|
struct dpll_data *dd;
|
||||||
long fint, fint_min, fint_max;
|
long fint, fint_min, fint_max;
|
||||||
|
@ -85,7 +93,11 @@ static int _dpll_test_fint(struct clk *clk, u8 n)
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
|
|
||||||
/* DPLL divider must result in a valid jitter correction val */
|
/* 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;
|
fint = __clk_get_rate(__clk_get_parent(clk)) / n;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (cpu_is_omap24xx()) {
|
if (cpu_is_omap24xx()) {
|
||||||
/* Should not be called for OMAP2, so warn if it is called */
|
/* Should not be called for OMAP2, so warn if it is called */
|
||||||
|
@ -186,15 +198,24 @@ static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Public functions */
|
/* 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)
|
void omap2_init_dpll_parent(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
u32 v;
|
u32 v;
|
||||||
struct dpll_data *dd;
|
struct dpll_data *dd;
|
||||||
|
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
if (!dd)
|
if (!dd)
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
return -EINVAL;
|
||||||
|
#else
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
v = __raw_readl(dd->control_reg);
|
v = __raw_readl(dd->control_reg);
|
||||||
v &= dd->enable_mask;
|
v &= dd->enable_mask;
|
||||||
|
@ -204,18 +225,34 @@ void omap2_init_dpll_parent(struct clk *clk)
|
||||||
if (cpu_is_omap24xx()) {
|
if (cpu_is_omap24xx()) {
|
||||||
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
|
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
|
||||||
v == OMAP2XXX_EN_DPLL_FRBYPASS)
|
v == OMAP2XXX_EN_DPLL_FRBYPASS)
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
clk_reparent(clk, dd->clk_bypass);
|
clk_reparent(clk, dd->clk_bypass);
|
||||||
|
#endif
|
||||||
} else if (cpu_is_omap34xx()) {
|
} else if (cpu_is_omap34xx()) {
|
||||||
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
|
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
|
||||||
v == OMAP3XXX_EN_DPLL_FRBYPASS)
|
v == OMAP3XXX_EN_DPLL_FRBYPASS)
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
clk_reparent(clk, dd->clk_bypass);
|
clk_reparent(clk, dd->clk_bypass);
|
||||||
|
#endif
|
||||||
} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
|
} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
|
||||||
if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
|
if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
|
||||||
v == OMAP4XXX_EN_DPLL_FRBYPASS ||
|
v == OMAP4XXX_EN_DPLL_FRBYPASS ||
|
||||||
v == OMAP4XXX_EN_DPLL_MNBYPASS)
|
v == OMAP4XXX_EN_DPLL_MNBYPASS)
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
clk_reparent(clk, dd->clk_bypass);
|
clk_reparent(clk, dd->clk_bypass);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,7 +269,11 @@ void omap2_init_dpll_parent(struct clk *clk)
|
||||||
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
|
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
|
||||||
* if the clock @clk is not a DPLL.
|
* 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)
|
u32 omap2_get_dpll_rate(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
long long dpll_clk;
|
long long dpll_clk;
|
||||||
u32 dpll_mult, dpll_div, v;
|
u32 dpll_mult, dpll_div, v;
|
||||||
|
@ -288,8 +329,15 @@ u32 omap2_get_dpll_rate(struct clk *clk)
|
||||||
* (expensive) function again. Returns ~0 if the target rate cannot
|
* (expensive) function again. Returns ~0 if the target rate cannot
|
||||||
* be rounded, or the rounded rate upon success.
|
* 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)
|
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
int m, n, r, scaled_max_m;
|
int m, n, r, scaled_max_m;
|
||||||
unsigned long scaled_rt_rp;
|
unsigned long scaled_rt_rp;
|
||||||
unsigned long new_rate = 0;
|
unsigned long new_rate = 0;
|
||||||
|
@ -303,7 +351,11 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
|
|
||||||
ref_rate = __clk_get_rate(dd->clk_ref);
|
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);
|
clk_name = __clk_get_name(clk);
|
||||||
|
#endif
|
||||||
pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
|
pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
|
||||||
clk_name, target_rate);
|
clk_name, target_rate);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,11 @@
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#else
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#endif
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,6 +52,14 @@ void omap2_clkt_iclk_deny_idle(struct clk *clk)
|
||||||
|
|
||||||
/* Public data */
|
/* Public data */
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
#else
|
||||||
const struct clkops clkops_omap2_iclk_dflt_wait = {
|
const struct clkops clkops_omap2_iclk_dflt_wait = {
|
||||||
.enable = omap2_dflt_clk_enable,
|
.enable = omap2_dflt_clk_enable,
|
||||||
.disable = omap2_dflt_clk_disable,
|
.disable = omap2_dflt_clk_disable,
|
||||||
|
@ -77,4 +89,4 @@ const struct clkops clkops_omap2_mdmclk_dflt_wait = {
|
||||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#else
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#endif
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
@ -57,7 +61,33 @@ static bool clkdm_control = true;
|
||||||
|
|
||||||
static LIST_HEAD(clocks);
|
static LIST_HEAD(clocks);
|
||||||
static DEFINE_MUTEX(clocks_mutex);
|
static DEFINE_MUTEX(clocks_mutex);
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
static DEFINE_SPINLOCK(clockfw_lock);
|
static DEFINE_SPINLOCK(clockfw_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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_warn("%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
|
* OMAP2+ specific clock functions
|
||||||
|
@ -109,7 +139,11 @@ static int _wait_idlest_generic(void __iomem *reg, u32 mask, u8 idlest,
|
||||||
* belong in the clock code and will be moved in the medium term to
|
* belong in the clock code and will be moved in the medium term to
|
||||||
* module-dependent code. No return value.
|
* 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)
|
static void _omap2_module_wait_ready(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
void __iomem *companion_reg, *idlest_reg;
|
void __iomem *companion_reg, *idlest_reg;
|
||||||
u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
|
u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
|
||||||
|
@ -124,12 +158,15 @@ static void _omap2_module_wait_ready(struct clk *clk)
|
||||||
}
|
}
|
||||||
|
|
||||||
clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
|
clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
|
||||||
|
|
||||||
r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
|
r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
|
||||||
if (r) {
|
if (r) {
|
||||||
/* IDLEST register not in the CM module */
|
/* IDLEST register not in the CM module */
|
||||||
_wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val,
|
_wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val,
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
__clk_get_name(clk->hw.clk));
|
||||||
|
#else
|
||||||
clk->name);
|
clk->name);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit);
|
cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit);
|
||||||
};
|
};
|
||||||
|
@ -145,15 +182,25 @@ static void _omap2_module_wait_ready(struct clk *clk)
|
||||||
* clockdomain pointer, and save it into the struct clk. Intended to be
|
* clockdomain pointer, and save it into the struct clk. Intended to be
|
||||||
* called during clk_register(). No return value.
|
* 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)
|
void omap2_init_clk_clkdm(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
struct clockdomain *clkdm;
|
struct clockdomain *clkdm;
|
||||||
const char *clk_name;
|
const char *clk_name;
|
||||||
|
|
||||||
if (!clk->clkdm_name)
|
if (!clk->clkdm_name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
clk_name = __clk_get_name(hw->clk);
|
||||||
|
#else
|
||||||
clk_name = __clk_get_name(clk);
|
clk_name = __clk_get_name(clk);
|
||||||
|
#endif
|
||||||
|
|
||||||
clkdm = clkdm_lookup(clk->clkdm_name);
|
clkdm = clkdm_lookup(clk->clkdm_name);
|
||||||
if (clkdm) {
|
if (clkdm) {
|
||||||
|
@ -200,8 +247,12 @@ void __init omap2_clk_disable_clkdm_control(void)
|
||||||
* associate this type of code with per-module data structures to
|
* associate this type of code with per-module data structures to
|
||||||
* avoid this issue, and remove the casts. No return value.
|
* avoid this issue, and remove the casts. No return value.
|
||||||
*/
|
*/
|
||||||
void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
|
#ifdef CONFIG_COMMON_CLK
|
||||||
u8 *other_bit)
|
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;
|
u32 r;
|
||||||
|
|
||||||
|
@ -229,8 +280,12 @@ void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
|
||||||
* register address ID (e.g., that CM_FCLKEN2 corresponds to
|
* register address ID (e.g., that CM_FCLKEN2 corresponds to
|
||||||
* CM_IDLEST2). This is not true for all modules. No return value.
|
* 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,
|
#ifdef CONFIG_COMMON_CLK
|
||||||
u8 *idlest_bit, u8 *idlest_val)
|
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;
|
u32 r;
|
||||||
|
|
||||||
|
@ -252,6 +307,225 @@ void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
/**
|
||||||
|
* omap2_dflt_clk_enable - enable a clock in the hardware
|
||||||
|
* @hw: struct clk_hw * of the clock to enable
|
||||||
|
*
|
||||||
|
* Enable the clock @hw in the hardware. We first call into the OMAP
|
||||||
|
* clockdomain code to "enable" the corresponding clockdomain if this
|
||||||
|
* is the first enabled user of the clockdomain. Then program the
|
||||||
|
* hardware to enable the clock. Then wait for the IP block that uses
|
||||||
|
* this clock to leave idle (if applicable). Returns the error value
|
||||||
|
* from clkdm_clk_enable() if it terminated with an error, or -EINVAL
|
||||||
|
* if @hw has a null clock enable_reg, or zero upon success.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* omap2_dflt_clk_disable - disable a clock in the hardware
|
||||||
|
* @hw: struct clk_hw * of the clock to disable
|
||||||
|
*
|
||||||
|
* Disable the clock @hw in the hardware, and call into the OMAP
|
||||||
|
* clockdomain code to "disable" the corresponding clockdomain if all
|
||||||
|
* clocks/hwmods in that clockdomain are now disabled. No return
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
|
||||||
|
* @hw: struct clk_hw * of the clock being enabled
|
||||||
|
*
|
||||||
|
* Increment the usecount of the clockdomain of the clock pointed to
|
||||||
|
* by @hw; if the usecount is 1, the clockdomain will be "enabled."
|
||||||
|
* Only needed for clocks that don't use omap2_dflt_clk_enable() as
|
||||||
|
* their enable function pointer. Passes along the return value of
|
||||||
|
* clkdm_clk_enable(), -EINVAL if @hw is not associated with a
|
||||||
|
* clockdomain, or 0 if clock framework-based clockdomain control is
|
||||||
|
* not implemented.
|
||||||
|
*/
|
||||||
|
int omap2_clkops_enable_clkdm(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct clk_hw_omap *clk;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
clk = to_clk_hw_omap(hw);
|
||||||
|
|
||||||
|
if (unlikely(!clk->clkdm)) {
|
||||||
|
pr_err("%s: %s: no clkdm set ?!\n", __func__,
|
||||||
|
__clk_get_name(hw->clk));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(clk->enable_reg))
|
||||||
|
pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__,
|
||||||
|
__clk_get_name(hw->clk));
|
||||||
|
|
||||||
|
if (!clkdm_control) {
|
||||||
|
pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
|
||||||
|
__func__, __clk_get_name(hw->clk));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clkdm_clk_enable(clk->clkdm, hw->clk);
|
||||||
|
WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
|
||||||
|
__func__, __clk_get_name(hw->clk), clk->clkdm->name, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
|
||||||
|
* @hw: struct clk_hw * of the clock being disabled
|
||||||
|
*
|
||||||
|
* Decrement the usecount of the clockdomain of the clock pointed to
|
||||||
|
* by @hw; if the usecount is 0, the clockdomain will be "disabled."
|
||||||
|
* Only needed for clocks that don't use omap2_dflt_clk_disable() as their
|
||||||
|
* disable function pointer. No return value.
|
||||||
|
*/
|
||||||
|
void omap2_clkops_disable_clkdm(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct clk_hw_omap *clk;
|
||||||
|
|
||||||
|
clk = to_clk_hw_omap(hw);
|
||||||
|
|
||||||
|
if (unlikely(!clk->clkdm)) {
|
||||||
|
pr_err("%s: %s: no clkdm set ?!\n", __func__,
|
||||||
|
__clk_get_name(hw->clk));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(clk->enable_reg))
|
||||||
|
pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__,
|
||||||
|
__clk_get_name(hw->clk));
|
||||||
|
|
||||||
|
if (!clkdm_control) {
|
||||||
|
pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
|
||||||
|
__func__, __clk_get_name(hw->clk));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clkdm_clk_disable(clk->clkdm, hw->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* omap2_dflt_clk_is_enabled - is clock enabled in the hardware?
|
||||||
|
* @hw: struct clk_hw * to check
|
||||||
|
*
|
||||||
|
* Return 1 if the clock represented by @hw is enabled in the
|
||||||
|
* hardware, or 0 otherwise. Intended for use in the struct
|
||||||
|
* clk_ops.is_enabled function pointer.
|
||||||
|
*/
|
||||||
|
int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||||
|
u32 v;
|
||||||
|
|
||||||
|
v = __raw_readl(clk->enable_reg);
|
||||||
|
|
||||||
|
if (clk->flags & INVERT_ENABLE)
|
||||||
|
v ^= BIT(clk->enable_bit);
|
||||||
|
|
||||||
|
v &= BIT(clk->enable_bit);
|
||||||
|
|
||||||
|
return v ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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_wait = {
|
||||||
|
.find_idlest = omap2_clk_dflt_find_idlest,
|
||||||
|
.find_companion = omap2_clk_dflt_find_companion,
|
||||||
|
};
|
||||||
|
#else
|
||||||
int omap2_dflt_clk_enable(struct clk *clk)
|
int omap2_dflt_clk_enable(struct clk *clk)
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
|
@ -482,6 +756,8 @@ void omap2_clk_disable_unused(struct clk *clk)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_COMMON_CLK */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument
|
* 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
|
* @mpurate_ck_name: clk name of the clock to change rate
|
||||||
|
@ -512,13 +788,15 @@ int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name)
|
||||||
r = clk_set_rate(mpurate_ck, mpurate);
|
r = clk_set_rate(mpurate_ck, mpurate);
|
||||||
if (IS_ERR_VALUE(r)) {
|
if (IS_ERR_VALUE(r)) {
|
||||||
WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n",
|
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);
|
clk_put(mpurate_ck);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
calibrate_delay();
|
calibrate_delay();
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
recalculate_root_clocks();
|
recalculate_root_clocks();
|
||||||
|
#endif
|
||||||
|
|
||||||
clk_put(mpurate_ck);
|
clk_put(mpurate_ck);
|
||||||
|
|
||||||
|
@ -564,8 +842,8 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name,
|
||||||
(clk_get_rate(mpu_ck) / 1000000));
|
(clk_get_rate(mpu_ck) / 1000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
/* Common data */
|
/* Common data */
|
||||||
|
|
||||||
int clk_enable(struct clk *clk)
|
int clk_enable(struct clk *clk)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -1072,4 +1350,4 @@ static int __init clk_debugfs_init(void)
|
||||||
late_initcall(clk_debugfs_init);
|
late_initcall(clk_debugfs_init);
|
||||||
|
|
||||||
#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
|
#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
|
||||||
|
#endif /* CONFIG_COMMON_CLK */
|
||||||
|
|
|
@ -397,6 +397,7 @@ extern const struct clkops clkops_null;
|
||||||
|
|
||||||
extern struct clk dummy_ck;
|
extern struct clk dummy_ck;
|
||||||
|
|
||||||
|
#endif /* CONFIG_COMMON_CLK */
|
||||||
|
|
||||||
/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
|
/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
|
||||||
#define CORE_CLK_SRC_32K 0x0
|
#define CORE_CLK_SRC_32K 0x0
|
||||||
|
@ -427,11 +428,36 @@ extern struct clk dummy_ck;
|
||||||
/* DPLL Type and DCO Selection Flags */
|
/* DPLL Type and DCO Selection Flags */
|
||||||
#define DPLL_J_TYPE 0x1
|
#define DPLL_J_TYPE 0x1
|
||||||
|
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
int omap2_clk_enable(struct clk *clk);
|
int omap2_clk_enable(struct clk *clk);
|
||||||
void omap2_clk_disable(struct clk *clk);
|
void omap2_clk_disable(struct clk *clk);
|
||||||
long omap2_clk_round_rate(struct clk *clk, unsigned long rate);
|
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_rate(struct clk *clk, unsigned long rate);
|
||||||
int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent);
|
int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent);
|
||||||
|
#endif /* CONFIG_COMMON_CLK */
|
||||||
|
|
||||||
|
#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);
|
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
|
||||||
unsigned long omap3_dpll_recalc(struct clk *clk);
|
unsigned long omap3_dpll_recalc(struct clk *clk);
|
||||||
unsigned long omap3_clkoutx2_recalc(struct clk *clk);
|
unsigned long omap3_clkoutx2_recalc(struct clk *clk);
|
||||||
|
@ -446,17 +472,33 @@ void omap4_dpllmx_allow_gatectrl(struct clk *clk);
|
||||||
void omap4_dpllmx_deny_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);
|
long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate);
|
||||||
unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk);
|
unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_OMAP_RESET_CLOCKS
|
#ifdef CONFIG_OMAP_RESET_CLOCKS
|
||||||
void omap2_clk_disable_unused(struct clk *clk);
|
void omap2_clk_disable_unused(struct clk *clk);
|
||||||
#else
|
#else
|
||||||
#define omap2_clk_disable_unused NULL
|
#define omap2_clk_disable_unused NULL
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
void omap2_init_clk_clkdm(struct clk_hw *clk);
|
||||||
|
#else
|
||||||
void omap2_init_clk_clkdm(struct clk *clk);
|
void omap2_init_clk_clkdm(struct clk *clk);
|
||||||
|
#endif
|
||||||
void __init omap2_clk_disable_clkdm_control(void);
|
void __init omap2_clk_disable_clkdm_control(void);
|
||||||
|
|
||||||
/* clkt_clksel.c public functions */
|
/* 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_clksel_find_parent_index(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 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
|
||||||
u32 *new_div);
|
u32 *new_div);
|
||||||
void omap2_init_clksel_parent(struct clk *clk);
|
void omap2_init_clksel_parent(struct clk *clk);
|
||||||
|
@ -464,20 +506,38 @@ unsigned long omap2_clksel_recalc(struct clk *clk);
|
||||||
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
|
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_rate(struct clk *clk, unsigned long rate);
|
||||||
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent);
|
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* clkt_iclk.c public functions */
|
/* clkt_iclk.c public functions */
|
||||||
extern void omap2_clkt_iclk_allow_idle(struct clk *clk);
|
extern void omap2_clkt_iclk_allow_idle(struct clk *clk);
|
||||||
extern void omap2_clkt_iclk_deny_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);
|
u32 omap2_get_dpll_rate(struct clk *clk);
|
||||||
void omap2_init_dpll_parent(struct clk *clk);
|
void omap2_init_dpll_parent(struct clk *clk);
|
||||||
|
#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);
|
int omap2_dflt_clk_enable(struct clk *clk);
|
||||||
void omap2_dflt_clk_disable(struct clk *clk);
|
void omap2_dflt_clk_disable(struct clk *clk);
|
||||||
void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
|
void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
|
||||||
u8 *other_bit);
|
u8 *other_bit);
|
||||||
void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
|
void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
|
||||||
u8 *idlest_bit, u8 *idlest_val);
|
u8 *idlest_bit, u8 *idlest_val);
|
||||||
|
#endif
|
||||||
int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name);
|
int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name);
|
||||||
void omap2_clk_print_new_rates(const char *hfclkin_ck_name,
|
void omap2_clk_print_new_rates(const char *hfclkin_ck_name,
|
||||||
const char *core_ck_name,
|
const char *core_ck_name,
|
||||||
|
@ -496,6 +556,13 @@ extern const struct clksel_rate gpt_sys_rates[];
|
||||||
extern const struct clksel_rate gfx_l3_rates[];
|
extern const struct clksel_rate gfx_l3_rates[];
|
||||||
extern const struct clksel_rate dsp_ick_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_wait;
|
||||||
extern const struct clkops clkops_omap2_iclk_dflt;
|
extern const struct clkops clkops_omap2_iclk_dflt;
|
||||||
extern const struct clkops clkops_omap2_iclk_idle_only;
|
extern const struct clkops clkops_omap2_iclk_idle_only;
|
||||||
|
@ -513,11 +580,17 @@ extern const struct clksel_rate div_1_3_rates[];
|
||||||
extern const struct clksel_rate div_1_4_rates[];
|
extern const struct clksel_rate div_1_4_rates[];
|
||||||
extern const struct clksel_rate div31_1to31_rates[];
|
extern const struct clksel_rate div31_1to31_rates[];
|
||||||
|
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
/* clocks shared between various OMAP SoCs */
|
/* clocks shared between various OMAP SoCs */
|
||||||
extern struct clk virt_19200000_ck;
|
extern struct clk virt_19200000_ck;
|
||||||
extern struct clk virt_26000000_ck;
|
extern struct clk virt_26000000_ck;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern int am33xx_clk_init(void);
|
extern int am33xx_clk_init(void);
|
||||||
|
|
||||||
#endif /* CONFIG_COMMON_CLK */
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
|
||||||
|
extern void omap2_clkops_disable_clkdm(struct clk_hw *hw);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/clkdev.h>
|
#include <linux/clkdev.h>
|
||||||
|
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
|
#include "clockdomain.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "cm2xxx_3xxx.h"
|
#include "cm2xxx_3xxx.h"
|
||||||
#include "cm-regbits-34xx.h"
|
#include "cm-regbits-34xx.h"
|
||||||
|
@ -42,7 +43,11 @@
|
||||||
/* Private functions */
|
/* Private functions */
|
||||||
|
|
||||||
/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
|
/* _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)
|
static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
@ -56,7 +61,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 */
|
/* _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)
|
static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -64,7 +73,11 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
|
||||||
const char *clk_name;
|
const char *clk_name;
|
||||||
|
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
clk_name = __clk_get_name(clk->hw.clk);
|
||||||
|
#else
|
||||||
clk_name = __clk_get_name(clk);
|
clk_name = __clk_get_name(clk);
|
||||||
|
#endif
|
||||||
|
|
||||||
state <<= __ffs(dd->idlest_mask);
|
state <<= __ffs(dd->idlest_mask);
|
||||||
|
|
||||||
|
@ -88,7 +101,11 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* From 3430 TRM ES2 4.7.6.2 */
|
/* 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)
|
static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
unsigned long fint;
|
unsigned long fint;
|
||||||
u16 f = 0;
|
u16 f = 0;
|
||||||
|
@ -133,14 +150,22 @@ static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n)
|
||||||
* locked successfully, return 0; if the DPLL did not lock in the time
|
* locked successfully, return 0; if the DPLL did not lock in the time
|
||||||
* allotted, or DPLL3 was passed in, return -EINVAL.
|
* 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)
|
static int _omap3_noncore_dpll_lock(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
u8 ai;
|
u8 ai;
|
||||||
u8 state = 1;
|
u8 state = 1;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
|
#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));
|
pr_debug("clock: locking DPLL %s\n", __clk_get_name(clk));
|
||||||
|
#endif
|
||||||
|
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
state <<= __ffs(dd->idlest_mask);
|
state <<= __ffs(dd->idlest_mask);
|
||||||
|
@ -178,7 +203,11 @@ static int _omap3_noncore_dpll_lock(struct clk *clk)
|
||||||
* DPLL3 was passed in, or the DPLL does not support low-power bypass,
|
* DPLL3 was passed in, or the DPLL does not support low-power bypass,
|
||||||
* return -EINVAL.
|
* 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)
|
static int _omap3_noncore_dpll_bypass(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
u8 ai;
|
u8 ai;
|
||||||
|
@ -187,7 +216,11 @@ static int _omap3_noncore_dpll_bypass(struct clk *clk)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
pr_debug("clock: configuring DPLL %s for low-power bypass\n",
|
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));
|
__clk_get_name(clk));
|
||||||
|
#endif
|
||||||
|
|
||||||
ai = omap3_dpll_autoidle_read(clk);
|
ai = omap3_dpll_autoidle_read(clk);
|
||||||
|
|
||||||
|
@ -210,14 +243,22 @@ static int _omap3_noncore_dpll_bypass(struct clk *clk)
|
||||||
* code. If DPLL3 was passed in, or the DPLL does not support
|
* code. If DPLL3 was passed in, or the DPLL does not support
|
||||||
* low-power stop, return -EINVAL; otherwise, return 0.
|
* 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)
|
static int _omap3_noncore_dpll_stop(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
u8 ai;
|
u8 ai;
|
||||||
|
|
||||||
if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
|
if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP)))
|
||||||
return -EINVAL;
|
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));
|
pr_debug("clock: stopping DPLL %s\n", __clk_get_name(clk));
|
||||||
|
#endif
|
||||||
|
|
||||||
ai = omap3_dpll_autoidle_read(clk);
|
ai = omap3_dpll_autoidle_read(clk);
|
||||||
|
|
||||||
|
@ -241,11 +282,19 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
|
||||||
* XXX This code is not needed for 3430/AM35xx; can it be optimized
|
* XXX This code is not needed for 3430/AM35xx; can it be optimized
|
||||||
* out in non-multi-OMAP builds for those chips?
|
* 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)
|
static void _lookup_dco(struct clk *clk, u8 *dco, u16 m, u8 n)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
unsigned long fint, clkinp; /* watch out for overflow */
|
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));
|
clkinp = __clk_get_rate(__clk_get_parent(clk));
|
||||||
|
#endif
|
||||||
fint = (clkinp / n) * m;
|
fint = (clkinp / n) * m;
|
||||||
|
|
||||||
if (fint < 1000000000)
|
if (fint < 1000000000)
|
||||||
|
@ -266,12 +315,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
|
* XXX This code is not needed for 3430/AM35xx; can it be optimized
|
||||||
* out in non-multi-OMAP builds for those chips?
|
* 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)
|
static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
unsigned long clkinp, sd; /* watch out for overflow */
|
unsigned long clkinp, sd; /* watch out for overflow */
|
||||||
int mod1, mod2;
|
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));
|
clkinp = __clk_get_rate(__clk_get_parent(clk));
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* target sigma-delta to near 250MHz
|
* target sigma-delta to near 250MHz
|
||||||
|
@ -298,7 +355,12 @@ 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
|
* Program the DPLL with the supplied M, N values, and wait for the DPLL to
|
||||||
* lock.. Returns -EINVAL upon error, or 0 upon success.
|
* 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)
|
static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct dpll_data *dd = clk->dpll_data;
|
struct dpll_data *dd = clk->dpll_data;
|
||||||
u8 dco, sd_div;
|
u8 dco, sd_div;
|
||||||
|
@ -355,8 +417,14 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
|
||||||
*
|
*
|
||||||
* Recalculate and propagate the DPLL rate.
|
* 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)
|
unsigned long omap3_dpll_recalc(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
return omap2_get_dpll_rate(clk);
|
return omap2_get_dpll_rate(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,8 +444,14 @@ unsigned long omap3_dpll_recalc(struct clk *clk)
|
||||||
* support low-power stop, or if the DPLL took too long to enter
|
* support low-power stop, or if the DPLL took too long to enter
|
||||||
* bypass or lock, return -EINVAL; otherwise, return 0.
|
* 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)
|
int omap3_noncore_dpll_enable(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
int r;
|
int r;
|
||||||
struct dpll_data *dd;
|
struct dpll_data *dd;
|
||||||
struct clk *parent;
|
struct clk *parent;
|
||||||
|
@ -386,15 +460,34 @@ int omap3_noncore_dpll_enable(struct clk *clk)
|
||||||
if (!dd)
|
if (!dd)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
if (clk->clkdm) {
|
||||||
|
r = clkdm_clk_enable(clk->clkdm, hw->clk);
|
||||||
|
if (r) {
|
||||||
|
WARN(1,
|
||||||
|
"%s: could not enable %s's clockdomain %s: %d\n",
|
||||||
|
__func__, __clk_get_name(hw->clk),
|
||||||
|
clk->clkdm->name, r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = __clk_get_parent(hw->clk);
|
||||||
|
|
||||||
|
if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) {
|
||||||
|
#else
|
||||||
parent = __clk_get_parent(clk);
|
parent = __clk_get_parent(clk);
|
||||||
|
|
||||||
if (__clk_get_rate(clk) == __clk_get_rate(dd->clk_bypass)) {
|
if (__clk_get_rate(clk) == __clk_get_rate(dd->clk_bypass)) {
|
||||||
|
#endif
|
||||||
WARN_ON(parent != dd->clk_bypass);
|
WARN_ON(parent != dd->clk_bypass);
|
||||||
r = _omap3_noncore_dpll_bypass(clk);
|
r = _omap3_noncore_dpll_bypass(clk);
|
||||||
} else {
|
} else {
|
||||||
WARN_ON(parent != dd->clk_ref);
|
WARN_ON(parent != dd->clk_ref);
|
||||||
r = _omap3_noncore_dpll_lock(clk);
|
r = _omap3_noncore_dpll_lock(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
/*
|
/*
|
||||||
*FIXME: this is dubious - if clk->rate has changed, what about
|
*FIXME: this is dubious - if clk->rate has changed, what about
|
||||||
* propagating?
|
* propagating?
|
||||||
|
@ -402,6 +495,7 @@ int omap3_noncore_dpll_enable(struct clk *clk)
|
||||||
if (!r)
|
if (!r)
|
||||||
clk->rate = (clk->recalc) ? clk->recalc(clk) :
|
clk->rate = (clk->recalc) ? clk->recalc(clk) :
|
||||||
omap2_get_dpll_rate(clk);
|
omap2_get_dpll_rate(clk);
|
||||||
|
#endif
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -413,9 +507,21 @@ int omap3_noncore_dpll_enable(struct clk *clk)
|
||||||
* Instructs a non-CORE DPLL to enter low-power stop. This function is
|
* Instructs a non-CORE DPLL to enter low-power stop. This function is
|
||||||
* intended for use in struct clkops. No return value.
|
* 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);
|
||||||
|
|
||||||
|
_omap3_noncore_dpll_stop(clk);
|
||||||
|
if (clk->clkdm)
|
||||||
|
clkdm_clk_disable(clk->clkdm, hw->clk);
|
||||||
|
#else
|
||||||
void omap3_noncore_dpll_disable(struct clk *clk)
|
void omap3_noncore_dpll_disable(struct clk *clk)
|
||||||
{
|
{
|
||||||
_omap3_noncore_dpll_stop(clk);
|
_omap3_noncore_dpll_stop(clk);
|
||||||
|
if (clk->clkdm)
|
||||||
|
clkdm_clk_disable(clk->clkdm, clk);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -432,6 +538,77 @@ void omap3_noncore_dpll_disable(struct clk *clk)
|
||||||
* target rate if it hasn't been done already, then program and lock
|
* target rate if it hasn't been done already, then program and lock
|
||||||
* the DPLL. Returns -EINVAL upon error, or 0 upon success.
|
* 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)
|
int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
|
||||||
{
|
{
|
||||||
struct clk *new_parent = NULL;
|
struct clk *new_parent = NULL;
|
||||||
|
@ -509,6 +686,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* DPLL autoidle read/set code */
|
/* DPLL autoidle read/set code */
|
||||||
|
|
||||||
|
@ -520,7 +698,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
|
* -EINVAL if passed a null pointer or if the struct clk does not
|
||||||
* appear to refer to a DPLL.
|
* 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)
|
u32 omap3_dpll_autoidle_read(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
@ -549,7 +731,11 @@ u32 omap3_dpll_autoidle_read(struct clk *clk)
|
||||||
* OMAP3430. The DPLL will enter low-power stop when its downstream
|
* OMAP3430. The DPLL will enter low-power stop when its downstream
|
||||||
* clocks are gated. No return value.
|
* 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)
|
void omap3_dpll_allow_idle(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
@ -560,8 +746,10 @@ void omap3_dpll_allow_idle(struct clk *clk)
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
|
|
||||||
if (!dd->autoidle_reg) {
|
if (!dd->autoidle_reg) {
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
pr_debug("clock: DPLL %s: autoidle not supported\n",
|
pr_debug("clock: DPLL %s: autoidle not supported\n",
|
||||||
__clk_get_name(clk));
|
__clk_get_name(clk));
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +771,11 @@ void omap3_dpll_allow_idle(struct clk *clk)
|
||||||
*
|
*
|
||||||
* Disable DPLL automatic idle control. No return value.
|
* 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)
|
void omap3_dpll_deny_idle(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
@ -594,8 +786,10 @@ void omap3_dpll_deny_idle(struct clk *clk)
|
||||||
dd = clk->dpll_data;
|
dd = clk->dpll_data;
|
||||||
|
|
||||||
if (!dd->autoidle_reg) {
|
if (!dd->autoidle_reg) {
|
||||||
|
#ifndef CONFIG_COMMON_CLK
|
||||||
pr_debug("clock: DPLL %s: autoidle not supported\n",
|
pr_debug("clock: DPLL %s: autoidle not supported\n",
|
||||||
__clk_get_name(clk));
|
__clk_get_name(clk));
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,6 +809,27 @@ void omap3_dpll_deny_idle(struct clk *clk)
|
||||||
* Using parent clock DPLL data, look up DPLL state. If locked, set our
|
* Using parent clock DPLL data, look up DPLL state. If locked, set our
|
||||||
* rate to the dpll_clk * 2; otherwise, just use dpll_clk.
|
* 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)
|
unsigned long omap3_clkoutx2_recalc(struct clk *clk)
|
||||||
{
|
{
|
||||||
const struct dpll_data *dd;
|
const struct dpll_data *dd;
|
||||||
|
@ -628,6 +843,8 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk)
|
||||||
while (pclk && !pclk->dpll_data)
|
while (pclk && !pclk->dpll_data)
|
||||||
pclk = __clk_get_parent(pclk);
|
pclk = __clk_get_parent(pclk);
|
||||||
|
|
||||||
|
parent_rate = __clk_get_rate(__clk_get_parent(clk));
|
||||||
|
#endif
|
||||||
/* clk does not have a DPLL as a parent? error in the clock data */
|
/* clk does not have a DPLL as a parent? error in the clock data */
|
||||||
if (!pclk) {
|
if (!pclk) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
@ -638,7 +855,6 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk)
|
||||||
|
|
||||||
WARN_ON(!dd->enable_mask);
|
WARN_ON(!dd->enable_mask);
|
||||||
|
|
||||||
parent_rate = __clk_get_rate(__clk_get_parent(clk));
|
|
||||||
v = __raw_readl(dd->control_reg) & dd->enable_mask;
|
v = __raw_readl(dd->control_reg) & dd->enable_mask;
|
||||||
v >>= __ffs(dd->enable_mask);
|
v >>= __ffs(dd->enable_mask);
|
||||||
if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
|
if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
|
||||||
|
@ -649,7 +865,12 @@ unsigned long omap3_clkoutx2_recalc(struct clk *clk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OMAP3/4 non-CORE DPLL clkops */
|
/* OMAP3/4 non-CORE DPLL clkops */
|
||||||
|
#ifdef CONFIG_COMMON_CLK
|
||||||
|
const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
|
||||||
|
.allow_idle = omap3_dpll_allow_idle,
|
||||||
|
.deny_idle = omap3_dpll_deny_idle,
|
||||||
|
};
|
||||||
|
#else
|
||||||
const struct clkops clkops_omap3_noncore_dpll_ops = {
|
const struct clkops clkops_omap3_noncore_dpll_ops = {
|
||||||
.enable = omap3_noncore_dpll_enable,
|
.enable = omap3_noncore_dpll_enable,
|
||||||
.disable = omap3_noncore_dpll_disable,
|
.disable = omap3_noncore_dpll_disable,
|
||||||
|
@ -661,3 +882,4 @@ const struct clkops clkops_omap3_core_dpll_ops = {
|
||||||
.allow_idle = omap3_dpll_allow_idle,
|
.allow_idle = omap3_dpll_allow_idle,
|
||||||
.deny_idle = omap3_dpll_deny_idle,
|
.deny_idle = omap3_dpll_deny_idle,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
|
@ -21,7 +21,11 @@
|
||||||
#include "cm-regbits-44xx.h"
|
#include "cm-regbits-44xx.h"
|
||||||
|
|
||||||
/* Supported only on OMAP4 */
|
/* 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)
|
int omap4_dpllmx_gatectrl_read(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
|
@ -40,7 +44,11 @@ int omap4_dpllmx_gatectrl_read(struct clk *clk)
|
||||||
return v;
|
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)
|
void omap4_dpllmx_allow_gatectrl(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
|
@ -58,7 +66,11 @@ void omap4_dpllmx_allow_gatectrl(struct clk *clk)
|
||||||
__raw_writel(v, clk->clksel_reg);
|
__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)
|
void omap4_dpllmx_deny_gatectrl(struct clk *clk)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
u32 v;
|
u32 v;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
|
@ -76,10 +88,17 @@ void omap4_dpllmx_deny_gatectrl(struct clk *clk)
|
||||||
__raw_writel(v, clk->clksel_reg);
|
__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 = {
|
const struct clkops clkops_omap4_dpllmx_ops = {
|
||||||
.allow_idle = omap4_dpllmx_allow_gatectrl,
|
.allow_idle = omap4_dpllmx_allow_gatectrl,
|
||||||
.deny_idle = omap4_dpllmx_deny_gatectrl,
|
.deny_idle = omap4_dpllmx_deny_gatectrl,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
|
* omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
|
||||||
|
@ -90,8 +109,15 @@ const struct clkops clkops_omap4_dpllmx_ops = {
|
||||||
* OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers)
|
* OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers)
|
||||||
* upon success, or 0 upon error.
|
* 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)
|
unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
u32 v;
|
u32 v;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
struct dpll_data *dd;
|
struct dpll_data *dd;
|
||||||
|
@ -123,8 +149,16 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk)
|
||||||
* M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or
|
* M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or
|
||||||
* ~0 if an error occurred in omap2_dpll_round_rate().
|
* ~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)
|
long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
u32 v;
|
u32 v;
|
||||||
struct dpll_data *dd;
|
struct dpll_data *dd;
|
||||||
long r;
|
long r;
|
||||||
|
@ -140,7 +174,11 @@ long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate)
|
||||||
if (v)
|
if (v)
|
||||||
target_rate = target_rate / OMAP4430_REGM4XEN_MULT;
|
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);
|
r = omap2_dpll_round_rate(clk, target_rate);
|
||||||
|
#endif
|
||||||
if (r == ~0)
|
if (r == ~0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue