arm-soc: power management changes
These are various power management related changes, mainly concerning cpuidle on i.MX and OMAP, as well as a the move of the omap smartreflex driver to live in the power subsystem. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIVAwUAUA2dhWCrR//JCVInAQLuqRAA1FxxzAMTESs3/rpjnQmZUUKef4SuJwY2 GBenXFLY5PlxgcrwTbKwepapu8IWfmw171+tRrrMWvQgtBwa+SefwFCaLcRkvRrs kNAHIVI+Gqm4/m6d+WC+ymJLOZdkcTHES+40eycxcjiIElGEMtiW5/qwh060GAgC YxtjoN9BKegjsDLPZdZghO855YUV8CKEg+q5kIYW0Q3Ci0POGvOhgvbI61K5w8z7 fTdbFRDRBqy0BEx9noKTu8XIB/inwlyUY7N3bAv494TsU48kxMIb95FdSGiY/0yV 1883wCacBYBNemWRvWBHNilSsDcuDmM3yNvdwi3JvQnzFBPc8uyze9wbPFOW4aQd Vhf+g8hjuHkw1xreWpO+nREysOjiiSzRUci2nT6aAQTcpWCacVTJ5sW7KOQ63nrH OQpe/fvm/qT8FKPDh/lcrqIUKrHfeFjZx7XlYjw7j0ZL+99mIpwuOql18mQee9G5 OV6c0rfgeTnGLdc1kOlLPElkXe7SQ/GJK1JI1mA5BNYJlVKx+o0qVlcnRzY6bWaP dmSIA+9Bs/fglvmAQHT3u68zn5KfoTbnJWb0v5PQJfitEBdlugKG8nF9mVRIX70X EygOta8vApF9N20WhE2TLLaDhlrOmd4bOtRVdoO8pDVN/hsWIylnEu952ZBSZg3U 9wF0Ydy2LP4= =tgT5 -----END PGP SIGNATURE----- Merge tag 'pm' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull arm-soc power management changes from Arnd Bergmann: "These are various power management related changes, mainly concerning cpuidle on i.MX and OMAP, as well as a the move of the omap smartreflex driver to live in the power subsystem." Fix up conflicts in arch/arm/mach-{imx/mach-imx6q.c,omap2/prm2xxx_3xxx.h} * tag 'pm' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (37 commits) ARM: OMAP2+: PM: fix IRQ_NOAUTOEN removal by mis-merge ARM: OMAP2+: do not allow SmartReflex to be built as a module ARM: OMAP2: Use hwmod to initialize mmc for 2420 ARM: OMAP3: PM: cpuidle: optimize the clkdm idle latency in C1 state ARM: OMAP3: PM: cpuidle: optimize the PER latency in C1 state ARM: OMAP3: PM: cpuidle: default to C1 in next_valid_state ARM: OMAP3: PM: cleanup cam_pwrdm leftovers ARM: OMAP3: PM: call pre/post transition per powerdomain ARM: OMAP2+: powerdomain: allow pre/post transtion to be per pwrdm ARM: OMAP3: PM: Remove IO Daisychain control from cpuidle ARM: OMAP3PLUS: hwmod: reconfigure IO Daisychain during hwmod mux ARM: OMAP3+: PRM: Enable IO wake up ARM: OMAP4: PRM: Add IO Daisychain support ARM: OMAP3: PM: Move IO Daisychain function to omap3 prm file ARM: OMAP3: PM: correct enable/disable of daisy io chain ARM: OMAP2+: PRM: fix compile for OMAP4-only build W1: OMAP HDQ1W: use runtime PM ARM: OMAP2+: HDQ1W: use omap_device W1: OMAP HDQ1W: use 32-bit register accesses W1: OMAP HDQ1W: allow driver to be built on all OMAP2+ ...
This commit is contained in:
commit
a5ebba6b54
46 changed files with 810 additions and 522 deletions
|
@ -279,6 +279,7 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,
|
|||
clk_register_clkdev(clk[dummy], NULL, "imx-keypad");
|
||||
clk_register_clkdev(clk[tve_gate], NULL, "imx-tve.0");
|
||||
clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx-tve.0");
|
||||
clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL);
|
||||
|
||||
/* Set SDHC parents to be PLL2 */
|
||||
clk_set_parent(clk[esdhc_a_sel], clk[pll2_sw]);
|
||||
|
@ -336,7 +337,6 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
|
|||
clk_register_clkdev(clk[mx51_mipi], "mipi_hsp", NULL);
|
||||
clk_register_clkdev(clk[vpu_gate], NULL, "imx51-vpu.0");
|
||||
clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0");
|
||||
clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL);
|
||||
clk_register_clkdev(clk[ipu_gate], "bus", "imx51-ipu");
|
||||
clk_register_clkdev(clk[ipu_di0_gate], "di0", "imx51-ipu");
|
||||
clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx51-ipu");
|
||||
|
|
|
@ -120,6 +120,7 @@ DT_MACHINE_START(IMX53_DT, "Freescale i.MX53 (Device Tree Support)")
|
|||
.handle_irq = imx53_handle_irq,
|
||||
.timer = &imx53_timer,
|
||||
.init_machine = imx53_dt_init,
|
||||
.init_late = imx53_init_late,
|
||||
.dt_compat = imx53_dt_board_compat,
|
||||
.restart = mxc_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
|
@ -24,6 +26,7 @@
|
|||
#include <linux/phy.h>
|
||||
#include <linux/micrel_phy.h>
|
||||
#include <linux/mfd/anatop.h>
|
||||
#include <asm/cpuidle.h>
|
||||
#include <asm/smp_twd.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
|
@ -31,8 +34,10 @@
|
|||
#include <asm/mach/time.h>
|
||||
#include <asm/system_misc.h>
|
||||
#include <mach/common.h>
|
||||
#include <mach/cpuidle.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
|
||||
void imx6q_restart(char mode, const char *cmd)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
@ -169,6 +174,19 @@ static void __init imx6q_init_machine(void)
|
|||
imx6q_usb_init();
|
||||
}
|
||||
|
||||
static struct cpuidle_driver imx6q_cpuidle_driver = {
|
||||
.name = "imx6q_cpuidle",
|
||||
.owner = THIS_MODULE,
|
||||
.en_core_tk_irqen = 1,
|
||||
.states[0] = ARM_CPUIDLE_WFI_STATE,
|
||||
.state_count = 1,
|
||||
};
|
||||
|
||||
static void __init imx6q_init_late(void)
|
||||
{
|
||||
imx_cpuidle_init(&imx6q_cpuidle_driver);
|
||||
}
|
||||
|
||||
static void __init imx6q_map_io(void)
|
||||
{
|
||||
imx_lluart_map_io();
|
||||
|
@ -213,6 +231,7 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)")
|
|||
.handle_irq = imx6q_handle_irq,
|
||||
.timer = &imx6q_timer,
|
||||
.init_machine = imx6q_init_machine,
|
||||
.init_late = imx6q_init_late,
|
||||
.dt_compat = imx6q_dt_compat,
|
||||
.restart = imx6q_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -267,5 +267,6 @@ MACHINE_START(MX53_ARD, "Freescale MX53 ARD Board")
|
|||
.handle_irq = imx53_handle_irq,
|
||||
.timer = &mx53_ard_timer,
|
||||
.init_machine = mx53_ard_board_init,
|
||||
.init_late = imx53_init_late,
|
||||
.restart = mxc_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -174,5 +174,6 @@ MACHINE_START(MX53_EVK, "Freescale MX53 EVK Board")
|
|||
.handle_irq = imx53_handle_irq,
|
||||
.timer = &mx53_evk_timer,
|
||||
.init_machine = mx53_evk_board_init,
|
||||
.init_late = imx53_init_late,
|
||||
.restart = mxc_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -316,5 +316,6 @@ MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board")
|
|||
.handle_irq = imx53_handle_irq,
|
||||
.timer = &mx53_loco_timer,
|
||||
.init_machine = mx53_loco_board_init,
|
||||
.init_late = imx53_init_late,
|
||||
.restart = mxc_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -163,5 +163,6 @@ MACHINE_START(MX53_SMD, "Freescale MX53 SMD Board")
|
|||
.handle_irq = imx53_handle_irq,
|
||||
.timer = &mx53_smd_timer,
|
||||
.init_machine = mx53_smd_board_init,
|
||||
.init_late = imx53_init_late,
|
||||
.restart = mxc_restart,
|
||||
MACHINE_END
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
|
||||
#include <asm/system_misc.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
@ -24,24 +23,6 @@
|
|||
#include <mach/devices-common.h>
|
||||
#include <mach/iomux-v3.h>
|
||||
|
||||
static struct clk *gpc_dvfs_clk;
|
||||
|
||||
static void imx5_idle(void)
|
||||
{
|
||||
/* gpc clock is needed for SRPG */
|
||||
if (gpc_dvfs_clk == NULL) {
|
||||
gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
|
||||
if (IS_ERR(gpc_dvfs_clk))
|
||||
return;
|
||||
clk_prepare(gpc_dvfs_clk);
|
||||
}
|
||||
clk_enable(gpc_dvfs_clk);
|
||||
mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
|
||||
if (!tzic_enable_wake())
|
||||
cpu_do_idle();
|
||||
clk_disable(gpc_dvfs_clk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the MX50 memory map.
|
||||
*/
|
||||
|
@ -105,7 +86,6 @@ void __init imx51_init_early(void)
|
|||
mxc_set_cpu_type(MXC_CPU_MX51);
|
||||
mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
|
||||
mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
|
||||
arm_pm_idle = imx5_idle;
|
||||
}
|
||||
|
||||
void __init imx53_init_early(void)
|
||||
|
@ -243,4 +223,10 @@ void __init imx53_soc_init(void)
|
|||
void __init imx51_init_late(void)
|
||||
{
|
||||
mx51_neon_fixup();
|
||||
imx51_pm_init();
|
||||
}
|
||||
|
||||
void __init imx53_init_late(void)
|
||||
{
|
||||
imx53_pm_init();
|
||||
}
|
||||
|
|
|
@ -12,19 +12,30 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/system_misc.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <mach/common.h>
|
||||
#include <mach/cpuidle.h>
|
||||
#include <mach/hardware.h>
|
||||
#include "crm-regs-imx5.h"
|
||||
|
||||
static struct clk *gpc_dvfs_clk;
|
||||
/*
|
||||
* The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
|
||||
* This is also the lowest power state possible without affecting
|
||||
* non-cpu parts of the system. For these reasons, imx5 should default
|
||||
* to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
|
||||
* uses this state and needs to take no action when registers remain confgiured
|
||||
* for this state.
|
||||
*/
|
||||
#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
|
||||
|
||||
/*
|
||||
* set cpu low power mode before WFI instruction. This function is called
|
||||
* mx5 because it can be used for mx50, mx51, and mx53.
|
||||
*/
|
||||
void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
||||
static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
||||
{
|
||||
u32 plat_lpc, arm_srpgcr, ccm_clpcr;
|
||||
u32 empgc0, empgc1;
|
||||
|
@ -87,11 +98,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
|
|||
}
|
||||
}
|
||||
|
||||
static int mx5_suspend_prepare(void)
|
||||
{
|
||||
return clk_prepare_enable(gpc_dvfs_clk);
|
||||
}
|
||||
|
||||
static int mx5_suspend_enter(suspend_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
|
@ -99,7 +105,7 @@ static int mx5_suspend_enter(suspend_state_t state)
|
|||
mx5_cpu_lp_set(STOP_POWER_OFF);
|
||||
break;
|
||||
case PM_SUSPEND_STANDBY:
|
||||
mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
|
||||
/* DEFAULT_IDLE_STATE already configured */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -114,12 +120,10 @@ static int mx5_suspend_enter(suspend_state_t state)
|
|||
__raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
|
||||
}
|
||||
cpu_do_idle();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mx5_suspend_finish(void)
|
||||
{
|
||||
clk_disable_unprepare(gpc_dvfs_clk);
|
||||
/* return registers to default idle state */
|
||||
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mx5_pm_valid(suspend_state_t state)
|
||||
|
@ -129,25 +133,80 @@ static int mx5_pm_valid(suspend_state_t state)
|
|||
|
||||
static const struct platform_suspend_ops mx5_suspend_ops = {
|
||||
.valid = mx5_pm_valid,
|
||||
.prepare = mx5_suspend_prepare,
|
||||
.enter = mx5_suspend_enter,
|
||||
.finish = mx5_suspend_finish,
|
||||
};
|
||||
|
||||
static int __init mx5_pm_init(void)
|
||||
static inline int imx5_cpu_do_idle(void)
|
||||
{
|
||||
if (!cpu_is_mx51() && !cpu_is_mx53())
|
||||
return 0;
|
||||
int ret = tzic_enable_wake();
|
||||
|
||||
if (gpc_dvfs_clk == NULL)
|
||||
gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
|
||||
if (likely(!ret))
|
||||
cpu_do_idle();
|
||||
|
||||
if (!IS_ERR(gpc_dvfs_clk)) {
|
||||
if (cpu_is_mx51())
|
||||
suspend_set_ops(&mx5_suspend_ops);
|
||||
} else
|
||||
return -EPERM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void imx5_pm_idle(void)
|
||||
{
|
||||
imx5_cpu_do_idle();
|
||||
}
|
||||
|
||||
static int imx5_cpuidle_enter(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int idx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = imx5_cpu_do_idle();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static struct cpuidle_driver imx5_cpuidle_driver = {
|
||||
.name = "imx5_cpuidle",
|
||||
.owner = THIS_MODULE,
|
||||
.en_core_tk_irqen = 1,
|
||||
.states[0] = {
|
||||
.enter = imx5_cpuidle_enter,
|
||||
.exit_latency = 2,
|
||||
.target_residency = 1,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID,
|
||||
.name = "IMX5 SRPG",
|
||||
.desc = "CPU state retained,powered off",
|
||||
},
|
||||
.state_count = 1,
|
||||
};
|
||||
|
||||
static int __init imx5_pm_common_init(void)
|
||||
{
|
||||
int ret;
|
||||
struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
|
||||
|
||||
if (IS_ERR(gpc_dvfs_clk))
|
||||
return PTR_ERR(gpc_dvfs_clk);
|
||||
|
||||
ret = clk_prepare_enable(gpc_dvfs_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
arm_pm_idle = imx5_pm_idle;
|
||||
|
||||
/* Set the registers to the default cpu idle state. */
|
||||
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
|
||||
|
||||
imx_cpuidle_init(&imx5_cpuidle_driver);
|
||||
return 0;
|
||||
}
|
||||
device_initcall(mx5_pm_init);
|
||||
|
||||
void __init imx51_pm_init(void)
|
||||
{
|
||||
int ret = imx5_pm_common_init();
|
||||
if (!ret)
|
||||
suspend_set_ops(&mx5_suspend_ops);
|
||||
}
|
||||
|
||||
void __init imx53_pm_init(void)
|
||||
{
|
||||
imx5_pm_common_init();
|
||||
}
|
||||
|
|
|
@ -74,8 +74,9 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
|
|||
obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o
|
||||
obj-$(CONFIG_SOC_OMAP5) += omap-mpuss-lowpower.o
|
||||
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
|
||||
obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o
|
||||
obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o
|
||||
|
||||
obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
|
||||
obj-$(CONFIG_POWER_AVS_OMAP_CLASS3) += smartreflex-class3.o
|
||||
|
||||
AFLAGS_sleep24xx.o :=-Wa,-march=armv6
|
||||
AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec)
|
||||
|
|
|
@ -75,20 +75,6 @@ static struct omap3_idle_statedata omap3_idle_data[] = {
|
|||
|
||||
static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
|
||||
|
||||
static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
|
||||
struct clockdomain *clkdm)
|
||||
{
|
||||
clkdm_allow_idle(clkdm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
|
||||
struct clockdomain *clkdm)
|
||||
{
|
||||
clkdm_deny_idle(clkdm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __omap3_enter_idle(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
|
@ -106,8 +92,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
|
|||
|
||||
/* Deny idle for C1 */
|
||||
if (index == 0) {
|
||||
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
|
||||
pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
|
||||
clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]);
|
||||
clkdm_deny_idle(core_pd->pwrdm_clkdms[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -129,8 +115,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
|
|||
|
||||
/* Re-allow idle for C1 */
|
||||
if (index == 0) {
|
||||
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
|
||||
pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
|
||||
clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
|
||||
clkdm_allow_idle(core_pd->pwrdm_clkdms[0]);
|
||||
}
|
||||
|
||||
return_sleep_time:
|
||||
|
@ -176,7 +162,7 @@ static int next_valid_state(struct cpuidle_device *dev,
|
|||
u32 mpu_deepest_state = PWRDM_POWER_RET;
|
||||
u32 core_deepest_state = PWRDM_POWER_RET;
|
||||
int idx;
|
||||
int next_index = -1;
|
||||
int next_index = 0; /* C1 is the default value */
|
||||
|
||||
if (enable_off_mode) {
|
||||
mpu_deepest_state = PWRDM_POWER_OFF;
|
||||
|
@ -207,12 +193,6 @@ static int next_valid_state(struct cpuidle_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* C1 is always valid.
|
||||
* So, no need to check for 'next_index == -1' outside
|
||||
* this loop.
|
||||
*/
|
||||
|
||||
return next_index;
|
||||
}
|
||||
|
||||
|
@ -226,23 +206,22 @@ static int next_valid_state(struct cpuidle_device *dev,
|
|||
* the device to the specified or a safer state.
|
||||
*/
|
||||
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
struct cpuidle_driver *drv,
|
||||
int index)
|
||||
{
|
||||
int new_state_idx;
|
||||
u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
|
||||
u32 core_next_state, per_next_state = 0, per_saved_state = 0;
|
||||
struct omap3_idle_statedata *cx;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Prevent idle completely if CAM is active.
|
||||
* Use only C1 if CAM is active.
|
||||
* CAM does not have wakeup capability in OMAP3.
|
||||
*/
|
||||
cam_state = pwrdm_read_pwrst(cam_pd);
|
||||
if (cam_state == PWRDM_POWER_ON) {
|
||||
if (pwrdm_read_pwrst(cam_pd) == PWRDM_POWER_ON)
|
||||
new_state_idx = drv->safe_state_index;
|
||||
goto select_state;
|
||||
}
|
||||
else
|
||||
new_state_idx = next_valid_state(dev, drv, index);
|
||||
|
||||
/*
|
||||
* FIXME: we currently manage device-specific idle states
|
||||
|
@ -252,24 +231,28 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
|
|||
* its own code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Prevent PER off if CORE is not in retention or off as this
|
||||
* would disable PER wakeups completely.
|
||||
*/
|
||||
cx = &omap3_idle_data[index];
|
||||
/* Program PER state */
|
||||
cx = &omap3_idle_data[new_state_idx];
|
||||
core_next_state = cx->core_state;
|
||||
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
|
||||
if ((per_next_state == PWRDM_POWER_OFF) &&
|
||||
(core_next_state > PWRDM_POWER_RET))
|
||||
per_next_state = PWRDM_POWER_RET;
|
||||
if (new_state_idx == 0) {
|
||||
/* In C1 do not allow PER state lower than CORE state */
|
||||
if (per_next_state < core_next_state)
|
||||
per_next_state = core_next_state;
|
||||
} else {
|
||||
/*
|
||||
* Prevent PER OFF if CORE is not in RETention or OFF as this
|
||||
* would disable PER wakeups completely.
|
||||
*/
|
||||
if ((per_next_state == PWRDM_POWER_OFF) &&
|
||||
(core_next_state > PWRDM_POWER_RET))
|
||||
per_next_state = PWRDM_POWER_RET;
|
||||
}
|
||||
|
||||
/* Are we changing PER target state? */
|
||||
if (per_next_state != per_saved_state)
|
||||
pwrdm_set_next_pwrst(per_pd, per_next_state);
|
||||
|
||||
new_state_idx = next_valid_state(dev, drv, index);
|
||||
|
||||
select_state:
|
||||
ret = omap3_enter_idle(dev, drv, new_state_idx);
|
||||
|
||||
/* Restore original PER state if it was modified */
|
||||
|
@ -286,7 +269,7 @@ struct cpuidle_driver omap3_idle_driver = {
|
|||
.owner = THIS_MODULE,
|
||||
.states = {
|
||||
{
|
||||
.enter = omap3_enter_idle,
|
||||
.enter = omap3_enter_idle_bm,
|
||||
.exit_latency = 2 + 2,
|
||||
.target_residency = 5,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID,
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
|
||||
#include "iomap.h"
|
||||
#include <plat/board.h>
|
||||
#include <plat/mmc.h>
|
||||
#include <plat/dma.h>
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/omap_device.h>
|
||||
|
@ -603,112 +602,6 @@ static inline void omap_init_aes(void) { }
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
|
||||
|
||||
static inline void omap242x_mmc_mux(struct omap_mmc_platform_data
|
||||
*mmc_controller)
|
||||
{
|
||||
if ((mmc_controller->slots[0].switch_pin > 0) && \
|
||||
(mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES))
|
||||
omap_mux_init_gpio(mmc_controller->slots[0].switch_pin,
|
||||
OMAP_PIN_INPUT_PULLUP);
|
||||
if ((mmc_controller->slots[0].gpio_wp > 0) && \
|
||||
(mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES))
|
||||
omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp,
|
||||
OMAP_PIN_INPUT_PULLUP);
|
||||
|
||||
omap_mux_init_signal("sdmmc_cmd", 0);
|
||||
omap_mux_init_signal("sdmmc_clki", 0);
|
||||
omap_mux_init_signal("sdmmc_clko", 0);
|
||||
omap_mux_init_signal("sdmmc_dat0", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir0", 0);
|
||||
omap_mux_init_signal("sdmmc_cmd_dir", 0);
|
||||
if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
|
||||
omap_mux_init_signal("sdmmc_dat1", 0);
|
||||
omap_mux_init_signal("sdmmc_dat2", 0);
|
||||
omap_mux_init_signal("sdmmc_dat3", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir1", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir2", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir3", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use internal loop-back in MMC/SDIO Module Input Clock
|
||||
* selection
|
||||
*/
|
||||
if (mmc_controller->slots[0].internal_clock) {
|
||||
u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
|
||||
v |= (1 << 24);
|
||||
omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
|
||||
}
|
||||
}
|
||||
|
||||
void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct omap_hwmod *oh;
|
||||
int id = 0;
|
||||
char *oh_name = "msdi1";
|
||||
char *dev_name = "mmci-omap";
|
||||
|
||||
if (!mmc_data[0]) {
|
||||
pr_err("%s fails: Incomplete platform data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
omap242x_mmc_mux(mmc_data[0]);
|
||||
|
||||
oh = omap_hwmod_lookup(oh_name);
|
||||
if (!oh) {
|
||||
pr_err("Could not look up %s\n", oh_name);
|
||||
return;
|
||||
}
|
||||
pdev = omap_device_build(dev_name, id, oh, mmc_data[0],
|
||||
sizeof(struct omap_mmc_platform_data), NULL, 0, 0);
|
||||
if (IS_ERR(pdev))
|
||||
WARN(1, "Can'd build omap_device for %s:%s.\n",
|
||||
dev_name, oh->name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
|
||||
#define OMAP_HDQ_BASE 0x480B2000
|
||||
static struct resource omap_hdq_resources[] = {
|
||||
{
|
||||
.start = OMAP_HDQ_BASE,
|
||||
.end = OMAP_HDQ_BASE + 0x1C,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = INT_24XX_HDQ_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
static struct platform_device omap_hdq_dev = {
|
||||
.name = "omap_hdq",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = NULL,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(omap_hdq_resources),
|
||||
.resource = omap_hdq_resources,
|
||||
};
|
||||
static inline void omap_hdq_init(void)
|
||||
{
|
||||
if (cpu_is_omap2420())
|
||||
return;
|
||||
|
||||
platform_device_register(&omap_hdq_dev);
|
||||
}
|
||||
#else
|
||||
static inline void omap_hdq_init(void) {}
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_VIDEO_OMAP2_VOUT) || \
|
||||
defined(CONFIG_VIDEO_OMAP2_VOUT_MODULE)
|
||||
#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
|
||||
|
@ -753,7 +646,6 @@ static int __init omap2_init_devices(void)
|
|||
omap_init_mcspi();
|
||||
}
|
||||
omap_init_pmu();
|
||||
omap_hdq_init();
|
||||
omap_init_sti();
|
||||
omap_init_sham();
|
||||
omap_init_aes();
|
||||
|
|
|
@ -22,7 +22,13 @@
|
|||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/omap_device.h>
|
||||
#include <plat/hdq1w.h>
|
||||
|
||||
#include "common.h"
|
||||
|
@ -70,3 +76,23 @@ int omap_hdq1w_reset(struct omap_hwmod *oh)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init omap_init_hdq(void)
|
||||
{
|
||||
int id = -1;
|
||||
struct platform_device *pdev;
|
||||
struct omap_hwmod *oh;
|
||||
char *oh_name = "hdq1w";
|
||||
char *devname = "omap_hdq";
|
||||
|
||||
oh = omap_hwmod_lookup(oh_name);
|
||||
if (!oh)
|
||||
return 0;
|
||||
|
||||
pdev = omap_device_build(devname, id, oh, NULL, 0, NULL, 0, 0);
|
||||
WARN(IS_ERR(pdev), "Can't build omap_device for %s:%s.\n",
|
||||
devname, oh->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(omap_init_hdq);
|
||||
|
|
|
@ -22,11 +22,15 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/omap_device.h>
|
||||
#include <plat/mmc.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "control.h"
|
||||
#include "mux.h"
|
||||
|
||||
/*
|
||||
* MSDI_CON_OFFSET: offset in bytes of the MSDI IP block's CON register
|
||||
|
@ -86,3 +90,72 @@ int omap_msdi_reset(struct omap_hwmod *oh)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
|
||||
|
||||
static inline void omap242x_mmc_mux(struct omap_mmc_platform_data
|
||||
*mmc_controller)
|
||||
{
|
||||
if ((mmc_controller->slots[0].switch_pin > 0) && \
|
||||
(mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES))
|
||||
omap_mux_init_gpio(mmc_controller->slots[0].switch_pin,
|
||||
OMAP_PIN_INPUT_PULLUP);
|
||||
if ((mmc_controller->slots[0].gpio_wp > 0) && \
|
||||
(mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES))
|
||||
omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp,
|
||||
OMAP_PIN_INPUT_PULLUP);
|
||||
|
||||
omap_mux_init_signal("sdmmc_cmd", 0);
|
||||
omap_mux_init_signal("sdmmc_clki", 0);
|
||||
omap_mux_init_signal("sdmmc_clko", 0);
|
||||
omap_mux_init_signal("sdmmc_dat0", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir0", 0);
|
||||
omap_mux_init_signal("sdmmc_cmd_dir", 0);
|
||||
if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
|
||||
omap_mux_init_signal("sdmmc_dat1", 0);
|
||||
omap_mux_init_signal("sdmmc_dat2", 0);
|
||||
omap_mux_init_signal("sdmmc_dat3", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir1", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir2", 0);
|
||||
omap_mux_init_signal("sdmmc_dat_dir3", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use internal loop-back in MMC/SDIO Module Input Clock
|
||||
* selection
|
||||
*/
|
||||
if (mmc_controller->slots[0].internal_clock) {
|
||||
u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
|
||||
v |= (1 << 24);
|
||||
omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
|
||||
}
|
||||
}
|
||||
|
||||
void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct omap_hwmod *oh;
|
||||
int id = 0;
|
||||
char *oh_name = "msdi1";
|
||||
char *dev_name = "mmci-omap";
|
||||
|
||||
if (!mmc_data[0]) {
|
||||
pr_err("%s fails: Incomplete platform data\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
omap242x_mmc_mux(mmc_data[0]);
|
||||
|
||||
oh = omap_hwmod_lookup(oh_name);
|
||||
if (!oh) {
|
||||
pr_err("Could not look up %s\n", oh_name);
|
||||
return;
|
||||
}
|
||||
pdev = omap_device_build(dev_name, id, oh, mmc_data[0],
|
||||
sizeof(struct omap_mmc_platform_data), NULL, 0, 0);
|
||||
if (IS_ERR(pdev))
|
||||
WARN(1, "Can'd build omap_device for %s:%s.\n",
|
||||
dev_name, oh->name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -255,7 +255,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
pwrdm_pre_transition();
|
||||
pwrdm_pre_transition(NULL);
|
||||
|
||||
/*
|
||||
* Check MPUSS next state and save interrupt controller if needed.
|
||||
|
@ -287,7 +287,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
|
|||
wakeup_cpu = smp_processor_id();
|
||||
set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);
|
||||
|
||||
pwrdm_post_transition();
|
||||
pwrdm_post_transition(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -153,6 +153,7 @@
|
|||
#include "prm44xx.h"
|
||||
#include "prminst44xx.h"
|
||||
#include "mux.h"
|
||||
#include "pm.h"
|
||||
|
||||
/* Maximum microseconds to wait for OMAP module to softreset */
|
||||
#define MAX_MODULE_SOFTRESET_WAIT 10000
|
||||
|
@ -197,6 +198,9 @@ static LIST_HEAD(omap_hwmod_list);
|
|||
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
|
||||
static struct omap_hwmod *mpu_oh;
|
||||
|
||||
/* io_chain_lock: used to serialize reconfigurations of the I/O chain */
|
||||
static DEFINE_SPINLOCK(io_chain_lock);
|
||||
|
||||
/*
|
||||
* linkspace: ptr to a buffer that struct omap_hwmod_link records are
|
||||
* allocated from - used to reduce the number of small memory
|
||||
|
@ -1758,6 +1762,32 @@ static int _reset(struct omap_hwmod *oh)
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* _reconfigure_io_chain - clear any I/O chain wakeups and reconfigure chain
|
||||
*
|
||||
* Call the appropriate PRM function to clear any logged I/O chain
|
||||
* wakeups and to reconfigure the chain. This apparently needs to be
|
||||
* done upon every mux change. Since hwmods can be concurrently
|
||||
* enabled and idled, hold a spinlock around the I/O chain
|
||||
* reconfiguration sequence. No return value.
|
||||
*
|
||||
* XXX When the PRM code is moved to drivers, this function can be removed,
|
||||
* as the PRM infrastructure should abstract this.
|
||||
*/
|
||||
static void _reconfigure_io_chain(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&io_chain_lock, flags);
|
||||
|
||||
if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl())
|
||||
omap3xxx_prm_reconfigure_io_chain();
|
||||
else if (cpu_is_omap44xx())
|
||||
omap44xx_prm_reconfigure_io_chain();
|
||||
|
||||
spin_unlock_irqrestore(&io_chain_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* _enable - enable an omap_hwmod
|
||||
* @oh: struct omap_hwmod *
|
||||
|
@ -1814,8 +1844,10 @@ static int _enable(struct omap_hwmod *oh)
|
|||
/* Mux pins for device runtime if populated */
|
||||
if (oh->mux && (!oh->mux->enabled ||
|
||||
((oh->_state == _HWMOD_STATE_IDLE) &&
|
||||
oh->mux->pads_dynamic)))
|
||||
oh->mux->pads_dynamic))) {
|
||||
omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
|
||||
_reconfigure_io_chain();
|
||||
}
|
||||
|
||||
_add_initiator_dep(oh, mpu_oh);
|
||||
|
||||
|
@ -1907,8 +1939,10 @@ static int _idle(struct omap_hwmod *oh)
|
|||
clkdm_hwmod_disable(oh->clkdm, oh);
|
||||
|
||||
/* Mux pins for device idle if populated */
|
||||
if (oh->mux && oh->mux->pads_dynamic)
|
||||
if (oh->mux && oh->mux->pads_dynamic) {
|
||||
omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
|
||||
_reconfigure_io_chain();
|
||||
}
|
||||
|
||||
oh->_state = _HWMOD_STATE_IDLE;
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
*
|
||||
* XXX these should be marked initdata for multi-OMAP kernels
|
||||
*/
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <plat/cpu.h>
|
||||
|
@ -29,8 +31,6 @@
|
|||
#include <plat/dmtimer.h>
|
||||
|
||||
#include "omap_hwmod_common_data.h"
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include "prm-regbits-34xx.h"
|
||||
#include "cm-regbits-34xx.h"
|
||||
#include "wd_timer.h"
|
||||
|
@ -1357,7 +1357,7 @@ static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
|
|||
};
|
||||
|
||||
static struct omap_hwmod omap34xx_sr1_hwmod = {
|
||||
.name = "sr1",
|
||||
.name = "smartreflex_mpu_iva",
|
||||
.class = &omap34xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr1_fck",
|
||||
.prcm = {
|
||||
|
@ -1375,7 +1375,7 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
|
|||
};
|
||||
|
||||
static struct omap_hwmod omap36xx_sr1_hwmod = {
|
||||
.name = "sr1",
|
||||
.name = "smartreflex_mpu_iva",
|
||||
.class = &omap36xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr1_fck",
|
||||
.prcm = {
|
||||
|
@ -1402,7 +1402,7 @@ static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
|
|||
};
|
||||
|
||||
static struct omap_hwmod omap34xx_sr2_hwmod = {
|
||||
.name = "sr2",
|
||||
.name = "smartreflex_core",
|
||||
.class = &omap34xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr2_fck",
|
||||
.prcm = {
|
||||
|
@ -1420,7 +1420,7 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
|
|||
};
|
||||
|
||||
static struct omap_hwmod omap36xx_sr2_hwmod = {
|
||||
.name = "sr2",
|
||||
.name = "smartreflex_core",
|
||||
.class = &omap36xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr2_fck",
|
||||
.prcm = {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/cpu.h>
|
||||
|
@ -32,8 +33,6 @@
|
|||
#include <plat/common.h>
|
||||
|
||||
#include "omap_hwmod_common_data.h"
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include "cm1_44xx.h"
|
||||
#include "cm2_44xx.h"
|
||||
#include "prm44xx.h"
|
||||
|
|
|
@ -101,7 +101,7 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
|
|||
static inline void enable_omap3630_toggle_l2_on_restore(void) { }
|
||||
#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
|
||||
|
||||
#ifdef CONFIG_OMAP_SMARTREFLEX
|
||||
#ifdef CONFIG_POWER_AVS_OMAP
|
||||
extern int omap_devinit_smartreflex(void);
|
||||
extern void omap_enable_smartreflex_on_init(void);
|
||||
#else
|
||||
|
|
|
@ -70,34 +70,6 @@ void (*omap3_do_wfi_sram)(void);
|
|||
|
||||
static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
|
||||
static struct powerdomain *core_pwrdm, *per_pwrdm;
|
||||
static struct powerdomain *cam_pwrdm;
|
||||
|
||||
static void omap3_enable_io_chain(void)
|
||||
{
|
||||
int timeout = 0;
|
||||
|
||||
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
|
||||
PM_WKEN);
|
||||
/* Do a readback to assure write has been done */
|
||||
omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
|
||||
|
||||
while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
|
||||
OMAP3430_ST_IO_CHAIN_MASK)) {
|
||||
timeout++;
|
||||
if (timeout > 1000) {
|
||||
pr_err("Wake up daisy chain activation failed.\n");
|
||||
return;
|
||||
}
|
||||
omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
|
||||
WKUP_MOD, PM_WKEN);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap3_disable_io_chain(void)
|
||||
{
|
||||
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
|
||||
PM_WKEN);
|
||||
}
|
||||
|
||||
static void omap3_core_save_context(void)
|
||||
{
|
||||
|
@ -299,24 +271,22 @@ void omap_sram_idle(void)
|
|||
/* Enable IO-PAD and IO-CHAIN wakeups */
|
||||
per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
|
||||
core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
|
||||
if (omap3_has_io_wakeup() &&
|
||||
(per_next_state < PWRDM_POWER_ON ||
|
||||
core_next_state < PWRDM_POWER_ON)) {
|
||||
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
|
||||
if (omap3_has_io_chain_ctrl())
|
||||
omap3_enable_io_chain();
|
||||
}
|
||||
|
||||
pwrdm_pre_transition();
|
||||
if (mpu_next_state < PWRDM_POWER_ON) {
|
||||
pwrdm_pre_transition(mpu_pwrdm);
|
||||
pwrdm_pre_transition(neon_pwrdm);
|
||||
}
|
||||
|
||||
/* PER */
|
||||
if (per_next_state < PWRDM_POWER_ON) {
|
||||
pwrdm_pre_transition(per_pwrdm);
|
||||
per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
|
||||
omap2_gpio_prepare_for_idle(per_going_off);
|
||||
}
|
||||
|
||||
/* CORE */
|
||||
if (core_next_state < PWRDM_POWER_ON) {
|
||||
pwrdm_pre_transition(core_pwrdm);
|
||||
if (core_next_state == PWRDM_POWER_OFF) {
|
||||
omap3_core_save_context();
|
||||
omap3_cm_save_context();
|
||||
|
@ -369,26 +339,20 @@ void omap_sram_idle(void)
|
|||
omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
|
||||
OMAP3430_GR_MOD,
|
||||
OMAP3_PRM_VOLTCTRL_OFFSET);
|
||||
pwrdm_post_transition(core_pwrdm);
|
||||
}
|
||||
omap3_intc_resume_idle();
|
||||
|
||||
pwrdm_post_transition();
|
||||
|
||||
/* PER */
|
||||
if (per_next_state < PWRDM_POWER_ON)
|
||||
if (per_next_state < PWRDM_POWER_ON) {
|
||||
omap2_gpio_resume_after_idle();
|
||||
|
||||
/* Disable IO-PAD and IO-CHAIN wakeup */
|
||||
if (omap3_has_io_wakeup() &&
|
||||
(per_next_state < PWRDM_POWER_ON ||
|
||||
core_next_state < PWRDM_POWER_ON)) {
|
||||
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
|
||||
PM_WKEN);
|
||||
if (omap3_has_io_chain_ctrl())
|
||||
omap3_disable_io_chain();
|
||||
pwrdm_post_transition(per_pwrdm);
|
||||
}
|
||||
|
||||
clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
|
||||
if (mpu_next_state < PWRDM_POWER_ON) {
|
||||
pwrdm_post_transition(mpu_pwrdm);
|
||||
pwrdm_post_transition(neon_pwrdm);
|
||||
}
|
||||
}
|
||||
|
||||
static void omap3_pm_idle(void)
|
||||
|
@ -754,7 +718,6 @@ int __init omap3_pm_init(void)
|
|||
neon_pwrdm = pwrdm_lookup("neon_pwrdm");
|
||||
per_pwrdm = pwrdm_lookup("per_pwrdm");
|
||||
core_pwrdm = pwrdm_lookup("core_pwrdm");
|
||||
cam_pwrdm = pwrdm_lookup("cam_pwrdm");
|
||||
|
||||
neon_clkdm = clkdm_lookup("neon_clkdm");
|
||||
mpu_clkdm = clkdm_lookup("mpu_clkdm");
|
||||
|
|
|
@ -985,15 +985,23 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int pwrdm_pre_transition(void)
|
||||
int pwrdm_pre_transition(struct powerdomain *pwrdm)
|
||||
{
|
||||
pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
|
||||
if (pwrdm)
|
||||
_pwrdm_pre_transition_cb(pwrdm, NULL);
|
||||
else
|
||||
pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pwrdm_post_transition(void)
|
||||
int pwrdm_post_transition(struct powerdomain *pwrdm)
|
||||
{
|
||||
pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
|
||||
if (pwrdm)
|
||||
_pwrdm_post_transition_cb(pwrdm, NULL);
|
||||
else
|
||||
pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -230,8 +230,8 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
|
|||
int pwrdm_wait_transition(struct powerdomain *pwrdm);
|
||||
|
||||
int pwrdm_state_switch(struct powerdomain *pwrdm);
|
||||
int pwrdm_pre_transition(void);
|
||||
int pwrdm_post_transition(void);
|
||||
int pwrdm_pre_transition(struct powerdomain *pwrdm);
|
||||
int pwrdm_post_transition(struct powerdomain *pwrdm);
|
||||
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
|
||||
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
|
||||
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
|
||||
|
|
|
@ -410,6 +410,14 @@
|
|||
*/
|
||||
#define MAX_MODULE_HARDRESET_WAIT 10000
|
||||
|
||||
/*
|
||||
* Maximum time(us) it takes to output the signal WUCLKOUT of the last
|
||||
* pad of the I/O ring after asserting WUCLKIN high. Tero measured
|
||||
* the actual time at 7 to 8 microseconds on OMAP3 and 2 to 4
|
||||
* microseconds on OMAP4, so this timeout may be too high.
|
||||
*/
|
||||
#define MAX_IOPAD_LATCH_TIME 100
|
||||
|
||||
# ifndef __ASSEMBLER__
|
||||
extern void __iomem *prm_base;
|
||||
extern void __iomem *cm_base;
|
||||
|
|
|
@ -302,11 +302,59 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
|
|||
OMAP3_PRM_IRQENABLE_MPU_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
|
||||
*
|
||||
* Clear any previously-latched I/O wakeup events and ensure that the
|
||||
* I/O wakeup gates are aligned with the current mux settings. Works
|
||||
* by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then
|
||||
* deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No
|
||||
* return value.
|
||||
*/
|
||||
void omap3xxx_prm_reconfigure_io_chain(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
|
||||
PM_WKEN);
|
||||
|
||||
omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
|
||||
OMAP3430_ST_IO_CHAIN_MASK,
|
||||
MAX_IOPAD_LATCH_TIME, i);
|
||||
if (i == MAX_IOPAD_LATCH_TIME)
|
||||
pr_warn("PRM: I/O chain clock line assertion timed out\n");
|
||||
|
||||
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
|
||||
PM_WKEN);
|
||||
|
||||
omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD,
|
||||
PM_WKST);
|
||||
|
||||
omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
|
||||
*
|
||||
* Activates the I/O wakeup event latches and allows events logged by
|
||||
* those latches to signal a wakeup event to the PRCM. For I/O
|
||||
* wakeups to occur, WAKEUPENABLE bits must be set in the pad mux
|
||||
* registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
|
||||
* No return value.
|
||||
*/
|
||||
static void __init omap3xxx_prm_enable_io_wakeup(void)
|
||||
{
|
||||
if (omap3_has_io_wakeup())
|
||||
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
|
||||
PM_WKEN);
|
||||
}
|
||||
|
||||
static int __init omap3xxx_prcm_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
omap3xxx_prm_enable_io_wakeup();
|
||||
ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
|
||||
if (!ret)
|
||||
irq_set_status_flags(omap_prcm_event_to_irq("io"),
|
||||
|
|
|
@ -253,12 +253,15 @@ extern u32 omap3_prm_vcvp_read(u8 offset);
|
|||
extern void omap3_prm_vcvp_write(u32 val, u8 offset);
|
||||
extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
|
||||
|
||||
extern void omap3xxx_prm_reconfigure_io_chain(void);
|
||||
|
||||
/* PRM interrupt-related functions */
|
||||
extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
|
||||
extern void omap3xxx_prm_ocp_barrier(void);
|
||||
extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
|
||||
extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLER */
|
||||
|
||||
/*
|
||||
* Bits common to specific registers
|
||||
|
|
|
@ -233,10 +233,71 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
|
|||
OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap44xx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
|
||||
*
|
||||
* Clear any previously-latched I/O wakeup events and ensure that the
|
||||
* I/O wakeup gates are aligned with the current mux settings. Works
|
||||
* by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then
|
||||
* deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted.
|
||||
* No return value. XXX Are the final two steps necessary?
|
||||
*/
|
||||
void omap44xx_prm_reconfigure_io_chain(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Trigger WUCLKIN enable */
|
||||
omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK,
|
||||
OMAP4430_WUCLK_CTRL_MASK,
|
||||
OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET);
|
||||
omap_test_timeout(
|
||||
(((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET) &
|
||||
OMAP4430_WUCLK_STATUS_MASK) >>
|
||||
OMAP4430_WUCLK_STATUS_SHIFT) == 1),
|
||||
MAX_IOPAD_LATCH_TIME, i);
|
||||
if (i == MAX_IOPAD_LATCH_TIME)
|
||||
pr_warn("PRM: I/O chain clock line assertion timed out\n");
|
||||
|
||||
/* Trigger WUCLKIN disable */
|
||||
omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, 0x0,
|
||||
OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET);
|
||||
omap_test_timeout(
|
||||
(((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET) &
|
||||
OMAP4430_WUCLK_STATUS_MASK) >>
|
||||
OMAP4430_WUCLK_STATUS_SHIFT) == 0),
|
||||
MAX_IOPAD_LATCH_TIME, i);
|
||||
if (i == MAX_IOPAD_LATCH_TIME)
|
||||
pr_warn("PRM: I/O chain clock line deassertion timed out\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap44xx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
|
||||
*
|
||||
* Activates the I/O wakeup event latches and allows events logged by
|
||||
* those latches to signal a wakeup event to the PRCM. For I/O wakeups
|
||||
* to occur, WAKEUPENABLE bits must be set in the pad mux registers, and
|
||||
* omap44xx_prm_reconfigure_io_chain() must be called. No return value.
|
||||
*/
|
||||
static void __init omap44xx_prm_enable_io_wakeup(void)
|
||||
{
|
||||
omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
|
||||
OMAP4430_GLOBAL_WUEN_MASK,
|
||||
OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET);
|
||||
}
|
||||
|
||||
static int __init omap4xxx_prcm_init(void)
|
||||
{
|
||||
if (cpu_is_omap44xx())
|
||||
if (cpu_is_omap44xx()) {
|
||||
omap44xx_prm_enable_io_wakeup();
|
||||
return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(omap4xxx_prcm_init);
|
||||
|
|
|
@ -763,6 +763,8 @@ extern u32 omap4_prm_vcvp_read(u8 offset);
|
|||
extern void omap4_prm_vcvp_write(u32 val, u8 offset);
|
||||
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
|
||||
|
||||
extern void omap44xx_prm_reconfigure_io_chain(void);
|
||||
|
||||
/* PRM interrupt-related functions */
|
||||
extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
|
||||
extern void omap44xx_prm_ocp_barrier(void);
|
||||
|
|
|
@ -11,36 +11,37 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include <linux/power/smartreflex.h>
|
||||
#include "voltage.h"
|
||||
|
||||
static int sr_class3_enable(struct voltagedomain *voltdm)
|
||||
static int sr_class3_enable(struct omap_sr *sr)
|
||||
{
|
||||
unsigned long volt = voltdm_get_voltage(voltdm);
|
||||
unsigned long volt = voltdm_get_voltage(sr->voltdm);
|
||||
|
||||
if (!volt) {
|
||||
pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: Curr voltage unknown. Cannot enable %s\n",
|
||||
__func__, sr->name);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
omap_vp_enable(voltdm);
|
||||
return sr_enable(voltdm, volt);
|
||||
omap_vp_enable(sr->voltdm);
|
||||
return sr_enable(sr->voltdm, volt);
|
||||
}
|
||||
|
||||
static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
|
||||
static int sr_class3_disable(struct omap_sr *sr, int is_volt_reset)
|
||||
{
|
||||
sr_disable_errgen(voltdm);
|
||||
omap_vp_disable(voltdm);
|
||||
sr_disable(voltdm);
|
||||
sr_disable_errgen(sr->voltdm);
|
||||
omap_vp_disable(sr->voltdm);
|
||||
sr_disable(sr->voltdm);
|
||||
if (is_volt_reset)
|
||||
voltdm_reset(voltdm);
|
||||
voltdm_reset(sr->voltdm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_class3_configure(struct voltagedomain *voltdm)
|
||||
static int sr_class3_configure(struct omap_sr *sr)
|
||||
{
|
||||
return sr_configure_errgen(voltdm);
|
||||
return sr_configure_errgen(sr->voltdm);
|
||||
}
|
||||
|
||||
/* SR class3 structure */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -24,7 +25,6 @@
|
|||
|
||||
#include <plat/omap_device.h>
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include "voltage.h"
|
||||
#include "control.h"
|
||||
#include "pm.h"
|
||||
|
@ -36,7 +36,10 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
|
|||
struct omap_sr_data *sr_data)
|
||||
{
|
||||
struct omap_sr_nvalue_table *nvalue_table;
|
||||
int i, count = 0;
|
||||
int i, j, count = 0;
|
||||
|
||||
sr_data->nvalue_count = 0;
|
||||
sr_data->nvalue_table = NULL;
|
||||
|
||||
while (volt_data[count].volt_nominal)
|
||||
count++;
|
||||
|
@ -44,8 +47,14 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
|
|||
nvalue_table = kzalloc(sizeof(struct omap_sr_nvalue_table)*count,
|
||||
GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!nvalue_table) {
|
||||
pr_err("OMAP: SmartReflex: cannot allocate memory for n-value table\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < count; i++) {
|
||||
u32 v;
|
||||
|
||||
/*
|
||||
* In OMAP4 the efuse registers are 24 bit aligned.
|
||||
* A __raw_readl will fail for non-32 bit aligned address
|
||||
|
@ -58,15 +67,30 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
|
|||
omap_ctrl_readb(offset + 1) << 8 |
|
||||
omap_ctrl_readb(offset + 2) << 16;
|
||||
} else {
|
||||
v = omap_ctrl_readl(volt_data[i].sr_efuse_offs);
|
||||
v = omap_ctrl_readl(volt_data[i].sr_efuse_offs);
|
||||
}
|
||||
|
||||
nvalue_table[i].efuse_offs = volt_data[i].sr_efuse_offs;
|
||||
nvalue_table[i].nvalue = v;
|
||||
/*
|
||||
* Many OMAP SoCs don't have the eFuse values set.
|
||||
* For example, pretty much all OMAP3xxx before
|
||||
* ES3.something.
|
||||
*
|
||||
* XXX There needs to be some way for board files or
|
||||
* userspace to add these in.
|
||||
*/
|
||||
if (v == 0)
|
||||
continue;
|
||||
|
||||
nvalue_table[j].nvalue = v;
|
||||
nvalue_table[j].efuse_offs = volt_data[i].sr_efuse_offs;
|
||||
nvalue_table[j].errminlimit = volt_data[i].sr_errminlimit;
|
||||
nvalue_table[j].volt_nominal = volt_data[i].volt_nominal;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
sr_data->nvalue_table = nvalue_table;
|
||||
sr_data->nvalue_count = count;
|
||||
sr_data->nvalue_count = j;
|
||||
}
|
||||
|
||||
static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
|
||||
|
@ -93,6 +117,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
sr_data->name = oh->name;
|
||||
sr_data->ip_type = oh->class->rev;
|
||||
sr_data->senn_mod = 0x1;
|
||||
sr_data->senp_mod = 0x1;
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <plat/voltage.h>
|
||||
|
||||
#include "vc.h"
|
||||
#include "vp.h"
|
||||
|
||||
|
@ -90,25 +92,6 @@ struct voltagedomain {
|
|||
struct omap_volt_data *volt_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct omap_volt_data - Omap voltage specific data.
|
||||
* @voltage_nominal: The possible voltage value in uV
|
||||
* @sr_efuse_offs: The offset of the efuse register(from system
|
||||
* control module base address) from where to read
|
||||
* the n-target value for the smartreflex module.
|
||||
* @sr_errminlimit: Error min limit value for smartreflex. This value
|
||||
* differs at differnet opp and thus is linked
|
||||
* with voltage.
|
||||
* @vp_errorgain: Error gain value for the voltage processor. This
|
||||
* field also differs according to the voltage/opp.
|
||||
*/
|
||||
struct omap_volt_data {
|
||||
u32 volt_nominal;
|
||||
u32 sr_efuse_offs;
|
||||
u8 sr_errminlimit;
|
||||
u8 vp_errgain;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct omap_voltdm_pmic - PMIC specific data required by voltage driver.
|
||||
* @slew_rate: PMIC slew rate (in uv/us)
|
||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_MXC_ULPI) += ulpi.o
|
|||
obj-$(CONFIG_MXC_USE_EPIT) += epit.o
|
||||
obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
|
||||
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
ifdef CONFIG_SND_IMX_SOC
|
||||
obj-y += ssi-fiq.o
|
||||
obj-y += ssi-fiq-ksym.o
|
||||
|
|
80
arch/arm/plat-mxc/cpuidle.c
Normal file
80
arch/arm/plat-mxc/cpuidle.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2012 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static struct cpuidle_device __percpu * imx_cpuidle_devices;
|
||||
|
||||
static void __init imx_cpuidle_devices_uninit(void)
|
||||
{
|
||||
int cpu_id;
|
||||
struct cpuidle_device *dev;
|
||||
|
||||
for_each_possible_cpu(cpu_id) {
|
||||
dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
|
||||
cpuidle_unregister_device(dev);
|
||||
}
|
||||
|
||||
free_percpu(imx_cpuidle_devices);
|
||||
}
|
||||
|
||||
int __init imx_cpuidle_init(struct cpuidle_driver *drv)
|
||||
{
|
||||
struct cpuidle_device *dev;
|
||||
int cpu_id, ret;
|
||||
|
||||
if (drv->state_count > CPUIDLE_STATE_MAX) {
|
||||
pr_err("%s: state_count exceeds maximum\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = cpuidle_register_driver(drv);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to register cpuidle driver with error: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
imx_cpuidle_devices = alloc_percpu(struct cpuidle_device);
|
||||
if (imx_cpuidle_devices == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto unregister_drv;
|
||||
}
|
||||
|
||||
/* initialize state data for each cpuidle_device */
|
||||
for_each_possible_cpu(cpu_id) {
|
||||
dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
|
||||
dev->cpu = cpu_id;
|
||||
dev->state_count = drv->state_count;
|
||||
|
||||
ret = cpuidle_register_device(dev);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to register cpu %u, error: %d\n",
|
||||
__func__, cpu_id, ret);
|
||||
goto uninit;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
uninit:
|
||||
imx_cpuidle_devices_uninit();
|
||||
|
||||
unregister_drv:
|
||||
cpuidle_unregister_driver(drv);
|
||||
return ret;
|
||||
}
|
|
@ -54,6 +54,7 @@ extern void imx50_soc_init(void);
|
|||
extern void imx51_soc_init(void);
|
||||
extern void imx53_soc_init(void);
|
||||
extern void imx51_init_late(void);
|
||||
extern void imx53_init_late(void);
|
||||
extern void epit_timer_init(void __iomem *base, int irq);
|
||||
extern void mxc_timer_init(void __iomem *, int);
|
||||
extern int mx1_clocks_init(unsigned long fref);
|
||||
|
@ -96,7 +97,6 @@ enum mx3_cpu_pwr_mode {
|
|||
};
|
||||
|
||||
extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
|
||||
extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
|
||||
extern void imx_print_silicon_rev(const char *cpu, int srev);
|
||||
|
||||
void avic_handle_irq(struct pt_regs *);
|
||||
|
@ -147,8 +147,12 @@ extern void imx6q_clock_map_io(void);
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
extern void imx6q_pm_init(void);
|
||||
extern void imx51_pm_init(void);
|
||||
extern void imx53_pm_init(void);
|
||||
#else
|
||||
static inline void imx6q_pm_init(void) {}
|
||||
static inline void imx51_pm_init(void) {}
|
||||
static inline void imx53_pm_init(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NEON
|
||||
|
|
22
arch/arm/plat-mxc/include/mach/cpuidle.h
Normal file
22
arch/arm/plat-mxc/include/mach/cpuidle.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2012 Linaro Ltd.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/cpuidle.h>
|
||||
|
||||
#ifdef CONFIG_CPU_IDLE
|
||||
extern int imx_cpuidle_init(struct cpuidle_driver *drv);
|
||||
#else
|
||||
static inline int imx_cpuidle_init(struct cpuidle_driver *drv)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
|
@ -50,7 +50,7 @@
|
|||
* IO 0x00200000+0x100000 -> 0xf4000000+0x100000
|
||||
* mx21:
|
||||
* AIPI 0x10000000+0x100000 -> 0xf4400000+0x100000
|
||||
* SAHB1 0x80000000+0x100000 -> 0xf4000000+0x100000
|
||||
* SAHB1 0x80000000+0x100000 -> 0xf5000000+0x100000
|
||||
* X_MEMC 0xdf000000+0x004000 -> 0xf5f00000+0x004000
|
||||
* mx25:
|
||||
* AIPS1 0x43f00000+0x100000 -> 0xf5300000+0x100000
|
||||
|
@ -58,47 +58,50 @@
|
|||
* AVIC 0x68000000+0x100000 -> 0xf5800000+0x100000
|
||||
* mx27:
|
||||
* AIPI 0x10000000+0x100000 -> 0xf4400000+0x100000
|
||||
* SAHB1 0x80000000+0x100000 -> 0xf4000000+0x100000
|
||||
* SAHB1 0x80000000+0x100000 -> 0xf5000000+0x100000
|
||||
* X_MEMC 0xd8000000+0x100000 -> 0xf5c00000+0x100000
|
||||
* mx31:
|
||||
* AIPS1 0x43f00000+0x100000 -> 0xf5300000+0x100000
|
||||
* AIPS2 0x53f00000+0x100000 -> 0xf5700000+0x100000
|
||||
* AVIC 0x68000000+0x100000 -> 0xf5800000+0x100000
|
||||
* X_MEMC 0xb8000000+0x010000 -> 0xf4c00000+0x010000
|
||||
* X_MEMC 0xb8000000+0x010000 -> 0xf5c00000+0x010000
|
||||
* SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
|
||||
* mx35:
|
||||
* AIPS1 0x43f00000+0x100000 -> 0xf5300000+0x100000
|
||||
* AIPS2 0x53f00000+0x100000 -> 0xf5700000+0x100000
|
||||
* AVIC 0x68000000+0x100000 -> 0xf5800000+0x100000
|
||||
* X_MEMC 0xb8000000+0x010000 -> 0xf4c00000+0x010000
|
||||
* X_MEMC 0xb8000000+0x010000 -> 0xf5c00000+0x010000
|
||||
* SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
|
||||
* mx50:
|
||||
* TZIC 0x0fffc000+0x004000 -> 0xf4bfc000+0x004000
|
||||
* SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
|
||||
* AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000
|
||||
* SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
|
||||
* AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000
|
||||
* mx51:
|
||||
* TZIC 0xe0000000+0x004000 -> 0xf5000000+0x004000
|
||||
* TZIC 0x0fffc000+0x004000 -> 0xf4bfc000+0x004000
|
||||
* IRAM 0x1ffe0000+0x020000 -> 0xf4fe0000+0x020000
|
||||
* DEBUG 0x60000000+0x100000 -> 0xf5000000+0x100000
|
||||
* SPBA0 0x70000000+0x100000 -> 0xf5400000+0x100000
|
||||
* AIPS1 0x73f00000+0x100000 -> 0xf5700000+0x100000
|
||||
* AIPS2 0x83f00000+0x100000 -> 0xf4300000+0x100000
|
||||
* AIPS2 0x83f00000+0x100000 -> 0xf5300000+0x100000
|
||||
* mx53:
|
||||
* TZIC 0x0fffc000+0x004000 -> 0xf4bfc000+0x004000
|
||||
* DEBUG 0x40000000+0x100000 -> 0xf5000000+0x100000
|
||||
* SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
|
||||
* AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000
|
||||
* AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000
|
||||
* mx6q:
|
||||
* SCU 0x00a00000+0x001000 -> 0xf4000000+0x001000
|
||||
* SCU 0x00a00000+0x004000 -> 0xf4000000+0x004000
|
||||
* CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000
|
||||
* ANATOP 0x020c8000+0x001000 -> 0xf42c8000+0x001000
|
||||
* ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000
|
||||
* UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000
|
||||
*/
|
||||
#define IMX_IO_P2V(x) ( \
|
||||
0xf4000000 + \
|
||||
(((x) & 0x80000000) >> 7) | \
|
||||
(0xf4000000 + \
|
||||
(((x) & 0x50000000) >> 6) + \
|
||||
(((x) & 0x0b000000) >> 4) + \
|
||||
(((x) & 0x000fffff)))
|
||||
(((x) & 0x000fffff))))
|
||||
|
||||
#define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x))
|
||||
|
||||
|
|
|
@ -202,6 +202,10 @@ void __init tzic_init_irq(void __iomem *irqbase)
|
|||
* tzic_enable_wake() - enable wakeup interrupt
|
||||
*
|
||||
* @return 0 if successful; non-zero otherwise
|
||||
*
|
||||
* This function provides an interrupt synchronization point that is required
|
||||
* by tzic enabled platforms before entering imx specific low power modes (ie,
|
||||
* those low power modes beyond the WAIT_CLOCKED basic ARM WFI only mode).
|
||||
*/
|
||||
int tzic_enable_wake(void)
|
||||
{
|
||||
|
|
|
@ -45,31 +45,30 @@ config OMAP_DEBUG_LEDS
|
|||
depends on OMAP_DEBUG_DEVICES
|
||||
default y if LEDS_CLASS
|
||||
|
||||
config OMAP_SMARTREFLEX
|
||||
bool "SmartReflex support"
|
||||
depends on (ARCH_OMAP3 || ARCH_OMAP4) && PM
|
||||
config POWER_AVS_OMAP
|
||||
bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
|
||||
depends on POWER_AVS && (ARCH_OMAP3 || ARCH_OMAP4) && PM
|
||||
help
|
||||
Say Y if you want to enable SmartReflex.
|
||||
|
||||
SmartReflex can perform continuous dynamic voltage
|
||||
scaling around the nominal operating point voltage
|
||||
according to silicon characteristics and operating
|
||||
conditions. Enabling SmartReflex reduces power
|
||||
consumption.
|
||||
Say Y to enable AVS(Adaptive Voltage Scaling)
|
||||
support on OMAP containing the version 1 or
|
||||
version 2 of the SmartReflex IP.
|
||||
V1 is the 65nm version used in OMAP3430.
|
||||
V2 is the update for the 45nm version of the IP used in OMAP3630
|
||||
and OMAP4430
|
||||
|
||||
Please note, that by default SmartReflex is only
|
||||
initialized. To enable the automatic voltage
|
||||
compensation for vdd mpu and vdd core from user space,
|
||||
initialized and not enabled. To enable the automatic voltage
|
||||
compensation for vdd mpu and vdd core from user space,
|
||||
user must write 1 to
|
||||
/debug/voltage/vdd_<X>/smartreflex/autocomp,
|
||||
where X is mpu or core for OMAP3.
|
||||
/debug/smartreflex/sr_<X>/autocomp,
|
||||
where X is mpu_iva or core for OMAP3.
|
||||
Optionally autocompensation can be enabled in the kernel
|
||||
by default during system init via the enable_on_init flag
|
||||
which an be passed as platform data to the smartreflex driver.
|
||||
|
||||
config OMAP_SMARTREFLEX_CLASS3
|
||||
config POWER_AVS_OMAP_CLASS3
|
||||
bool "Class 3 mode of Smartreflex Implementation"
|
||||
depends on OMAP_SMARTREFLEX && TWL4030_CORE
|
||||
depends on POWER_AVS_OMAP && TWL4030_CORE
|
||||
help
|
||||
Say Y to enable Class 3 implementation of Smartreflex
|
||||
|
||||
|
|
|
@ -11,10 +11,29 @@
|
|||
#ifndef __ARCH_ARM_OMAP_VOLTAGE_H
|
||||
#define __ARCH_ARM_OMAP_VOLTAGE_H
|
||||
|
||||
/**
|
||||
* struct omap_volt_data - Omap voltage specific data.
|
||||
* @voltage_nominal: The possible voltage value in uV
|
||||
* @sr_efuse_offs: The offset of the efuse register(from system
|
||||
* control module base address) from where to read
|
||||
* the n-target value for the smartreflex module.
|
||||
* @sr_errminlimit: Error min limit value for smartreflex. This value
|
||||
* differs at differnet opp and thus is linked
|
||||
* with voltage.
|
||||
* @vp_errorgain: Error gain value for the voltage processor. This
|
||||
* field also differs according to the voltage/opp.
|
||||
*/
|
||||
struct omap_volt_data {
|
||||
u32 volt_nominal;
|
||||
u32 sr_efuse_offs;
|
||||
u8 sr_errminlimit;
|
||||
u8 vp_errgain;
|
||||
};
|
||||
struct voltagedomain;
|
||||
|
||||
struct voltagedomain *voltdm_lookup(const char *name);
|
||||
int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt);
|
||||
unsigned long voltdm_get_voltage(struct voltagedomain *voltdm);
|
||||
|
||||
struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
|
||||
unsigned long volt);
|
||||
#endif
|
||||
|
|
|
@ -310,3 +310,5 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
|
|||
Say Y to enable battery temperature measurements using
|
||||
thermistor connected on BATCTRL ADC.
|
||||
endif # POWER_SUPPLY
|
||||
|
||||
source "drivers/power/avs/Kconfig"
|
||||
|
|
|
@ -43,4 +43,5 @@ obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
|
|||
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
|
||||
|
|
12
drivers/power/avs/Kconfig
Normal file
12
drivers/power/avs/Kconfig
Normal file
|
@ -0,0 +1,12 @@
|
|||
menuconfig POWER_AVS
|
||||
bool "Adaptive Voltage Scaling class support"
|
||||
help
|
||||
AVS is a power management technique which finely controls the
|
||||
operating voltage of a device in order to optimize (i.e. reduce)
|
||||
its power consumption.
|
||||
At a given operating point the voltage is adapted depending on
|
||||
static factors (chip manufacturing process) and dynamic factors
|
||||
(temperature depending performance).
|
||||
AVS is also called SmartReflex on OMAP devices.
|
||||
|
||||
Say Y here to enable Adaptive Voltage Scaling class support.
|
1
drivers/power/avs/Makefile
Normal file
1
drivers/power/avs/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Author: Thara Gopinath <thara@ti.com>
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||
* Thara Gopinath <thara@ti.com>
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
|
@ -25,39 +25,12 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "pm.h"
|
||||
#include "smartreflex.h"
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#define SMARTREFLEX_NAME_LEN 16
|
||||
#define NVALUE_NAME_LEN 40
|
||||
#define SR_DISABLE_TIMEOUT 200
|
||||
|
||||
struct omap_sr {
|
||||
struct list_head node;
|
||||
struct platform_device *pdev;
|
||||
struct omap_sr_nvalue_table *nvalue_table;
|
||||
struct voltagedomain *voltdm;
|
||||
struct dentry *dbg_dir;
|
||||
unsigned int irq;
|
||||
int srid;
|
||||
int ip_type;
|
||||
int nvalue_count;
|
||||
bool autocomp_active;
|
||||
u32 clk_length;
|
||||
u32 err_weight;
|
||||
u32 err_minlimit;
|
||||
u32 err_maxlimit;
|
||||
u32 accum_data;
|
||||
u32 senn_avgweight;
|
||||
u32 senp_avgweight;
|
||||
u32 senp_mod;
|
||||
u32 senn_mod;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
/* sr_list contains all the instances of smartreflex module */
|
||||
static LIST_HEAD(sr_list);
|
||||
|
||||
|
@ -148,7 +121,7 @@ static irqreturn_t sr_interrupt(int irq, void *data)
|
|||
}
|
||||
|
||||
if (sr_class->notify)
|
||||
sr_class->notify(sr_info->voltdm, status);
|
||||
sr_class->notify(sr_info, status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -207,7 +180,7 @@ static void sr_set_regfields(struct omap_sr *sr)
|
|||
sr->err_weight = OMAP3430_SR_ERRWEIGHT;
|
||||
sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
|
||||
sr->accum_data = OMAP3430_SR_ACCUMDATA;
|
||||
if (!(strcmp(sr->voltdm->name, "mpu"))) {
|
||||
if (!(strcmp(sr->name, "smartreflex_mpu_iva"))) {
|
||||
sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
|
||||
sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
|
||||
} else {
|
||||
|
@ -226,7 +199,7 @@ static void sr_start_vddautocomp(struct omap_sr *sr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!sr_class->enable(sr->voltdm))
|
||||
if (!sr_class->enable(sr))
|
||||
sr->autocomp_active = true;
|
||||
}
|
||||
|
||||
|
@ -240,7 +213,7 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
|
|||
}
|
||||
|
||||
if (sr->autocomp_active) {
|
||||
sr_class->disable(sr->voltdm, 1);
|
||||
sr_class->disable(sr, 1);
|
||||
sr->autocomp_active = false;
|
||||
}
|
||||
}
|
||||
|
@ -258,19 +231,13 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
|
|||
*/
|
||||
static int sr_late_init(struct omap_sr *sr_info)
|
||||
{
|
||||
char *name;
|
||||
struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
|
||||
struct resource *mem;
|
||||
int ret = 0;
|
||||
|
||||
if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
|
||||
name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
|
||||
if (name == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
ret = request_irq(sr_info->irq, sr_interrupt,
|
||||
0, name, sr_info);
|
||||
0, sr_info->name, sr_info);
|
||||
if (ret)
|
||||
goto error;
|
||||
disable_irq(sr_info->irq);
|
||||
|
@ -289,7 +256,6 @@ static int sr_late_init(struct omap_sr *sr_info)
|
|||
dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
|
||||
"interrupt handler. Smartreflex will"
|
||||
"not function as desired\n", __func__);
|
||||
kfree(name);
|
||||
kfree(sr_info);
|
||||
|
||||
return ret;
|
||||
|
@ -320,9 +286,9 @@ static void sr_v1_disable(struct omap_sr *sr)
|
|||
* Wait for SR to be disabled.
|
||||
* wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
|
||||
*/
|
||||
omap_test_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
|
||||
ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
sr_test_cond_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
|
||||
ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
|
||||
if (timeout >= SR_DISABLE_TIMEOUT)
|
||||
dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
|
||||
|
@ -365,9 +331,9 @@ static void sr_v2_disable(struct omap_sr *sr)
|
|||
* Wait for SR to be disabled.
|
||||
* wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
|
||||
*/
|
||||
omap_test_timeout((sr_read_reg(sr, IRQSTATUS) &
|
||||
IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
sr_test_cond_timeout((sr_read_reg(sr, IRQSTATUS) &
|
||||
IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
|
||||
if (timeout >= SR_DISABLE_TIMEOUT)
|
||||
dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
|
||||
|
@ -378,22 +344,23 @@ static void sr_v2_disable(struct omap_sr *sr)
|
|||
sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
|
||||
}
|
||||
|
||||
static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
|
||||
static struct omap_sr_nvalue_table *sr_retrieve_nvalue_row(
|
||||
struct omap_sr *sr, u32 efuse_offs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!sr->nvalue_table) {
|
||||
dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
|
||||
__func__);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < sr->nvalue_count; i++) {
|
||||
if (sr->nvalue_table[i].efuse_offs == efuse_offs)
|
||||
return sr->nvalue_table[i].nvalue;
|
||||
return &sr->nvalue_table[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Public Functions */
|
||||
|
@ -419,8 +386,7 @@ int sr_configure_errgen(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
|
@ -487,8 +453,7 @@ int sr_disable_errgen(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
|
@ -538,8 +503,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
|
@ -620,12 +584,11 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
|
|||
{
|
||||
struct omap_volt_data *volt_data;
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
u32 nvalue_reciprocal;
|
||||
struct omap_sr_nvalue_table *nvalue_row;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
|
@ -637,16 +600,16 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
|
|||
return PTR_ERR(volt_data);
|
||||
}
|
||||
|
||||
nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
|
||||
nvalue_row = sr_retrieve_nvalue_row(sr, volt_data->sr_efuse_offs);
|
||||
|
||||
if (!nvalue_reciprocal) {
|
||||
dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n",
|
||||
__func__, volt);
|
||||
if (!nvalue_row) {
|
||||
dev_warn(&sr->pdev->dev, "%s: failure getting SR data for this voltage %ld\n",
|
||||
__func__, volt);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* errminlimit is opp dependent and hence linked to voltage */
|
||||
sr->err_minlimit = volt_data->sr_errminlimit;
|
||||
sr->err_minlimit = nvalue_row->errminlimit;
|
||||
|
||||
pm_runtime_get_sync(&sr->pdev->dev);
|
||||
|
||||
|
@ -655,11 +618,11 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
|
|||
return 0;
|
||||
|
||||
/* Configure SR */
|
||||
ret = sr_class->configure(voltdm);
|
||||
ret = sr_class->configure(sr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
|
||||
sr_write_reg(sr, NVALUERECIPROCAL, nvalue_row->nvalue);
|
||||
|
||||
/* SRCONFIG - enable SR */
|
||||
sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
|
||||
|
@ -678,8 +641,7 @@ void sr_disable(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -759,8 +721,7 @@ void omap_sr_enable(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -773,7 +734,7 @@ void omap_sr_enable(struct voltagedomain *voltdm)
|
|||
return;
|
||||
}
|
||||
|
||||
sr_class->enable(voltdm);
|
||||
sr_class->enable(sr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -792,8 +753,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -806,7 +766,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
|
|||
return;
|
||||
}
|
||||
|
||||
sr_class->disable(voltdm, 0);
|
||||
sr_class->disable(sr, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -825,8 +785,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
|
|||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -839,7 +798,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
|
|||
return;
|
||||
}
|
||||
|
||||
sr_class->disable(voltdm, 1);
|
||||
sr_class->disable(sr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -911,9 +870,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
|||
struct omap_sr_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *mem, *irq;
|
||||
struct dentry *nvalue_dir;
|
||||
struct omap_volt_data *volt_data;
|
||||
int i, ret = 0;
|
||||
char *name;
|
||||
|
||||
sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
|
||||
if (!sr_info) {
|
||||
|
@ -950,6 +907,14 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
|||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
|
||||
sr_info->name = kasprintf(GFP_KERNEL, "%s", pdata->name);
|
||||
if (!sr_info->name) {
|
||||
dev_err(&pdev->dev, "%s: Unable to alloc SR instance name\n",
|
||||
__func__);
|
||||
ret = -ENOMEM;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
sr_info->pdev = pdev;
|
||||
sr_info->srid = pdev->id;
|
||||
sr_info->voltdm = pdata->voltdm;
|
||||
|
@ -997,20 +962,12 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
|
||||
if (!name) {
|
||||
dev_err(&pdev->dev, "%s: Unable to alloc debugfs name\n",
|
||||
__func__);
|
||||
ret = -ENOMEM;
|
||||
goto err_iounmap;
|
||||
}
|
||||
sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
|
||||
kfree(name);
|
||||
sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir);
|
||||
if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
|
||||
dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
|
||||
__func__);
|
||||
ret = PTR_ERR(sr_info->dbg_dir);
|
||||
goto err_iounmap;
|
||||
goto err_free_name;
|
||||
}
|
||||
|
||||
(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
|
||||
|
@ -1019,8 +976,6 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
|||
&sr_info->err_weight);
|
||||
(void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
|
||||
&sr_info->err_maxlimit);
|
||||
(void) debugfs_create_x32("errminlimit", S_IRUGO, sr_info->dbg_dir,
|
||||
&sr_info->err_minlimit);
|
||||
|
||||
nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
|
||||
if (IS_ERR_OR_NULL(nvalue_dir)) {
|
||||
|
@ -1030,12 +985,10 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
|||
goto err_debugfs;
|
||||
}
|
||||
|
||||
omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
|
||||
if (!volt_data) {
|
||||
dev_warn(&pdev->dev, "%s: No Voltage table for the"
|
||||
" corresponding vdd vdd_%s. Cannot create debugfs"
|
||||
"entries for n-values\n",
|
||||
__func__, sr_info->voltdm->name);
|
||||
if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) {
|
||||
dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n",
|
||||
__func__, sr_info->name);
|
||||
|
||||
ret = -ENODATA;
|
||||
goto err_debugfs;
|
||||
}
|
||||
|
@ -1043,16 +996,23 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < sr_info->nvalue_count; i++) {
|
||||
char name[NVALUE_NAME_LEN + 1];
|
||||
|
||||
snprintf(name, sizeof(name), "volt_%d",
|
||||
volt_data[i].volt_nominal);
|
||||
snprintf(name, sizeof(name), "volt_%lu",
|
||||
sr_info->nvalue_table[i].volt_nominal);
|
||||
(void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
|
||||
&(sr_info->nvalue_table[i].nvalue));
|
||||
snprintf(name, sizeof(name), "errminlimit_%lu",
|
||||
sr_info->nvalue_table[i].volt_nominal);
|
||||
(void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
|
||||
&(sr_info->nvalue_table[i].errminlimit));
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_debugfs:
|
||||
debugfs_remove_recursive(sr_info->dbg_dir);
|
||||
err_free_name:
|
||||
kfree(sr_info->name);
|
||||
err_iounmap:
|
||||
list_del(&sr_info->node);
|
||||
iounmap(sr_info->base);
|
||||
|
@ -1089,6 +1049,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
|
|||
|
||||
list_del(&sr_info->node);
|
||||
iounmap(sr_info->base);
|
||||
kfree(sr_info->name);
|
||||
kfree(sr_info);
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(mem->start, resource_size(mem));
|
|
@ -60,7 +60,7 @@ config W1_MASTER_GPIO
|
|||
|
||||
config HDQ_MASTER_OMAP
|
||||
tristate "OMAP HDQ driver"
|
||||
depends on SOC_OMAP2430 || ARCH_OMAP3
|
||||
depends on ARCH_OMAP2PLUS
|
||||
help
|
||||
Say Y here if you want support for the 1-wire or HDQ Interface
|
||||
on an OMAP processor.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* drivers/w1/masters/omap_hdq.c
|
||||
*
|
||||
* Copyright (C) 2007 Texas Instruments, Inc.
|
||||
* Copyright (C) 2007,2012 Texas Instruments, Inc.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
|
@ -14,9 +14,9 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <mach/hardware.h>
|
||||
|
@ -61,8 +61,6 @@ struct hdq_data {
|
|||
/* lock status update */
|
||||
struct mutex hdq_mutex;
|
||||
int hdq_usecount;
|
||||
struct clk *hdq_ick;
|
||||
struct clk *hdq_fck;
|
||||
u8 hdq_irqstatus;
|
||||
/* device lock */
|
||||
spinlock_t hdq_spinlock;
|
||||
|
@ -102,20 +100,20 @@ static struct w1_bus_master omap_w1_master = {
|
|||
/* HDQ register I/O routines */
|
||||
static inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset)
|
||||
{
|
||||
return __raw_readb(hdq_data->hdq_base + offset);
|
||||
return __raw_readl(hdq_data->hdq_base + offset);
|
||||
}
|
||||
|
||||
static inline void hdq_reg_out(struct hdq_data *hdq_data, u32 offset, u8 val)
|
||||
{
|
||||
__raw_writeb(val, hdq_data->hdq_base + offset);
|
||||
__raw_writel(val, hdq_data->hdq_base + offset);
|
||||
}
|
||||
|
||||
static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
|
||||
u8 val, u8 mask)
|
||||
{
|
||||
u8 new_val = (__raw_readb(hdq_data->hdq_base + offset) & ~mask)
|
||||
u8 new_val = (__raw_readl(hdq_data->hdq_base + offset) & ~mask)
|
||||
| (val & mask);
|
||||
__raw_writeb(new_val, hdq_data->hdq_base + offset);
|
||||
__raw_writel(new_val, hdq_data->hdq_base + offset);
|
||||
|
||||
return new_val;
|
||||
}
|
||||
|
@ -419,17 +417,8 @@ static int omap_hdq_get(struct hdq_data *hdq_data)
|
|||
hdq_data->hdq_usecount++;
|
||||
try_module_get(THIS_MODULE);
|
||||
if (1 == hdq_data->hdq_usecount) {
|
||||
if (clk_enable(hdq_data->hdq_ick)) {
|
||||
dev_dbg(hdq_data->dev, "Can not enable ick\n");
|
||||
ret = -ENODEV;
|
||||
goto clk_err;
|
||||
}
|
||||
if (clk_enable(hdq_data->hdq_fck)) {
|
||||
dev_dbg(hdq_data->dev, "Can not enable fck\n");
|
||||
clk_disable(hdq_data->hdq_ick);
|
||||
ret = -ENODEV;
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(hdq_data->dev);
|
||||
|
||||
/* make sure HDQ is out of reset */
|
||||
if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
|
||||
|
@ -450,9 +439,6 @@ static int omap_hdq_get(struct hdq_data *hdq_data)
|
|||
}
|
||||
}
|
||||
|
||||
clk_err:
|
||||
clk_put(hdq_data->hdq_ick);
|
||||
clk_put(hdq_data->hdq_fck);
|
||||
out:
|
||||
mutex_unlock(&hdq_data->hdq_mutex);
|
||||
rtn:
|
||||
|
@ -475,10 +461,8 @@ static int omap_hdq_put(struct hdq_data *hdq_data)
|
|||
} else {
|
||||
hdq_data->hdq_usecount--;
|
||||
module_put(THIS_MODULE);
|
||||
if (0 == hdq_data->hdq_usecount) {
|
||||
clk_disable(hdq_data->hdq_ick);
|
||||
clk_disable(hdq_data->hdq_fck);
|
||||
}
|
||||
if (0 == hdq_data->hdq_usecount)
|
||||
pm_runtime_put_sync(hdq_data->dev);
|
||||
}
|
||||
mutex_unlock(&hdq_data->hdq_mutex);
|
||||
|
||||
|
@ -591,35 +575,11 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
|
|||
goto err_ioremap;
|
||||
}
|
||||
|
||||
/* get interface & functional clock objects */
|
||||
hdq_data->hdq_ick = clk_get(&pdev->dev, "ick");
|
||||
if (IS_ERR(hdq_data->hdq_ick)) {
|
||||
dev_dbg(&pdev->dev, "Can't get HDQ ick clock object\n");
|
||||
ret = PTR_ERR(hdq_data->hdq_ick);
|
||||
goto err_ick;
|
||||
}
|
||||
|
||||
hdq_data->hdq_fck = clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(hdq_data->hdq_fck)) {
|
||||
dev_dbg(&pdev->dev, "Can't get HDQ fck clock object\n");
|
||||
ret = PTR_ERR(hdq_data->hdq_fck);
|
||||
goto err_fck;
|
||||
}
|
||||
|
||||
hdq_data->hdq_usecount = 0;
|
||||
mutex_init(&hdq_data->hdq_mutex);
|
||||
|
||||
if (clk_enable(hdq_data->hdq_ick)) {
|
||||
dev_dbg(&pdev->dev, "Can not enable ick\n");
|
||||
ret = -ENODEV;
|
||||
goto err_intfclk;
|
||||
}
|
||||
|
||||
if (clk_enable(hdq_data->hdq_fck)) {
|
||||
dev_dbg(&pdev->dev, "Can not enable fck\n");
|
||||
ret = -ENODEV;
|
||||
goto err_fnclk;
|
||||
}
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
|
||||
dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
|
||||
|
@ -641,9 +601,7 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
|
|||
|
||||
omap_hdq_break(hdq_data);
|
||||
|
||||
/* don't clock the HDQ until it is needed */
|
||||
clk_disable(hdq_data->hdq_ick);
|
||||
clk_disable(hdq_data->hdq_fck);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
omap_w1_master.data = hdq_data;
|
||||
|
||||
|
@ -655,20 +613,11 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_w1:
|
||||
err_irq:
|
||||
clk_disable(hdq_data->hdq_fck);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
err_w1:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
err_fnclk:
|
||||
clk_disable(hdq_data->hdq_ick);
|
||||
|
||||
err_intfclk:
|
||||
clk_put(hdq_data->hdq_fck);
|
||||
|
||||
err_fck:
|
||||
clk_put(hdq_data->hdq_ick);
|
||||
|
||||
err_ick:
|
||||
iounmap(hdq_data->hdq_base);
|
||||
|
||||
err_ioremap:
|
||||
|
@ -696,8 +645,7 @@ static int omap_hdq_remove(struct platform_device *pdev)
|
|||
mutex_unlock(&hdq_data->hdq_mutex);
|
||||
|
||||
/* remove module dependency */
|
||||
clk_put(hdq_data->hdq_ick);
|
||||
clk_put(hdq_data->hdq_fck);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_irq(INT_24XX_HDQ_IRQ, hdq_data);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
iounmap(hdq_data->hdq_base);
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_OMAP_SMARTREFLEX_H
|
||||
#define __ASM_ARM_OMAP_SMARTREFLEX_H
|
||||
#ifndef __POWER_SMARTREFLEX_H
|
||||
#define __POWER_SMARTREFLEX_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "voltage.h"
|
||||
#include <linux/delay.h>
|
||||
#include <plat/voltage.h>
|
||||
|
||||
/*
|
||||
* Different Smartreflex IPs version. The v1 is the 65nm version used in
|
||||
|
@ -142,6 +143,51 @@
|
|||
#define OMAP3430_SR_ERRWEIGHT 0x04
|
||||
#define OMAP3430_SR_ERRMAXLIMIT 0x02
|
||||
|
||||
struct omap_sr {
|
||||
char *name;
|
||||
struct list_head node;
|
||||
struct platform_device *pdev;
|
||||
struct omap_sr_nvalue_table *nvalue_table;
|
||||
struct voltagedomain *voltdm;
|
||||
struct dentry *dbg_dir;
|
||||
unsigned int irq;
|
||||
int srid;
|
||||
int ip_type;
|
||||
int nvalue_count;
|
||||
bool autocomp_active;
|
||||
u32 clk_length;
|
||||
u32 err_weight;
|
||||
u32 err_minlimit;
|
||||
u32 err_maxlimit;
|
||||
u32 accum_data;
|
||||
u32 senn_avgweight;
|
||||
u32 senp_avgweight;
|
||||
u32 senp_mod;
|
||||
u32 senn_mod;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
/**
|
||||
* test_cond_timeout - busy-loop, testing a condition
|
||||
* @cond: condition to test until it evaluates to true
|
||||
* @timeout: maximum number of microseconds in the timeout
|
||||
* @index: loop index (integer)
|
||||
*
|
||||
* Loop waiting for @cond to become true or until at least @timeout
|
||||
* microseconds have passed. To use, define some integer @index in the
|
||||
* calling code. After running, if @index == @timeout, then the loop has
|
||||
* timed out.
|
||||
*
|
||||
* Copied from omap_test_timeout */
|
||||
#define sr_test_cond_timeout(cond, timeout, index) \
|
||||
({ \
|
||||
for (index = 0; index < timeout; index++) { \
|
||||
if (cond) \
|
||||
break; \
|
||||
udelay(1); \
|
||||
} \
|
||||
})
|
||||
|
||||
/**
|
||||
* struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass
|
||||
* pmic specific info to smartreflex driver
|
||||
|
@ -161,7 +207,7 @@ struct omap_smartreflex_dev_attr {
|
|||
const char *sensor_voltdm_name;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OMAP_SMARTREFLEX
|
||||
#ifdef CONFIG_POWER_AVS_OMAP
|
||||
/*
|
||||
* The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
|
||||
* The smartreflex class driver should pass the class type.
|
||||
|
@ -186,10 +232,10 @@ struct omap_smartreflex_dev_attr {
|
|||
* based decisions.
|
||||
*/
|
||||
struct omap_sr_class_data {
|
||||
int (*enable)(struct voltagedomain *voltdm);
|
||||
int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
|
||||
int (*configure)(struct voltagedomain *voltdm);
|
||||
int (*notify)(struct voltagedomain *voltdm, u32 status);
|
||||
int (*enable)(struct omap_sr *sr);
|
||||
int (*disable)(struct omap_sr *sr, int is_volt_reset);
|
||||
int (*configure)(struct omap_sr *sr);
|
||||
int (*notify)(struct omap_sr *sr, u32 status);
|
||||
u8 notify_flags;
|
||||
u8 class_type;
|
||||
};
|
||||
|
@ -197,17 +243,22 @@ struct omap_sr_class_data {
|
|||
/**
|
||||
* struct omap_sr_nvalue_table - Smartreflex n-target value info
|
||||
*
|
||||
* @efuse_offs: The offset of the efuse where n-target values are stored.
|
||||
* @nvalue: The n-target value.
|
||||
* @efuse_offs: The offset of the efuse where n-target values are stored.
|
||||
* @nvalue: The n-target value.
|
||||
* @errminlimit: The value of the ERRMINLIMIT bitfield for this n-target
|
||||
* @volt_nominal: microvolts DC that the VDD is initially programmed to
|
||||
*/
|
||||
struct omap_sr_nvalue_table {
|
||||
u32 efuse_offs;
|
||||
u32 nvalue;
|
||||
u32 errminlimit;
|
||||
unsigned long volt_nominal;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct omap_sr_data - Smartreflex platform data.
|
||||
*
|
||||
* @name: instance name
|
||||
* @ip_type: Smartreflex IP type.
|
||||
* @senp_mod: SENPENABLE value for the sr
|
||||
* @senn_mod: SENNENABLE value for sr
|
||||
|
@ -219,6 +270,7 @@ struct omap_sr_nvalue_table {
|
|||
* @voltdm: Pointer to the voltage domain associated with the SR
|
||||
*/
|
||||
struct omap_sr_data {
|
||||
const char *name;
|
||||
int ip_type;
|
||||
u32 senp_mod;
|
||||
u32 senn_mod;
|
Loading…
Reference in a new issue