Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32cc0021 authored by Mike Turquette's avatar Mike Turquette Committed by Paul Walmsley
Browse files

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: default avatarRajendra 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: default avatarMike 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: default avatarPaul Walmsley <paul@pwsan.com>
parent f5dd3bb5
Loading
Loading
Loading
Loading
+179 −5
Original line number Diff line number Diff line
@@ -41,7 +41,11 @@

#include <linux/kernel.h>
#include <linux/errno.h>
#ifdef CONFIG_COMMON_CLK
#include <linux/clk-provider.h>
#else
#include <linux/clk.h>
#endif
#include <linux/io.h>
#include <linux/bug.h>

@@ -58,11 +62,18 @@
 * the element associated with the supplied parent clock address.
 * Returns a pointer to the struct clksel on success or NULL on error.
 */
#ifdef CONFIG_COMMON_CLK
static const struct clksel *_get_clksel_by_parent(struct clk_hw_omap *clk,
#else
static const struct clksel *_get_clksel_by_parent(struct clk *clk,
#endif
						  struct clk *src_clk)
{
	const struct clksel *clks;

	if (!src_clk)
		return NULL;

	for (clks = clk->clksel; clks->parent; clks++)
		if (clks->parent == src_clk)
			break; /* Found the requested parent */
@@ -70,7 +81,11 @@ static const struct clksel *_get_clksel_by_parent(struct clk *clk,
	if (!clks->parent) {
		/* This indicates a data problem */
		WARN(1, "clock: %s: could not find parent clock %s in clksel array\n",
#ifdef CONFIG_COMMON_CLK
		     __clk_get_name(clk->hw.clk), __clk_get_name(src_clk));
#else
		     __clk_get_name(clk), __clk_get_name(src_clk));
#endif
		return NULL;
	}

@@ -92,6 +107,7 @@ static const struct clksel *_get_clksel_by_parent(struct clk *clk,
 * success (in this latter case, the corresponding register bitfield
 * value is passed back in the variable pointed to by @field_val)
 */
#ifndef CONFIG_COMMON_CLK
static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
				u32 *field_val)
{
@@ -134,6 +150,7 @@ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,

	return max_div;
}
#endif

/**
 * _write_clksel_reg() - program a clock's clksel register in hardware
@@ -148,7 +165,11 @@ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
 * take into account any time the hardware might take to switch the
 * clock source.
 */
#ifdef CONFIG_COMMON_CLK
static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val)
#else
static void _write_clksel_reg(struct clk *clk, u32 field_val)
#endif
{
	u32 v;

@@ -171,13 +192,22 @@ static void _write_clksel_reg(struct clk *clk, u32 field_val)
 * before calling.  Returns 0 on error or returns the actual integer divisor
 * upon success.
 */
#ifdef CONFIG_COMMON_CLK
static u32 _clksel_to_divisor(struct clk_hw_omap *clk, u32 field_val)
#else
static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
#endif
{
	const struct clksel *clks;
	const struct clksel_rate *clkr;
	struct clk *parent;

#ifdef CONFIG_COMMON_CLK
	parent = __clk_get_parent(clk->hw.clk);
#else
	parent = __clk_get_parent(clk);
#endif

	clks = _get_clksel_by_parent(clk, parent);
	if (!clks)
		return 0;
@@ -193,7 +223,12 @@ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
	if (!clkr->div) {
		/* This indicates a data error */
		WARN(1, "clock: %s: could not find fieldval %d for parent %s\n",
#ifdef CONFIG_COMMON_CLK
		     __clk_get_name(clk->hw.clk), field_val,
		     __clk_get_name(parent));
#else
		     __clk_get_name(clk), field_val, __clk_get_name(parent));
#endif
		return 0;
	}

@@ -210,7 +245,11 @@ static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
 * register field value _before_ left-shifting (i.e., LSB is at bit
 * 0); or returns 0xFFFFFFFF (~0) upon error.
 */
#ifdef CONFIG_COMMON_CLK
static u32 _divisor_to_clksel(struct clk_hw_omap *clk, u32 div)
#else
static u32 _divisor_to_clksel(struct clk *clk, u32 div)
#endif
{
	const struct clksel *clks;
	const struct clksel_rate *clkr;
@@ -219,7 +258,11 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div)
	/* should never happen */
	WARN_ON(div == 0);

#ifdef CONFIG_COMMON_CLK
	parent = __clk_get_parent(clk->hw.clk);
#else
	parent = __clk_get_parent(clk);
#endif
	clks = _get_clksel_by_parent(clk, parent);
	if (!clks)
		return ~0;
@@ -234,7 +277,12 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div)

	if (!clkr->div) {
		pr_err("clock: %s: could not find divisor %d for parent %s\n",
#ifdef CONFIG_COMMON_CLK
		       __clk_get_name(clk->hw.clk), div,
		       __clk_get_name(parent));
#else
		       __clk_get_name(clk), div, __clk_get_name(parent));
#endif
		return ~0;
	}

