OMAP2+: clockdomain: Add 2 APIs to control clockdomain from hwmod framework

Duplicate the existing API for clockdomain enable from clock to enable
a clock domain from hwmod framework.
This will be needed when the hwmod framework will move from the current
clock centric approach to the module based approach.

These APIs are returning 0 for the moment for OMAP2 and OMAP3 until
their hwmods are updated with the clksm attribute.

Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
This commit is contained in:
Benoit Cousson 2011-07-10 05:56:54 -06:00 committed by Paul Walmsley
parent a5122ff8ce
commit 113a74137f
2 changed files with 116 additions and 43 deletions

View File

@ -796,7 +796,50 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
} }
/* Clockdomain-to-clock framework interface code */ /* Clockdomain-to-clock/hwmod framework interface code */
static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
{
if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
return -EINVAL;
/*
* For arch's with no autodeps, clkcm_clk_enable
* should be called for every clock instance or hwmod that is
* enabled, so the clkdm can be force woken up.
*/
if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps)
return 0;
arch_clkdm->clkdm_clk_enable(clkdm);
pwrdm_wait_transition(clkdm->pwrdm.ptr);
pwrdm_clkdm_state_switch(clkdm);
pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
return 0;
}
static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
{
if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
return -EINVAL;
if (atomic_read(&clkdm->usecount) == 0) {
WARN_ON(1); /* underflow */
return -ERANGE;
}
if (atomic_dec_return(&clkdm->usecount) > 0)
return 0;
arch_clkdm->clkdm_clk_disable(clkdm);
pwrdm_clkdm_state_switch(clkdm);
pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
return 0;
}
/** /**
* clkdm_clk_enable - add an enabled downstream clock to this clkdm * clkdm_clk_enable - add an enabled downstream clock to this clkdm
@ -819,24 +862,10 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
* downstream clocks for debugging purposes? * downstream clocks for debugging purposes?
*/ */
if (!clkdm || !clk) if (!clk)
return -EINVAL; return -EINVAL;
if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable) return _clkdm_clk_hwmod_enable(clkdm);
return -EINVAL;
if (atomic_inc_return(&clkdm->usecount) > 1)
return 0;
/* Clockdomain now has one enabled downstream clock */
pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
clk->name);
arch_clkdm->clkdm_clk_enable(clkdm);
pwrdm_clkdm_state_switch(clkdm);
return 0;
} }
/** /**
@ -849,9 +878,8 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
* clockdomain usecount goes to 0, put the clockdomain to sleep * clockdomain usecount goes to 0, put the clockdomain to sleep
* (software-supervised mode) or remove the clkdm autodependencies * (software-supervised mode) or remove the clkdm autodependencies
* (hardware-supervised mode). Returns -EINVAL if passed null * (hardware-supervised mode). Returns -EINVAL if passed null
* pointers; -ERANGE if the @clkdm usecount underflows and debugging * pointers; -ERANGE if the @clkdm usecount underflows; or returns 0
* is enabled; or returns 0 upon success or if the clockdomain is in * upon success or if the clockdomain is in hwsup idle mode.
* hwsup idle mode.
*/ */
int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
{ {
@ -860,30 +888,72 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
* downstream clocks for debugging purposes? * downstream clocks for debugging purposes?
*/ */
if (!clkdm || !clk) if (!clk)
return -EINVAL; return -EINVAL;
if (!arch_clkdm || !arch_clkdm->clkdm_clk_disable) return _clkdm_clk_hwmod_disable(clkdm);
return -EINVAL; }
#ifdef DEBUG /**
if (atomic_read(&clkdm->usecount) == 0) { * clkdm_hwmod_enable - add an enabled downstream hwmod to this clkdm
WARN_ON(1); /* underflow */ * @clkdm: struct clockdomain *
return -ERANGE; * @oh: struct omap_hwmod * of the enabled downstream hwmod
} *
#endif * Increment the usecount of the clockdomain @clkdm and ensure that it
* is awake before @oh is enabled. Intended to be called by
if (atomic_dec_return(&clkdm->usecount) > 0) * module_enable() code.
return 0; * If the clockdomain is in software-supervised idle mode, force the
* clockdomain to wake. If the clockdomain is in hardware-supervised idle
/* All downstream clocks of this clockdomain are now disabled */ * mode, add clkdm-pwrdm autodependencies, to ensure that devices in the
* clockdomain can be read from/written to by on-chip processors.
pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, * Returns -EINVAL if passed null pointers;
clk->name); * returns 0 upon success or if the clockdomain is in hwsup idle mode.
*/
arch_clkdm->clkdm_clk_disable(clkdm); int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
pwrdm_clkdm_state_switch(clkdm); {
/* The clkdm attribute does not exist yet prior OMAP4 */
return 0; if (cpu_is_omap24xx() || cpu_is_omap34xx())
return 0;
/*
* XXX Rewrite this code to maintain a list of enabled
* downstream hwmods for debugging purposes?
*/
if (!oh)
return -EINVAL;
return _clkdm_clk_hwmod_enable(clkdm);
}
/**
* clkdm_hwmod_disable - remove an enabled downstream hwmod from this clkdm
* @clkdm: struct clockdomain *
* @oh: struct omap_hwmod * of the disabled downstream hwmod
*
* Decrement the usecount of this clockdomain @clkdm when @oh is
* disabled. Intended to be called by module_disable() code.
* If the clockdomain usecount goes to 0, put the clockdomain to sleep
* (software-supervised mode) or remove the clkdm autodependencies
* (hardware-supervised mode).
* Returns -EINVAL if passed null pointers; -ERANGE if the @clkdm usecount
* underflows; or returns 0 upon success or if the clockdomain is in hwsup
* idle mode.
*/
int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
{
/* The clkdm attribute does not exist yet prior OMAP4 */
if (cpu_is_omap24xx() || cpu_is_omap34xx())
return 0;
/*
* XXX Rewrite this code to maintain a list of enabled
* downstream hwmods for debugging purposes?
*/
if (!oh)
return -EINVAL;
return _clkdm_clk_hwmod_disable(clkdm);
} }

View File

@ -20,6 +20,7 @@
#include "powerdomain.h" #include "powerdomain.h"
#include <plat/clock.h> #include <plat/clock.h>
#include <plat/omap_hwmod.h>
#include <plat/cpu.h> #include <plat/cpu.h>
/* /*
@ -183,6 +184,8 @@ int clkdm_sleep(struct clockdomain *clkdm);
int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk); int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh);
int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh);
extern void __init omap2xxx_clockdomains_init(void); extern void __init omap2xxx_clockdomains_init(void);
extern void __init omap3xxx_clockdomains_init(void); extern void __init omap3xxx_clockdomains_init(void);