diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 09:31:45 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-02 09:31:45 -0700 | 
| commit | 97b1007a2924aaa9126398623f6755a8c3c6a616 (patch) | |
| tree | b65c6edb631256e64bb3c72f083fa1be048de097 /arch/arm/mach-tegra/pm.c | |
| parent | dfab34aa61a0f8c14a67d7b4c1dae28e57ba592d (diff) | |
| parent | e0d20b69d3fa74a21ec363989612bddd58b930b8 (diff) | |
| download | olio-linux-3.10-97b1007a2924aaa9126398623f6755a8c3c6a616.tar.xz olio-linux-3.10-97b1007a2924aaa9126398623f6755a8c3c6a616.zip  | |
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform updates from Olof Johansson:
 "This branch contains part 1 of the platform updates for 3.10.  Among
  the highlights:
   - Support for the new Atmel Cortex-A5 based platforms (SAMA5D3)
   - New support for CSR SiRFatlas6 SoCs
   - A handful of updates for NVidia T114 (a.k.a. Tegra 4)
   - A bunch of updates for the shmobile platforms
   - A handful of updates for davinci
   - A few updates for Qualcomm MSM
   - Plus a handful of other patches, defconfig updates, etc."
* tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (135 commits)
  ARM: tegra: pm: fix build error w/o PM_SLEEP
  ARM: davinci: ensure global variables are declared
  ARM: davinci: sram.c: fix incorrect type in assignment
  ARM: davinci: da8xx dt: make file local symbols static
  ARM: davinci: da8xx: add remoteproc support
  ARM: socfpga: Upgrade clk driver for socfpga to make use of dts clock entries
  ARM: socfpga: Add clock entries into device tree
  ARM: socfpga: Enable soft reset
  ARM: EXYNOS: replace cpumask by the corresponding macro
  ARM: EXYNOS: handle properly the return values
  ARM: EXYNOS: factor out the idle states
  ARM: OMAP4: Enable fix for Cortex-A9 erratas
  ARM: OMAP2+: Export SoC information to userspace
  ARM: OMAP2+: SoC name and revision unification
  ARM: OMAP2+: Move common part of late init into common function
  ARM: tegra: pm: remove duplicated include from pm.c
  ARM: davinci: da850: override mmc DT node device name
  ARM: davinci: da850: add mmc DT entries
  mmc: davinci_mmc: add DT support
  ARM: SAMSUNG: check processor type before cache restoration in resume
  ...
Diffstat (limited to 'arch/arm/mach-tegra/pm.c')
| -rw-r--r-- | arch/arm/mach-tegra/pm.c | 131 | 
1 files changed, 81 insertions, 50 deletions
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 891fb70d0aa..45cf52c7e52 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -22,7 +22,7 @@  #include <linux/cpumask.h>  #include <linux/delay.h>  #include <linux/cpu_pm.h> -#include <linux/clk.h> +#include <linux/suspend.h>  #include <linux/err.h>  #include <linux/clk/tegra.h> @@ -37,52 +37,13 @@  #include "reset.h"  #include "flowctrl.h"  #include "fuse.h" +#include "pmc.h"  #include "sleep.h" -#define TEGRA_POWER_CPU_PWRREQ_OE	(1 << 16)  /* CPU pwr req enable */ - -#define PMC_CTRL		0x0 -#define PMC_CPUPWRGOOD_TIMER	0xc8 -#define PMC_CPUPWROFF_TIMER	0xcc -  #ifdef CONFIG_PM_SLEEP  static DEFINE_SPINLOCK(tegra_lp2_lock); -static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); -static struct clk *tegra_pclk;  void (*tegra_tear_down_cpu)(void); -static void set_power_timers(unsigned long us_on, unsigned long us_off) -{ -	unsigned long long ticks; -	unsigned long long pclk; -	unsigned long rate; -	static unsigned long tegra_last_pclk; - -	if (tegra_pclk == NULL) { -		tegra_pclk = clk_get_sys(NULL, "pclk"); -		WARN_ON(IS_ERR(tegra_pclk)); -	} - -	rate = clk_get_rate(tegra_pclk); - -	if (WARN_ON_ONCE(rate <= 0)) -		pclk = 100000000; -	else -		pclk = rate; - -	if ((rate != tegra_last_pclk)) { -		ticks = (us_on * pclk) + 999999ull; -		do_div(ticks, 1000000); -		writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER); - -		ticks = (us_off * pclk) + 999999ull; -		do_div(ticks, 1000000); -		writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER); -		wmb(); -	} -	tegra_last_pclk = pclk; -} -  /*   * restore_cpu_complex   * @@ -178,16 +139,9 @@ static int tegra_sleep_cpu(unsigned long v2p)  	return 0;  } -void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time) +void tegra_idle_lp2_last(void)  { -	u32 mode; - -	/* Only the last cpu down does the final suspend steps */ -	mode = readl(pmc + PMC_CTRL); -	mode |= TEGRA_POWER_CPU_PWRREQ_OE; -	writel(mode, pmc + PMC_CTRL); - -	set_power_timers(cpu_on_time, cpu_off_time); +	tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);  	cpu_cluster_pm_enter();  	suspend_cpu_complex(); @@ -197,4 +151,81 @@ void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)  	restore_cpu_complex();  	cpu_cluster_pm_exit();  } + +enum tegra_suspend_mode tegra_pm_validate_suspend_mode( +				enum tegra_suspend_mode mode) +{ +	/* Tegra114 didn't support any suspending mode yet. */ +	if (tegra_chip_id == TEGRA114) +		return TEGRA_SUSPEND_NONE; + +	/* +	 * The Tegra devices only support suspending to LP2 currently. +	 */ +	if (mode > TEGRA_SUSPEND_LP2) +		return TEGRA_SUSPEND_LP2; + +	return mode; +} + +static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = { +	[TEGRA_SUSPEND_NONE] = "none", +	[TEGRA_SUSPEND_LP2] = "LP2", +	[TEGRA_SUSPEND_LP1] = "LP1", +	[TEGRA_SUSPEND_LP0] = "LP0", +}; + +static int __cpuinit tegra_suspend_enter(suspend_state_t state) +{ +	enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode(); + +	if (WARN_ON(mode < TEGRA_SUSPEND_NONE || +		    mode >= TEGRA_MAX_SUSPEND_MODE)) +		return -EINVAL; + +	pr_info("Entering suspend state %s\n", lp_state[mode]); + +	tegra_pmc_pm_set(mode); + +	local_fiq_disable(); + +	suspend_cpu_complex(); +	switch (mode) { +	case TEGRA_SUSPEND_LP2: +		tegra_set_cpu_in_lp2(0); +		break; +	default: +		break; +	} + +	cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu); + +	switch (mode) { +	case TEGRA_SUSPEND_LP2: +		tegra_clear_cpu_in_lp2(0); +		break; +	default: +		break; +	} +	restore_cpu_complex(); + +	local_fiq_enable(); + +	return 0; +} + +static const struct platform_suspend_ops tegra_suspend_ops = { +	.valid		= suspend_valid_only_mem, +	.enter		= tegra_suspend_enter, +}; + +void __init tegra_init_suspend(void) +{ +	if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE) +		return; + +	tegra_pmc_suspend_init(); + +	suspend_set_ops(&tegra_suspend_ops); +}  #endif  |