@@ -249,7 +297,11 @@ static u32 _divisor_to_clksel(struct clk *clk, u32 div)
 * into the hardware, convert it into the actual divisor value, and
 * return it; or return 0 on error.
 */
#ifdef CONFIG_COMMON_CLK
static u32 _read_divisor(struct clk_hw_omap *clk)
#else
static u32 _read_divisor(struct clk *clk)
#endif
{
	u32 v;

@@ -277,7 +329,12 @@ static u32 _read_divisor(struct clk *clk)
 *
 * Returns the rounded clock rate or returns 0xffffffff on error.
 */
#ifdef CONFIG_COMMON_CLK
u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk,
						 unsigned long target_rate,
#else
u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
#endif
				u32 *new_div)
{
	unsigned long test_rate;
@@ -288,9 +345,14 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
	unsigned long parent_rate;
	const char *clk_name;

#ifdef CONFIG_COMMON_CLK
	parent = __clk_get_parent(clk->hw.clk);
	clk_name = __clk_get_name(clk->hw.clk);
#else
	parent = __clk_get_parent(clk);
	parent_rate = __clk_get_rate(parent);
	clk_name = __clk_get_name(clk);
#endif
	parent_rate = __clk_get_rate(parent);

	if (!clk->clksel || !clk->clksel_mask)
		return ~0;
@@ -340,6 +402,63 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
 * (i.e., those used in struct clk field function pointers, etc.)
 */

#ifdef CONFIG_COMMON_CLK
/**
 * omap2_clksel_find_parent_index() - return the array index of the current
 * hardware parent of @hw
 * @hw: struct clk_hw * to find the current hardware parent of
 *
 * Given a struct clk_hw pointer @hw to the 'hw' member of a struct
 * clk_hw_omap record representing a source-selectable hardware clock,
 * read the hardware register and determine what its parent is
 * currently set to.  Intended to be called only by the common clock
 * framework struct clk_hw_ops.get_parent function pointer.  Return
 * the array index of this parent clock upon success -- there is no
 * way to return an error, so if we encounter an error, just WARN()
 * and pretend that we know that we're doing.
 */
u8 omap2_clksel_find_parent_index(struct clk_hw *hw)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	const struct clksel *clks;
	const struct clksel_rate *clkr;
	u32 r, found = 0;
	struct clk *parent;
	const char *clk_name;
	int ret = 0, f = 0;

	parent = __clk_get_parent(hw->clk);
	clk_name = __clk_get_name(hw->clk);

	/* XXX should be able to return an error */
	WARN((!clk->clksel || !clk->clksel_mask),
	     "clock: %s: attempt to call on a non-clksel clock", clk_name);

	r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
	r >>= __ffs(clk->clksel_mask);

	for (clks = clk->clksel; clks->parent && !found; clks++) {
		for (clkr = clks->rates; clkr->div && !found; clkr++) {
			if (!(clkr->flags & cpu_mask))
				continue;

			if (clkr->val == r) {
				found = 1;
				ret = f;
			}
		}
		f++;
	}

	/* This indicates a data error */
	WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
	     clk_name, r);

	return ret;
}

