diff options
Diffstat (limited to 'arch')
40 files changed, 652 insertions, 1762 deletions
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index a2200c77bf7..4b89fae14a5 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -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"); diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c index fdd90805d98..1b7a2fc3659 100644 --- a/arch/arm/mach-imx/imx53-dt.c +++ b/arch/arm/mach-imx/imx53-dt.c @@ -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 diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 426d2087c46..5ec0608f2a7 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -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 diff --git a/arch/arm/mach-imx/mach-mx53_ard.c b/arch/arm/mach-imx/mach-mx53_ard.c index f641a175869..6c28e65f424 100644 --- a/arch/arm/mach-imx/mach-mx53_ard.c +++ b/arch/arm/mach-imx/mach-mx53_ard.c @@ -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 diff --git a/arch/arm/mach-imx/mach-mx53_evk.c b/arch/arm/mach-imx/mach-mx53_evk.c index a1060b26fb2..09fe2197b49 100644 --- a/arch/arm/mach-imx/mach-mx53_evk.c +++ b/arch/arm/mach-imx/mach-mx53_evk.c @@ -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 diff --git a/arch/arm/mach-imx/mach-mx53_loco.c b/arch/arm/mach-imx/mach-mx53_loco.c index 388c415d6b6..8abe23c1d3c 100644 --- a/arch/arm/mach-imx/mach-mx53_loco.c +++ b/arch/arm/mach-imx/mach-mx53_loco.c @@ -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 diff --git a/arch/arm/mach-imx/mach-mx53_smd.c b/arch/arm/mach-imx/mach-mx53_smd.c index f297df7ccb3..b15d6a6d3b6 100644 --- a/arch/arm/mach-imx/mach-mx53_smd.c +++ b/arch/arm/mach-imx/mach-mx53_smd.c @@ -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 diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index 1d003053d56..f19d604e1b2 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -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();  } diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index e26a9cb05ed..19621ed1ffa 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -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) +{ +	int ret = tzic_enable_wake(); + +	if (likely(!ret)) +		cpu_do_idle(); + +	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)  { -	if (!cpu_is_mx51() && !cpu_is_mx53()) -		return 0; +	int ret; +	struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); -	if (gpc_dvfs_clk == NULL) -		gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); +	if (IS_ERR(gpc_dvfs_clk)) +		return PTR_ERR(gpc_dvfs_clk); -	if (!IS_ERR(gpc_dvfs_clk)) { -		if (cpu_is_mx51()) -			suspend_set_ops(&mx5_suspend_ops); -	} else -		return -EPERM; +	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(); +} diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 19b771d0c0d..b7a4ab65fac 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -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) diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 31344528eb5..f2a49a48ef5 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -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, diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 71651e20a43..c00c68961bb 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -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(); diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c index 297ebe03f09..cdd6dda0382 100644 --- a/arch/arm/mach-omap2/hdq1w.c +++ b/arch/arm/mach-omap2/hdq1w.c @@ -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); diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c index ef2a6924731..fb5bc6cf377 100644 --- a/arch/arm/mach-omap2/msdi.c +++ b/arch/arm/mach-omap2/msdi.c @@ -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 diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 13670aa84e5..e35a86bf4e1 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -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;  } diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3f21568f175..6ca8e519968 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -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 @@ -1759,6 +1763,32 @@ static int _reset(struct omap_hwmod *oh)  }  /** + * _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; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index cdb9637aab1..c9e38200216 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -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		= { diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 5c2ce7e7783..242aee498ce 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -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" diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index ab04d3bba2e..686137d164d 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.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 diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 9b463c98750..e4fc88c65db 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -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"); diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 2f963f702a0..69b36e185e9 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -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;  } diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index a8a95184243..baee90608d1 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -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); diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index d5ae4e234bb..e5f0503a68b 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -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; diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 21cb74003a5..a0309dea679 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -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"), diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index f7bb57fff41..c19d249b481 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -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 diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index f106d21ff58..bb727c2d933 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -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); diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h index 7978092946d..ee72ae6bd8c 100644 --- a/arch/arm/mach-omap2/prm44xx.h +++ b/arch/arm/mach-omap2/prm44xx.h @@ -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); diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c index 955566eefac..1da8f03c479 100644 --- a/arch/arm/mach-omap2/smartreflex-class3.c +++ b/arch/arm/mach-omap2/smartreflex-class3.c @@ -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 */ diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c deleted file mode 100644 index 008fbd7b935..00000000000 --- a/arch/arm/mach-omap2/smartreflex.c +++ /dev/null @@ -1,1165 +0,0 @@ -/* - * OMAP SmartReflex Voltage Control - * - * Author: Thara Gopinath	<thara@ti.com> - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Thara Gopinath <thara@ti.com> - * - * Copyright (C) 2008 Nokia Corporation - * Kalle Jokiniemi - * - * Copyright (C) 2007 Texas Instruments, Inc. - * Lesly A M <x0080970@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/debugfs.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> - -#include "common.h" - -#include "pm.h" -#include "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); - -static struct omap_sr_class_data *sr_class; -static struct omap_sr_pmic_data *sr_pmic_data; -static struct dentry		*sr_dbg_dir; - -static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value) -{ -	__raw_writel(value, (sr->base + offset)); -} - -static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, -					u32 value) -{ -	u32 reg_val; - -	/* -	 * Smartreflex error config register is special as it contains -	 * certain status bits which if written a 1 into means a clear -	 * of those bits. So in order to make sure no accidental write of -	 * 1 happens to those status bits, do a clear of them in the read -	 * value. This mean this API doesn't rewrite values in these bits -	 * if they are currently set, but does allow the caller to write -	 * those bits. -	 */ -	if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1) -		mask |= ERRCONFIG_STATUS_V1_MASK; -	else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2) -		mask |= ERRCONFIG_VPBOUNDINTST_V2; - -	reg_val = __raw_readl(sr->base + offset); -	reg_val &= ~mask; - -	value &= mask; - -	reg_val |= value; - -	__raw_writel(reg_val, (sr->base + offset)); -} - -static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset) -{ -	return __raw_readl(sr->base + offset); -} - -static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm) -{ -	struct omap_sr *sr_info; - -	if (!voltdm) { -		pr_err("%s: Null voltage domain passed!\n", __func__); -		return ERR_PTR(-EINVAL); -	} - -	list_for_each_entry(sr_info, &sr_list, node) { -		if (voltdm == sr_info->voltdm) -			return sr_info; -	} - -	return ERR_PTR(-ENODATA); -} - -static irqreturn_t sr_interrupt(int irq, void *data) -{ -	struct omap_sr *sr_info = data; -	u32 status = 0; - -	switch (sr_info->ip_type) { -	case SR_TYPE_V1: -		/* Read the status bits */ -		status = sr_read_reg(sr_info, ERRCONFIG_V1); - -		/* Clear them by writing back */ -		sr_write_reg(sr_info, ERRCONFIG_V1, status); -		break; -	case SR_TYPE_V2: -		/* Read the status bits */ -		status = sr_read_reg(sr_info, IRQSTATUS); - -		/* Clear them by writing back */ -		sr_write_reg(sr_info, IRQSTATUS, status); -		break; -	default: -		dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n", -			sr_info->ip_type); -		return IRQ_NONE; -	} - -	if (sr_class->notify) -		sr_class->notify(sr_info->voltdm, status); - -	return IRQ_HANDLED; -} - -static void sr_set_clk_length(struct omap_sr *sr) -{ -	struct clk *sys_ck; -	u32 sys_clk_speed; - -	if (cpu_is_omap34xx()) -		sys_ck = clk_get(NULL, "sys_ck"); -	else -		sys_ck = clk_get(NULL, "sys_clkin_ck"); - -	if (IS_ERR(sys_ck)) { -		dev_err(&sr->pdev->dev, "%s: unable to get sys clk\n", -			__func__); -		return; -	} - -	sys_clk_speed = clk_get_rate(sys_ck); -	clk_put(sys_ck); - -	switch (sys_clk_speed) { -	case 12000000: -		sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK; -		break; -	case 13000000: -		sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK; -		break; -	case 19200000: -		sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK; -		break; -	case 26000000: -		sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK; -		break; -	case 38400000: -		sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK; -		break; -	default: -		dev_err(&sr->pdev->dev, "%s: Invalid sysclk value: %d\n", -			__func__, sys_clk_speed); -		break; -	} -} - -static void sr_set_regfields(struct omap_sr *sr) -{ -	/* -	 * For time being these values are defined in smartreflex.h -	 * and populated during init. May be they can be moved to board -	 * file or pmic specific data structure. In that case these structure -	 * fields will have to be populated using the pdata or pmic structure. -	 */ -	if (cpu_is_omap34xx() || cpu_is_omap44xx()) { -		sr->err_weight = OMAP3430_SR_ERRWEIGHT; -		sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT; -		sr->accum_data = OMAP3430_SR_ACCUMDATA; -		if (!(strcmp(sr->voltdm->name, "mpu"))) { -			sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT; -			sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT; -		} else { -			sr->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT; -			sr->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT; -		} -	} -} - -static void sr_start_vddautocomp(struct omap_sr *sr) -{ -	if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) { -		dev_warn(&sr->pdev->dev, -			"%s: smartreflex class driver not registered\n", -			__func__); -		return; -	} - -	if (!sr_class->enable(sr->voltdm)) -		sr->autocomp_active = true; -} - -static void sr_stop_vddautocomp(struct omap_sr *sr) -{ -	if (!sr_class || !(sr_class->disable)) { -		dev_warn(&sr->pdev->dev, -			"%s: smartreflex class driver not registered\n", -			__func__); -		return; -	} - -	if (sr->autocomp_active) { -		sr_class->disable(sr->voltdm, 1); -		sr->autocomp_active = false; -	} -} - -/* - * This function handles the intializations which have to be done - * only when both sr device and class driver regiter has - * completed. This will be attempted to be called from both sr class - * driver register and sr device intializtion API's. Only one call - * will ultimately succeed. - * - * Currently this function registers interrupt handler for a particular SR - * if smartreflex class driver is already registered and has - * requested for interrupts and the SR interrupt line in present. - */ -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); -		if (ret) -			goto error; -		disable_irq(sr_info->irq); -	} - -	if (pdata && pdata->enable_on_init) -		sr_start_vddautocomp(sr_info); - -	return ret; - -error: -	iounmap(sr_info->base); -	mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0); -	release_mem_region(mem->start, resource_size(mem)); -	list_del(&sr_info->node); -	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; -} - -static void sr_v1_disable(struct omap_sr *sr) -{ -	int timeout = 0; -	int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | -			ERRCONFIG_MCUBOUNDINTST; - -	/* Enable MCUDisableAcknowledge interrupt */ -	sr_modify_reg(sr, ERRCONFIG_V1, -			ERRCONFIG_MCUDISACKINTEN, ERRCONFIG_MCUDISACKINTEN); - -	/* SRCONFIG - disable SR */ -	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); - -	/* Disable all other SR interrupts and clear the status as needed */ -	if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1) -		errconf_val |= ERRCONFIG_VPBOUNDINTST_V1; -	sr_modify_reg(sr, ERRCONFIG_V1, -			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | -			ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1), -			errconf_val); - -	/* -	 * 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); - -	if (timeout >= SR_DISABLE_TIMEOUT) -		dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n", -			__func__); - -	/* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */ -	sr_modify_reg(sr, ERRCONFIG_V1, ERRCONFIG_MCUDISACKINTEN, -			ERRCONFIG_MCUDISACKINTST); -} - -static void sr_v2_disable(struct omap_sr *sr) -{ -	int timeout = 0; - -	/* Enable MCUDisableAcknowledge interrupt */ -	sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUDISABLEACKINT); - -	/* SRCONFIG - disable SR */ -	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); - -	/* -	 * Disable all other SR interrupts and clear the status -	 * write to status register ONLY on need basis - only if status -	 * is set. -	 */ -	if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2) -		sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, -			ERRCONFIG_VPBOUNDINTST_V2); -	else -		sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, -				0x0); -	sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT | -			IRQENABLE_MCUVALIDINT | -			IRQENABLE_MCUBOUNDSINT)); -	sr_write_reg(sr, IRQSTATUS, (IRQSTATUS_MCUACCUMINT | -			IRQSTATUS_MCVALIDINT | -			IRQSTATUS_MCBOUNDSINT)); - -	/* -	 * 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); - -	if (timeout >= SR_DISABLE_TIMEOUT) -		dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n", -			__func__); - -	/* Disable MCUDisableAcknowledge interrupt & clear pending interrupt */ -	sr_write_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUDISABLEACKINT); -	sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT); -} - -static u32 sr_retrieve_nvalue(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; -	} - -	for (i = 0; i < sr->nvalue_count; i++) { -		if (sr->nvalue_table[i].efuse_offs == efuse_offs) -			return sr->nvalue_table[i].nvalue; -	} - -	return 0; -} - -/* Public Functions */ - -/** - * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the - *			 error generator module. - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the smartreflex class driver to - * configure the error generator module inside the smartreflex module. - * SR settings if using the ERROR module inside Smartreflex. - * SR CLASS 3 by default uses only the ERROR module where as - * SR CLASS 2 can choose between ERROR module and MINMAXAVG - * module. Returns 0 on success and error value in case of failure. - */ -int sr_configure_errgen(struct voltagedomain *voltdm) -{ -	u32 sr_config, sr_errconfig, errconfig_offs; -	u32 vpboundint_en, vpboundint_st; -	u32 senp_en = 0, senn_en = 0; -	u8 senp_shift, senn_shift; -	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); -		return PTR_ERR(sr); -	} - -	if (!sr->clk_length) -		sr_set_clk_length(sr); - -	senp_en = sr->senp_mod; -	senn_en = sr->senn_mod; - -	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | -		SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN; - -	switch (sr->ip_type) { -	case SR_TYPE_V1: -		sr_config |= SRCONFIG_DELAYCTRL; -		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT; -		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT; -		errconfig_offs = ERRCONFIG_V1; -		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; -		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; -		break; -	case SR_TYPE_V2: -		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT; -		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT; -		errconfig_offs = ERRCONFIG_V2; -		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; -		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; -		break; -	default: -		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" -			"module without specifying the ip\n", __func__); -		return -EINVAL; -	} - -	sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift)); -	sr_write_reg(sr, SRCONFIG, sr_config); -	sr_errconfig = (sr->err_weight << ERRCONFIG_ERRWEIGHT_SHIFT) | -		(sr->err_maxlimit << ERRCONFIG_ERRMAXLIMIT_SHIFT) | -		(sr->err_minlimit <<  ERRCONFIG_ERRMINLIMIT_SHIFT); -	sr_modify_reg(sr, errconfig_offs, (SR_ERRWEIGHT_MASK | -		SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK), -		sr_errconfig); - -	/* Enabling the interrupts if the ERROR module is used */ -	sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st), -		      vpboundint_en); - -	return 0; -} - -/** - * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the smartreflex class driver to - * disable the error generator module inside the smartreflex module. - * - * Returns 0 on success and error value in case of failure. - */ -int sr_disable_errgen(struct voltagedomain *voltdm) -{ -	u32 errconfig_offs; -	u32 vpboundint_en, vpboundint_st; -	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); -		return PTR_ERR(sr); -	} - -	switch (sr->ip_type) { -	case SR_TYPE_V1: -		errconfig_offs = ERRCONFIG_V1; -		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; -		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; -		break; -	case SR_TYPE_V2: -		errconfig_offs = ERRCONFIG_V2; -		vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; -		vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; -		break; -	default: -		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" -			"module without specifying the ip\n", __func__); -		return -EINVAL; -	} - -	/* Disable the interrupts of ERROR module */ -	sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0); - -	/* Disable the Sensor and errorgen */ -	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0); - -	return 0; -} - -/** - * sr_configure_minmax() - Configures the smrtreflex to perform AVS using the - *			 minmaxavg module. - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the smartreflex class driver to - * configure the minmaxavg module inside the smartreflex module. - * SR settings if using the ERROR module inside Smartreflex. - * SR CLASS 3 by default uses only the ERROR module where as - * SR CLASS 2 can choose between ERROR module and MINMAXAVG - * module. Returns 0 on success and error value in case of failure. - */ -int sr_configure_minmax(struct voltagedomain *voltdm) -{ -	u32 sr_config, sr_avgwt; -	u32 senp_en = 0, senn_en = 0; -	u8 senp_shift, senn_shift; -	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); -		return PTR_ERR(sr); -	} - -	if (!sr->clk_length) -		sr_set_clk_length(sr); - -	senp_en = sr->senp_mod; -	senn_en = sr->senn_mod; - -	sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | -		SRCONFIG_SENENABLE | -		(sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT); - -	switch (sr->ip_type) { -	case SR_TYPE_V1: -		sr_config |= SRCONFIG_DELAYCTRL; -		senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT; -		senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT; -		break; -	case SR_TYPE_V2: -		senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT; -		senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT; -		break; -	default: -		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" -			"module without specifying the ip\n", __func__); -		return -EINVAL; -	} - -	sr_config |= ((senn_en << senn_shift) | (senp_en << senp_shift)); -	sr_write_reg(sr, SRCONFIG, sr_config); -	sr_avgwt = (sr->senp_avgweight << AVGWEIGHT_SENPAVGWEIGHT_SHIFT) | -		(sr->senn_avgweight << AVGWEIGHT_SENNAVGWEIGHT_SHIFT); -	sr_write_reg(sr, AVGWEIGHT, sr_avgwt); - -	/* -	 * Enabling the interrupts if MINMAXAVG module is used. -	 * TODO: check if all the interrupts are mandatory -	 */ -	switch (sr->ip_type) { -	case SR_TYPE_V1: -		sr_modify_reg(sr, ERRCONFIG_V1, -			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | -			ERRCONFIG_MCUBOUNDINTEN), -			(ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST | -			 ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST | -			 ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST)); -		break; -	case SR_TYPE_V2: -		sr_write_reg(sr, IRQSTATUS, -			IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT | -			IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT); -		sr_write_reg(sr, IRQENABLE_SET, -			IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT | -			IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT); -		break; -	default: -		dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" -			"module without specifying the ip\n", __func__); -		return -EINVAL; -	} - -	return 0; -} - -/** - * sr_enable() - Enables the smartreflex module. - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * @volt:	The voltage at which the Voltage domain associated with - *		the smartreflex module is operating at. - *		This is required only to program the correct Ntarget value. - * - * This API is to be called from the smartreflex class driver to - * enable a smartreflex module. Returns 0 on success. Returns error - * value if the voltage passed is wrong or if ntarget value is wrong. - */ -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; -	int ret; - -	if (IS_ERR(sr)) { -		pr_warning("%s: omap_sr struct for sr_%s not found\n", -			__func__, voltdm->name); -		return PTR_ERR(sr); -	} - -	volt_data = omap_voltage_get_voltdata(sr->voltdm, volt); - -	if (IS_ERR(volt_data)) { -		dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table" -			"for nominal voltage %ld\n", __func__, volt); -		return PTR_ERR(volt_data); -	} - -	nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs); - -	if (!nvalue_reciprocal) { -		dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n", -			__func__, volt); -		return -ENODATA; -	} - -	/* errminlimit is opp dependent and hence linked to voltage */ -	sr->err_minlimit = volt_data->sr_errminlimit; - -	pm_runtime_get_sync(&sr->pdev->dev); - -	/* Check if SR is already enabled. If yes do nothing */ -	if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) -		return 0; - -	/* Configure SR */ -	ret = sr_class->configure(voltdm); -	if (ret) -		return ret; - -	sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal); - -	/* SRCONFIG - enable SR */ -	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE); -	return 0; -} - -/** - * sr_disable() - Disables the smartreflex module. - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the smartreflex class driver to - * disable a smartreflex module. - */ -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); -		return; -	} - -	/* Check if SR clocks are already disabled. If yes do nothing */ -	if (pm_runtime_suspended(&sr->pdev->dev)) -		return; - -	/* -	 * Disable SR if only it is indeed enabled. Else just -	 * disable the clocks. -	 */ -	if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) { -		switch (sr->ip_type) { -		case SR_TYPE_V1: -			sr_v1_disable(sr); -			break; -		case SR_TYPE_V2: -			sr_v2_disable(sr); -			break; -		default: -			dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n", -				sr->ip_type); -		} -	} - -	pm_runtime_put_sync_suspend(&sr->pdev->dev); -} - -/** - * sr_register_class() - API to register a smartreflex class parameters. - * @class_data:	The structure containing various sr class specific data. - * - * This API is to be called by the smartreflex class driver to register itself - * with the smartreflex driver during init. Returns 0 on success else the - * error value. - */ -int sr_register_class(struct omap_sr_class_data *class_data) -{ -	struct omap_sr *sr_info; - -	if (!class_data) { -		pr_warning("%s:, Smartreflex class data passed is NULL\n", -			__func__); -		return -EINVAL; -	} - -	if (sr_class) { -		pr_warning("%s: Smartreflex class driver already registered\n", -			__func__); -		return -EBUSY; -	} - -	sr_class = class_data; - -	/* -	 * Call into late init to do intializations that require -	 * both sr driver and sr class driver to be initiallized. -	 */ -	list_for_each_entry(sr_info, &sr_list, node) -		sr_late_init(sr_info); - -	return 0; -} - -/** - * omap_sr_enable() -  API to enable SR clocks and to call into the - *			registered smartreflex class enable API. - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the kernel in order to enable - * a particular smartreflex module. This API will do the initial - * configurations to turn on the smartreflex module and in turn call - * into the registered smartreflex class enable API. - */ -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); -		return; -	} - -	if (!sr->autocomp_active) -		return; - -	if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) { -		dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" -			"registered\n", __func__); -		return; -	} - -	sr_class->enable(voltdm); -} - -/** - * omap_sr_disable() - API to disable SR without resetting the voltage - *			processor voltage - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the kernel in order to disable - * a particular smartreflex module. This API will in turn call - * into the registered smartreflex class disable API. This API will tell - * the smartreflex class disable not to reset the VP voltage after - * disabling smartreflex. - */ -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); -		return; -	} - -	if (!sr->autocomp_active) -		return; - -	if (!sr_class || !(sr_class->disable)) { -		dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" -			"registered\n", __func__); -		return; -	} - -	sr_class->disable(voltdm, 0); -} - -/** - * omap_sr_disable_reset_volt() - API to disable SR and reset the - *				voltage processor voltage - * @voltdm:	VDD pointer to which the SR module to be configured belongs to. - * - * This API is to be called from the kernel in order to disable - * a particular smartreflex module. This API will in turn call - * into the registered smartreflex class disable API. This API will tell - * the smartreflex class disable to reset the VP voltage after - * disabling smartreflex. - */ -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); -		return; -	} - -	if (!sr->autocomp_active) -		return; - -	if (!sr_class || !(sr_class->disable)) { -		dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" -			"registered\n", __func__); -		return; -	} - -	sr_class->disable(voltdm, 1); -} - -/** - * omap_sr_register_pmic() - API to register pmic specific info. - * @pmic_data:	The structure containing pmic specific data. - * - * This API is to be called from the PMIC specific code to register with - * smartreflex driver pmic specific info. Currently the only info required - * is the smartreflex init on the PMIC side. - */ -void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data) -{ -	if (!pmic_data) { -		pr_warning("%s: Trying to register NULL PMIC data structure" -			"with smartreflex\n", __func__); -		return; -	} - -	sr_pmic_data = pmic_data; -} - -/* PM Debug FS entries to enable and disable smartreflex. */ -static int omap_sr_autocomp_show(void *data, u64 *val) -{ -	struct omap_sr *sr_info = data; - -	if (!sr_info) { -		pr_warning("%s: omap_sr struct not found\n", __func__); -		return -EINVAL; -	} - -	*val = sr_info->autocomp_active; - -	return 0; -} - -static int omap_sr_autocomp_store(void *data, u64 val) -{ -	struct omap_sr *sr_info = data; - -	if (!sr_info) { -		pr_warning("%s: omap_sr struct not found\n", __func__); -		return -EINVAL; -	} - -	/* Sanity check */ -	if (val > 1) { -		pr_warning("%s: Invalid argument %lld\n", __func__, val); -		return -EINVAL; -	} - -	/* control enable/disable only if there is a delta in value */ -	if (sr_info->autocomp_active != val) { -		if (!val) -			sr_stop_vddautocomp(sr_info); -		else -			sr_start_vddautocomp(sr_info); -	} - -	return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show, -			omap_sr_autocomp_store, "%llu\n"); - -static int __init omap_sr_probe(struct platform_device *pdev) -{ -	struct omap_sr *sr_info; -	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) { -		dev_err(&pdev->dev, "%s: unable to allocate sr_info\n", -			__func__); -		return -ENOMEM; -	} - -	platform_set_drvdata(pdev, sr_info); - -	if (!pdata) { -		dev_err(&pdev->dev, "%s: platform data missing\n", __func__); -		ret = -EINVAL; -		goto err_free_devinfo; -	} - -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!mem) { -		dev_err(&pdev->dev, "%s: no mem resource\n", __func__); -		ret = -ENODEV; -		goto err_free_devinfo; -	} - -	mem = request_mem_region(mem->start, resource_size(mem), -					dev_name(&pdev->dev)); -	if (!mem) { -		dev_err(&pdev->dev, "%s: no mem region\n", __func__); -		ret = -EBUSY; -		goto err_free_devinfo; -	} - -	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - -	pm_runtime_enable(&pdev->dev); -	pm_runtime_irq_safe(&pdev->dev); - -	sr_info->pdev = pdev; -	sr_info->srid = pdev->id; -	sr_info->voltdm = pdata->voltdm; -	sr_info->nvalue_table = pdata->nvalue_table; -	sr_info->nvalue_count = pdata->nvalue_count; -	sr_info->senn_mod = pdata->senn_mod; -	sr_info->senp_mod = pdata->senp_mod; -	sr_info->autocomp_active = false; -	sr_info->ip_type = pdata->ip_type; -	sr_info->base = ioremap(mem->start, resource_size(mem)); -	if (!sr_info->base) { -		dev_err(&pdev->dev, "%s: ioremap fail\n", __func__); -		ret = -ENOMEM; -		goto err_release_region; -	} - -	if (irq) -		sr_info->irq = irq->start; - -	sr_set_clk_length(sr_info); -	sr_set_regfields(sr_info); - -	list_add(&sr_info->node, &sr_list); - -	/* -	 * Call into late init to do intializations that require -	 * both sr driver and sr class driver to be initiallized. -	 */ -	if (sr_class) { -		ret = sr_late_init(sr_info); -		if (ret) { -			pr_warning("%s: Error in SR late init\n", __func__); -			goto err_iounmap; -		} -	} - -	dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__); -	if (!sr_dbg_dir) { -		sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); -		if (IS_ERR_OR_NULL(sr_dbg_dir)) { -			ret = PTR_ERR(sr_dbg_dir); -			pr_err("%s:sr debugfs dir creation failed(%d)\n", -				__func__, ret); -			goto err_iounmap; -		} -	} - -	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); -	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; -	} - -	(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, -			sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops); -	(void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, -			&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)) { -		dev_err(&pdev->dev, "%s: Unable to create debugfs directory" -			"for n-values\n", __func__); -		ret = PTR_ERR(nvalue_dir); -		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); -		ret = -ENODATA; -		goto err_debugfs; -	} - -	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); -		(void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, -				&(sr_info->nvalue_table[i].nvalue)); -	} - -	return ret; - -err_debugfs: -	debugfs_remove_recursive(sr_info->dbg_dir); -err_iounmap: -	list_del(&sr_info->node); -	iounmap(sr_info->base); -err_release_region: -	release_mem_region(mem->start, resource_size(mem)); -err_free_devinfo: -	kfree(sr_info); - -	return ret; -} - -static int __devexit omap_sr_remove(struct platform_device *pdev) -{ -	struct omap_sr_data *pdata = pdev->dev.platform_data; -	struct omap_sr *sr_info; -	struct resource *mem; - -	if (!pdata) { -		dev_err(&pdev->dev, "%s: platform data missing\n", __func__); -		return -EINVAL; -	} - -	sr_info = _sr_lookup(pdata->voltdm); -	if (IS_ERR(sr_info)) { -		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", -			__func__); -		return PTR_ERR(sr_info); -	} - -	if (sr_info->autocomp_active) -		sr_stop_vddautocomp(sr_info); -	if (sr_info->dbg_dir) -		debugfs_remove_recursive(sr_info->dbg_dir); - -	list_del(&sr_info->node); -	iounmap(sr_info->base); -	kfree(sr_info); -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(mem->start, resource_size(mem)); - -	return 0; -} - -static void __devexit omap_sr_shutdown(struct platform_device *pdev) -{ -	struct omap_sr_data *pdata = pdev->dev.platform_data; -	struct omap_sr *sr_info; - -	if (!pdata) { -		dev_err(&pdev->dev, "%s: platform data missing\n", __func__); -		return; -	} - -	sr_info = _sr_lookup(pdata->voltdm); -	if (IS_ERR(sr_info)) { -		dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", -			__func__); -		return; -	} - -	if (sr_info->autocomp_active) -		sr_stop_vddautocomp(sr_info); - -	return; -} - -static struct platform_driver smartreflex_driver = { -	.remove         = __devexit_p(omap_sr_remove), -	.shutdown	= __devexit_p(omap_sr_shutdown), -	.driver		= { -		.name	= "smartreflex", -	}, -}; - -static int __init sr_init(void) -{ -	int ret = 0; - -	/* -	 * sr_init is a late init. If by then a pmic specific API is not -	 * registered either there is no need for anything to be done on -	 * the PMIC side or somebody has forgotten to register a PMIC -	 * handler. Warn for the second condition. -	 */ -	if (sr_pmic_data && sr_pmic_data->sr_pmic_init) -		sr_pmic_data->sr_pmic_init(); -	else -		pr_warning("%s: No PMIC hook to init smartreflex\n", __func__); - -	ret = platform_driver_probe(&smartreflex_driver, omap_sr_probe); -	if (ret) { -		pr_err("%s: platform driver register failed for SR\n", -			__func__); -		return ret; -	} - -	return 0; -} -late_initcall(sr_init); - -static void __exit sr_exit(void) -{ -	platform_driver_unregister(&smartreflex_driver); -} -module_exit(sr_exit); - -MODULE_DESCRIPTION("OMAP Smartreflex Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h deleted file mode 100644 index 5809141171f..00000000000 --- a/arch/arm/mach-omap2/smartreflex.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * OMAP Smartreflex Defines and Routines - * - * Author: Thara Gopinath	<thara@ti.com> - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Thara Gopinath <thara@ti.com> - * - * Copyright (C) 2008 Nokia Corporation - * Kalle Jokiniemi - * - * Copyright (C) 2007 Texas Instruments, Inc. - * Lesly A M <x0080970@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_ARM_OMAP_SMARTREFLEX_H -#define __ASM_ARM_OMAP_SMARTREFLEX_H - -#include <linux/platform_device.h> - -#include "voltage.h" - -/* - * Different Smartreflex IPs version. The v1 is the 65nm version used in - * OMAP3430. The v2 is the update for the 45nm version of the IP - * used in OMAP3630 and OMAP4430 - */ -#define SR_TYPE_V1	1 -#define SR_TYPE_V2	2 - -/* SMART REFLEX REG ADDRESS OFFSET */ -#define SRCONFIG		0x00 -#define SRSTATUS		0x04 -#define SENVAL			0x08 -#define SENMIN			0x0C -#define SENMAX			0x10 -#define SENAVG			0x14 -#define AVGWEIGHT		0x18 -#define NVALUERECIPROCAL	0x1c -#define SENERROR_V1		0x20 -#define ERRCONFIG_V1		0x24 -#define IRQ_EOI			0x20 -#define IRQSTATUS_RAW		0x24 -#define IRQSTATUS		0x28 -#define IRQENABLE_SET		0x2C -#define IRQENABLE_CLR		0x30 -#define SENERROR_V2		0x34 -#define ERRCONFIG_V2		0x38 - -/* Bit/Shift Positions */ - -/* SRCONFIG */ -#define SRCONFIG_ACCUMDATA_SHIFT	22 -#define SRCONFIG_SRCLKLENGTH_SHIFT	12 -#define SRCONFIG_SENNENABLE_V1_SHIFT	5 -#define SRCONFIG_SENPENABLE_V1_SHIFT	3 -#define SRCONFIG_SENNENABLE_V2_SHIFT	1 -#define SRCONFIG_SENPENABLE_V2_SHIFT	0 -#define SRCONFIG_CLKCTRL_SHIFT		0 - -#define SRCONFIG_ACCUMDATA_MASK		(0x3ff << 22) - -#define SRCONFIG_SRENABLE		BIT(11) -#define SRCONFIG_SENENABLE		BIT(10) -#define SRCONFIG_ERRGEN_EN		BIT(9) -#define SRCONFIG_MINMAXAVG_EN		BIT(8) -#define SRCONFIG_DELAYCTRL		BIT(2) - -/* AVGWEIGHT */ -#define AVGWEIGHT_SENPAVGWEIGHT_SHIFT	2 -#define AVGWEIGHT_SENNAVGWEIGHT_SHIFT	0 - -/* NVALUERECIPROCAL */ -#define NVALUERECIPROCAL_SENPGAIN_SHIFT	20 -#define NVALUERECIPROCAL_SENNGAIN_SHIFT	16 -#define NVALUERECIPROCAL_RNSENP_SHIFT	8 -#define NVALUERECIPROCAL_RNSENN_SHIFT	0 - -/* ERRCONFIG */ -#define ERRCONFIG_ERRWEIGHT_SHIFT	16 -#define ERRCONFIG_ERRMAXLIMIT_SHIFT	8 -#define ERRCONFIG_ERRMINLIMIT_SHIFT	0 - -#define SR_ERRWEIGHT_MASK		(0x07 << 16) -#define SR_ERRMAXLIMIT_MASK		(0xff << 8) -#define SR_ERRMINLIMIT_MASK		(0xff << 0) - -#define ERRCONFIG_VPBOUNDINTEN_V1	BIT(31) -#define ERRCONFIG_VPBOUNDINTST_V1	BIT(30) -#define	ERRCONFIG_MCUACCUMINTEN		BIT(29) -#define ERRCONFIG_MCUACCUMINTST		BIT(28) -#define	ERRCONFIG_MCUVALIDINTEN		BIT(27) -#define ERRCONFIG_MCUVALIDINTST		BIT(26) -#define ERRCONFIG_MCUBOUNDINTEN		BIT(25) -#define	ERRCONFIG_MCUBOUNDINTST		BIT(24) -#define	ERRCONFIG_MCUDISACKINTEN	BIT(23) -#define ERRCONFIG_VPBOUNDINTST_V2	BIT(23) -#define ERRCONFIG_MCUDISACKINTST	BIT(22) -#define ERRCONFIG_VPBOUNDINTEN_V2	BIT(22) - -#define ERRCONFIG_STATUS_V1_MASK	(ERRCONFIG_VPBOUNDINTST_V1 | \ -					ERRCONFIG_MCUACCUMINTST | \ -					ERRCONFIG_MCUVALIDINTST | \ -					ERRCONFIG_MCUBOUNDINTST | \ -					ERRCONFIG_MCUDISACKINTST) -/* IRQSTATUS */ -#define IRQSTATUS_MCUACCUMINT		BIT(3) -#define IRQSTATUS_MCVALIDINT		BIT(2) -#define IRQSTATUS_MCBOUNDSINT		BIT(1) -#define IRQSTATUS_MCUDISABLEACKINT	BIT(0) - -/* IRQENABLE_SET and IRQENABLE_CLEAR */ -#define IRQENABLE_MCUACCUMINT		BIT(3) -#define IRQENABLE_MCUVALIDINT		BIT(2) -#define IRQENABLE_MCUBOUNDSINT		BIT(1) -#define IRQENABLE_MCUDISABLEACKINT	BIT(0) - -/* Common Bit values */ - -#define SRCLKLENGTH_12MHZ_SYSCLK	0x3c -#define SRCLKLENGTH_13MHZ_SYSCLK	0x41 -#define SRCLKLENGTH_19MHZ_SYSCLK	0x60 -#define SRCLKLENGTH_26MHZ_SYSCLK	0x82 -#define SRCLKLENGTH_38MHZ_SYSCLK	0xC0 - -/* - * 3430 specific values. Maybe these should be passed from board file or - * pmic structures. - */ -#define OMAP3430_SR_ACCUMDATA		0x1f4 - -#define OMAP3430_SR1_SENPAVGWEIGHT	0x03 -#define OMAP3430_SR1_SENNAVGWEIGHT	0x03 - -#define OMAP3430_SR2_SENPAVGWEIGHT	0x01 -#define OMAP3430_SR2_SENNAVGWEIGHT	0x01 - -#define OMAP3430_SR_ERRWEIGHT		0x04 -#define OMAP3430_SR_ERRMAXLIMIT		0x02 - -/** - * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass - *				pmic specific info to smartreflex driver - * - * @sr_pmic_init:	API to initialize smartreflex on the PMIC side. - */ -struct omap_sr_pmic_data { -	void (*sr_pmic_init) (void); -}; - -/** - * struct omap_smartreflex_dev_attr - Smartreflex Device attribute. - * - * @sensor_voltdm_name:       Name of voltdomain of SR instance - */ -struct omap_smartreflex_dev_attr { -	const char      *sensor_voltdm_name; -}; - -#ifdef CONFIG_OMAP_SMARTREFLEX -/* - * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR. - * The smartreflex class driver should pass the class type. - * Should be used to populate the class_type field of the - * omap_smartreflex_class_data structure. - */ -#define SR_CLASS1	0x1 -#define SR_CLASS2	0x2 -#define SR_CLASS3	0x3 - -/** - * struct omap_sr_class_data - Smartreflex class driver info - * - * @enable:		API to enable a particular class smaartreflex. - * @disable:		API to disable a particular class smartreflex. - * @configure:		API to configure a particular class smartreflex. - * @notify:		API to notify the class driver about an event in SR. - *			Not needed for class3. - * @notify_flags:	specify the events to be notified to the class driver - * @class_type:		specify which smartreflex class. - *			Can be used by the SR driver to take any class - *			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); -	u8 notify_flags; -	u8 class_type; -}; - -/** - * 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. - */ -struct omap_sr_nvalue_table { -	u32 efuse_offs; -	u32 nvalue; -}; - -/** - * struct omap_sr_data - Smartreflex platform data. - * - * @ip_type:		Smartreflex IP type. - * @senp_mod:		SENPENABLE value for the sr - * @senn_mod:		SENNENABLE value for sr - * @nvalue_count:	Number of distinct nvalues in the nvalue table - * @enable_on_init:	whether this sr module needs to enabled at - *			boot up or not. - * @nvalue_table:	table containing the  efuse offsets and nvalues - *			corresponding to them. - * @voltdm:		Pointer to the voltage domain associated with the SR - */ -struct omap_sr_data { -	int				ip_type; -	u32				senp_mod; -	u32				senn_mod; -	int				nvalue_count; -	bool				enable_on_init; -	struct omap_sr_nvalue_table	*nvalue_table; -	struct voltagedomain		*voltdm; -}; - -/* Smartreflex module enable/disable interface */ -void omap_sr_enable(struct voltagedomain *voltdm); -void omap_sr_disable(struct voltagedomain *voltdm); -void omap_sr_disable_reset_volt(struct voltagedomain *voltdm); - -/* API to register the pmic specific data with the smartreflex driver. */ -void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data); - -/* Smartreflex driver hooks to be called from Smartreflex class driver */ -int sr_enable(struct voltagedomain *voltdm, unsigned long volt); -void sr_disable(struct voltagedomain *voltdm); -int sr_configure_errgen(struct voltagedomain *voltdm); -int sr_disable_errgen(struct voltagedomain *voltdm); -int sr_configure_minmax(struct voltagedomain *voltdm); - -/* API to register the smartreflex class driver with the smartreflex driver */ -int sr_register_class(struct omap_sr_class_data *class_data); -#else -static inline void omap_sr_enable(struct voltagedomain *voltdm) {} -static inline void omap_sr_disable(struct voltagedomain *voltdm) {} -static inline void omap_sr_disable_reset_volt( -		struct voltagedomain *voltdm) {} -static inline void omap_sr_register_pmic( -		struct omap_sr_pmic_data *pmic_data) {} -#endif -#endif diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index a503e1e8358..e107e3915a8 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -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; diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index a7c43c1042b..0ac2caf1594 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -16,6 +16,8 @@  #include <linux/err.h> +#include <plat/voltage.h> +  #include "vc.h"  #include "vp.h" @@ -91,25 +93,6 @@ struct voltagedomain {  };  /** - * 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)   * @step_size:	PMIC voltage step size (in uv) diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index e81290c27c6..63b064b5c1d 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -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 diff --git a/arch/arm/plat-mxc/cpuidle.c b/arch/arm/plat-mxc/cpuidle.c new file mode 100644 index 00000000000..d4cb511a44a --- /dev/null +++ b/arch/arm/plat-mxc/cpuidle.c @@ -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; +} diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 7cfcc44537f..7128e971041 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -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 diff --git a/arch/arm/plat-mxc/include/mach/cpuidle.h b/arch/arm/plat-mxc/include/mach/cpuidle.h new file mode 100644 index 00000000000..bc932d1af37 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/cpuidle.h @@ -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 diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h index 1d432a75e40..ebf10654bb4 100644 --- a/arch/arm/plat-mxc/include/mach/hardware.h +++ b/arch/arm/plat-mxc/include/mach/hardware.h @@ -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)) diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c index c60a7e41638..c2193178210 100644 --- a/arch/arm/plat-mxc/tzic.c +++ b/arch/arm/plat-mxc/tzic.c @@ -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)  { diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index dcfb506a592..dd36eba9506 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -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 diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h index 0a6a482ec01..5be4d5def42 100644 --- a/arch/arm/plat-omap/include/plat/voltage.h +++ b/arch/arm/plat-omap/include/plat/voltage.h @@ -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  |