aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/pm.c
diff options
context:
space:
mode:
authorSekhar Nori <nsekhar@ti.com>2009-12-17 07:59:31 -0500
committerKevin Hilman <khilman@deeprootsystems.com>2010-02-04 16:29:55 -0500
commitefc1bb8a6fd56f6df5b797dff5156c935175c319 (patch)
tree47b79c7f2d585ae73650acbf9d11058fb00ecb52 /arch/arm/mach-davinci/pm.c
parent7307d093e6f05d845fc5ce47893c391c819a5c2b (diff)
davinci: add power management support
This patch adds core power management (suspend-to-RAM) support for DaVinci SoCs. The code depends on the the "deepsleep" feature to suspend the SoC and saves power by gating the input clock. The wakeup can be based on an external event as supported by the SoC. Assembly code (in sleep.S) is added to aid gating DDR2 clocks. Code doing this work should not be accessing DDR2. The assembly code is relocated to SRAM by the code in pm.c The support has been validated on DA850/OMAP-L138 only though the code is (hopefully) generic enough that other SoCs supporting deepsleep feature simply requires SoC specific code to start using this driver. Note that all the device drivers don't support suspend/resume still and are being worked on. Signed-off-by: Sekhar Nori <nsekhar@ti.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-davinci/pm.c')
-rw-r--r--arch/arm/mach-davinci/pm.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c
new file mode 100644
index 000000000000..fab953b43dea
--- /dev/null
+++ b/arch/arm/mach-davinci/pm.c
@@ -0,0 +1,158 @@
1/*
2 * DaVinci Power Management Routines
3 *
4 * Copyright (C) 2009 Texas Instruments, Inc. http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/pm.h>
12#include <linux/suspend.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/clk.h>
16#include <linux/spinlock.h>
17
18#include <asm/cacheflush.h>
19#include <asm/delay.h>
20
21#include <mach/da8xx.h>
22#include <mach/sram.h>
23#include <mach/pm.h>
24
25#include "clock.h"
26
27#define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF
28
29static void (*davinci_sram_suspend) (struct davinci_pm_config *);
30static struct davinci_pm_config *pdata;
31
32static void davinci_sram_push(void *dest, void *src, unsigned int size)
33{
34 memcpy(dest, src, size);
35 flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
36}
37
38static void davinci_pm_suspend(void)
39{
40 unsigned val;
41
42 if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
43
44 /* Switch CPU PLL to bypass mode */
45 val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
46 val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
47 __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
48
49 udelay(PLL_BYPASS_TIME);
50
51 /* Powerdown CPU PLL */
52 val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
53 val |= PLLCTL_PLLPWRDN;
54 __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
55 }
56
57 /* Configure sleep count in deep sleep register */
58 val = __raw_readl(pdata->deepsleep_reg);
59 val &= ~DEEPSLEEP_SLEEPCOUNT_MASK,
60 val |= pdata->sleepcount;
61 __raw_writel(val, pdata->deepsleep_reg);
62
63 /* System goes to sleep in this call */
64 davinci_sram_suspend(pdata);
65
66 if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
67
68 /* put CPU PLL in reset */
69 val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
70 val &= ~PLLCTL_PLLRST;
71 __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
72
73 /* put CPU PLL in power down */
74 val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
75 val &= ~PLLCTL_PLLPWRDN;
76 __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
77
78 /* wait for CPU PLL reset */
79 udelay(PLL_RESET_TIME);
80
81 /* bring CPU PLL out of reset */
82 val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
83 val |= PLLCTL_PLLRST;
84 __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
85
86 /* Wait for CPU PLL to lock */
87 udelay(PLL_LOCK_TIME);
88
89 /* Remove CPU PLL from bypass mode */
90 val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
91 val &= ~PLLCTL_PLLENSRC;
92 val |= PLLCTL_PLLEN;
93 __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
94 }
95}
96
97static int davinci_pm_enter(suspend_state_t state)
98{
99 int ret = 0;
100
101 switch (state) {
102 case PM_SUSPEND_STANDBY:
103 case PM_SUSPEND_MEM:
104 davinci_pm_suspend();
105 break;
106 default:
107 ret = -EINVAL;
108 }
109
110 return ret;
111}
112
113static struct platform_suspend_ops davinci_pm_ops = {
114 .enter = davinci_pm_enter,
115 .valid = suspend_valid_only_mem,
116};
117
118static int __init davinci_pm_probe(struct platform_device *pdev)
119{
120 pdata = pdev->dev.platform_data;
121 if (!pdata) {
122 dev_err(&pdev->dev, "cannot get platform data\n");
123 return -ENOENT;
124 }
125
126 davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
127 if (!davinci_sram_suspend) {
128 dev_err(&pdev->dev, "cannot allocate SRAM memory\n");
129 return -ENOMEM;
130 }
131
132 davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
133 davinci_cpu_suspend_sz);
134
135 suspend_set_ops(&davinci_pm_ops);
136
137 return 0;
138}
139
140static int __exit davinci_pm_remove(struct platform_device *pdev)
141{
142 sram_free(davinci_sram_suspend, davinci_cpu_suspend_sz);
143 return 0;
144}
145
146static struct platform_driver davinci_pm_driver = {
147 .driver = {
148 .name = "pm-davinci",
149 .owner = THIS_MODULE,
150 },
151 .remove = __exit_p(davinci_pm_remove),
152};
153
154static int __init davinci_pm_init(void)
155{
156 return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe);
157}
158late_initcall(davinci_pm_init);