#else

/**
 * omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr
 * @clk: OMAP clock struct ptr to use
@@ -393,6 +512,8 @@ void omap2_init_clksel_parent(struct clk *clk)
	return;
}

#endif

/**
 * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
 * @clk: struct clk *
@@ -402,6 +523,28 @@ void omap2_init_clksel_parent(struct clk *clk)
 * function.  Returns the clock's current rate, based on its parent's rate
 * and its current divisor setting in the hardware.
 */
#ifdef CONFIG_COMMON_CLK
unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate)
{
	unsigned long rate;
	u32 div = 0;
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);

	if (!parent_rate)
		return 0;

	div = _read_divisor(clk);
	if (!div)
		rate = parent_rate;
	else
		rate = parent_rate / div;

	pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__,
		 __clk_get_name(hw->clk), rate, div);

	return rate;
}
#else
unsigned long omap2_clksel_recalc(struct clk *clk)
{
	unsigned long rate;
@@ -420,6 +563,7 @@ unsigned long omap2_clksel_recalc(struct clk *clk)

	return rate;
}
#endif

/**
 * omap2_clksel_round_rate() - find rounded rate for the given clock and rate
@@ -432,8 +576,15 @@ unsigned long omap2_clksel_recalc(struct clk *clk)
 *
 * Returns the rounded clock rate or returns 0xffffffff on error.
 */
#ifdef CONFIG_COMMON_CLK
long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate,
			unsigned long *parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
#else
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
{
#endif
	u32 new_div;

	return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
@@ -454,8 +605,15 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
 * is changed, they will all be affected without any notification.
 * Returns -EINVAL upon error, or 0 upon success.
 */
#ifdef CONFIG_COMMON_CLK
int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
#else
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
{
#endif
	u32 field_val, validrate, new_div = 0;

	if (!clk->clksel || !clk->clksel_mask)
@@ -471,11 +629,16 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)

	_write_clksel_reg(clk, field_val);

	clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div;

#ifdef CONFIG_COMMON_CLK
	pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(hw->clk),
		 __clk_get_rate(hw->clk));
#else
	pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(clk),
		 __clk_get_rate(clk));

	clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div;
#endif

	return 0;
}

@@ -499,6 +662,18 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
 * affected without any notification.  Returns -EINVAL upon error, or
 * 0 upon success.
 */
#ifdef CONFIG_COMMON_CLK
int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);

	if (!clk->clksel || !clk->clksel_mask)
		return -EINVAL;

	_write_clksel_reg(clk, field_val);
	return 0;
}
#else
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
{
	u32 field_val = 0;
@@ -510,7 +685,6 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
	parent_div = _get_div_and_fieldval(new_parent, clk, &field_val);
	if (!parent_div)
		return -EINVAL;

	_write_clksel_reg(clk, field_val);

	clk_reparent(clk, new_parent);
@@ -520,7 +694,6 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)

	if (parent_div > 0)
		__clk_get_rate(clk) /= parent_div;

	pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
		 __clk_get_name(clk),
		 __clk_get_name(__clk_get_parent(clk)),
@@ -528,3 +701,4 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)

	return 0;
}
#endif
+53 −1
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

#include <linux/kernel.h>
#include <linux/errno.h>
#ifdef CONFIG_COMMON_CLK
#include <linux/clk-provider.h>
#else
#include <linux/clk.h>
#endif
#include <linux/io.h>

#include <asm/div64.h>
@@ -76,7 +80,11 @@
 * (assuming that it is counting N upwards), or -2 if the enclosing loop
 * should skip to the next iteration (again assuming N is increasing).
 */
#ifdef CONFIG_COMMON_CLK
static int _dpll_test_fint(struct clk_hw_omap *clk, u8 n)
#else
static int _dpll_test_fint(struct clk *clk, u8 n)
#endif
{
	struct dpll_data *dd;
	long fint, fint_min, fint_max;
@@ -85,7 +93,11 @@ static int _dpll_test_fint(struct clk *clk, u8 n)
	dd = clk->dpll_data;

	/* DPLL divider must result in a valid jitter correction val */
#ifdef CONFIG_COMMON_CLK
	fint = __clk_get_rate(__clk_get_parent(clk->hw.clk)) / n;
#else
	fint = __clk_get_rate(__clk_get_parent(clk)) / n;
#endif

	if (cpu_is_omap24xx()) {
		/* Should not be called for OMAP2, so warn if it is called */
@@ -186,15 +198,24 @@ static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
}

/* Public functions */

#ifdef CONFIG_COMMON_CLK
u8 omap2_init_dpll_parent(struct clk_hw *hw)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
#else
void omap2_init_dpll_parent(struct clk *clk)
{
#endif
	u32 v;
	struct dpll_data *dd;

	dd = clk->dpll_data;
	if (!dd)
#ifdef CONFIG_COMMON_CLK
		return -EINVAL;
#else
		return;
#endif

	v = __raw_readl(dd->control_reg);
	v &= dd->enable_mask;
@@ -204,18 +225,34 @@ void omap2_init_dpll_parent(struct clk *clk)
	if (cpu_is_omap24xx()) {
		if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
		    v == OMAP2XXX_EN_DPLL_FRBYPASS)
#ifdef CONFIG_COMMON_CLK
			return 1;
#else
			clk_reparent(clk, dd->clk_bypass);
#endif
	} else if (cpu_is_omap34xx()) {
		if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
		    v == OMAP3XXX_EN_DPLL_FRBYPASS)
#ifdef CONFIG_COMMON_CLK
			return 1;
#else
			clk_reparent(clk, dd->clk_bypass);
#endif
	} else if (soc_is_am33xx() || cpu_is_omap44xx()) {
		if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
		    v == OMAP4XXX_EN_DPLL_FRBYPASS ||
		    v == OMAP4XXX_EN_DPLL_MNBYPASS)
#ifdef CONFIG_COMMON_CLK
			return 1;
#else
			clk_reparent(clk, dd->clk_bypass);
#endif
	}
#ifdef CONFIG_COMMON_CLK
	return 0;
#else
	return;
#endif
}

/**
@@ -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
 * if the clock @clk is not a DPLL.
 */
#ifdef CONFIG_COMMON_CLK
unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
#else
u32 omap2_get_dpll_rate(struct clk *clk)
#endif
{
	long long dpll_clk;
	u32 dpll_mult, dpll_div, v;
@@ -288,8 +329,15 @@ u32 omap2_get_dpll_rate(struct clk *clk)
 * (expensive) function again.  Returns ~0 if the target rate cannot
 * be rounded, or the rounded rate upon success.
 */
#ifdef CONFIG_COMMON_CLK
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
		unsigned long *parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
#else
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
{
#endif
	int m, n, r, scaled_max_m;
	unsigned long scaled_rt_rp;
	unsigned long new_rate = 0;
@@ -303,7 +351,11 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
	dd = clk->dpll_data;

	ref_rate = __clk_get_rate(dd->clk_ref);
#ifdef CONFIG_COMMON_CLK
	clk_name = __clk_get_name(hw->clk);
#else
	clk_name = __clk_get_name(clk);
#endif
	pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
		 clk_name, target_rate);

+13 −1
Original line number Diff line number Diff line
@@ -11,7 +11,11 @@
#undef DEBUG

#include <linux/kernel.h>
#ifdef CONFIG_COMMON_CLK
#include <linux/clk-provider.h>
#else
#include <linux/clk.h>
#endif
#include <linux/io.h>


@@ -48,6 +52,14 @@ void omap2_clkt_iclk_deny_idle(struct clk *clk)

/* 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 = {
	.enable		= omap2_dflt_clk_enable,
	.disable	= omap2_dflt_clk_disable,
@@ -77,4 +89,4 @@ const struct clkops clkops_omap2_mdmclk_dflt_wait = {
	.allow_idle	= omap2_clkt_iclk_allow_idle,
	.deny_idle	= omap2_clkt_iclk_deny_idle,
};
#endif
+286 −8
Original line number Diff line number Diff line
@@ -20,7 +20,11 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/delay.h>
#ifdef CONFIG_COMMON_CLK
#include <linux/clk-provider.h>
#else
#include <linux/clk.h>
#endif
#include <linux/io.h>
#include <linux/bitops.h>

@@ -57,7 +61,33 @@ static bool clkdm_control = true;

static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
#ifndef CONFIG_COMMON_CLK
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
@@ -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
 * module-dependent code.  No return value.
 */
#ifdef CONFIG_COMMON_CLK
static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
#else
static void _omap2_module_wait_ready(struct clk *clk)
#endif
{
	void __iomem *companion_reg, *idlest_reg;
	u8 other_bit, idlest_bit, idlest_val, 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);

	r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
	if (r) {
		/* IDLEST register not in the CM module */
		_wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val,
#ifdef CONFIG_COMMON_CLK
				     __clk_get_name(clk->hw.clk));
#else
				     clk->name);
#endif
	} else {
		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
 * called during clk_register().  No return value.
 */
#ifdef CONFIG_COMMON_CLK
void omap2_init_clk_clkdm(struct clk_hw *hw)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
#else
void omap2_init_clk_clkdm(struct clk *clk)
{
#endif
	struct clockdomain *clkdm;
	const char *clk_name;

	if (!clk->clkdm_name)
		return;

#ifdef CONFIG_COMMON_CLK
	clk_name = __clk_get_name(hw->clk);
#else
	clk_name = __clk_get_name(clk);
#endif

	clkdm = clkdm_lookup(clk->clkdm_name);
	if (clkdm) {
@@ -200,8 +247,12 @@ void __init omap2_clk_disable_clkdm_control(void)
 * associate this type of code with per-module data structures to
 * avoid this issue, and remove the casts.  No return value.
 */
void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
				   u8 *other_bit)
#ifdef CONFIG_COMMON_CLK
void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
#else
void omap2_clk_dflt_find_companion(struct clk *clk,
#endif
			void __iomem **other_reg, u8 *other_bit)
{
	u32 r;

@@ -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
 * CM_IDLEST2).  This is not true for all modules.  No return value.
 */
void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
				u8 *idlest_bit, u8 *idlest_val)
#ifdef CONFIG_COMMON_CLK
void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
#else
void omap2_clk_dflt_find_idlest(struct clk *clk,
#endif
		void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val)
{
	u32 r;

@@ -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)
{
	u32 v;
@@ -482,6 +756,8 @@ void omap2_clk_disable_unused(struct clk *clk)
}
#endif

#endif /* CONFIG_COMMON_CLK */

/**
 * omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument
 * @mpurate_ck_name: clk name of the clock to change rate
@@ -512,13 +788,15 @@ int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name)
	r = clk_set_rate(mpurate_ck, mpurate);
	if (IS_ERR_VALUE(r)) {
		WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n",
		     mpurate_ck->name, mpurate, r);
		     mpurate_ck_name, mpurate, r);
		clk_put(mpurate_ck);
		return -EINVAL;
	}

	calibrate_delay();
#ifndef CONFIG_COMMON_CLK
	recalculate_root_clocks();
#endif

	clk_put(mpurate_ck);

@@ -564,8 +842,8 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name,
		(clk_get_rate(mpu_ck) / 1000000));
}

#ifndef CONFIG_COMMON_CLK
/* Common data */

int clk_enable(struct clk *clk)
{
	unsigned long flags;
@@ -1072,4 +1350,4 @@ err_out:
late_initcall(clk_debugfs_init);

#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
#endif /* CONFIG_COMMON_CLK */
+75 −2

File changed.

Preview size limit exceeded, changes collapsed.

Loading