]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap2/pm34xx.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / pm34xx.c
1 /*
2  * linux/arch/arm/mach-omap2/pm34xx.c
3  *
4  * OMAP3 Power Management Routines
5  *
6  * Copyright (C) 2006-2008 Nokia Corporation
7  * Tony Lindgren <tony@atomide.com>
8  * Jouni Hogander
9  *
10  * Copyright (C) 2005 Texas Instruments, Inc.
11  * Richard Woodruff <r-woodruff2@ti.com>
12  *
13  * Based on pm.c for omap1
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License version 2 as
17  * published by the Free Software Foundation.
18  */
19
20 #include <linux/pm.h>
21 #include <linux/suspend.h>
22 #include <linux/interrupt.h>
23 #include <linux/module.h>
24 #include <linux/list.h>
25 #include <linux/err.h>
26
27 #include <asm/arch/gpio.h>
28 #include <asm/arch/sram.h>
29 #include <asm/arch/pm.h>
30 #include <asm/arch/clockdomain.h>
31 #include <asm/arch/powerdomain.h>
32
33 #include "cm.h"
34 #include "cm-regbits-34xx.h"
35 #include "prm-regbits-34xx.h"
36
37 #include "prm.h"
38 #include "pm.h"
39
40 struct power_state {
41         struct powerdomain *pwrdm;
42         u32 next_state;
43         u32 saved_state;
44         struct list_head node;
45 };
46
47 static LIST_HEAD(pwrst_list);
48
49 void (*_omap_sram_idle)(u32 *addr, int save_state);
50
51 static void (*saved_idle)(void);
52
53 static struct powerdomain *mpu_pwrdm;
54
55 /* PRCM Interrupt Handler for wakeups */
56 static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
57 {
58         u32 wkst, irqstatus_mpu;
59         u32 fclk, iclk;
60
61         /* WKUP */
62         wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
63         if (wkst) {
64                 iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
65                 fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
66                 cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
67                 cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
68                 prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
69                 while (prm_read_mod_reg(WKUP_MOD, PM_WKST));
70                 cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
71                 cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
72         }
73
74         /* CORE */
75         wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
76         if (wkst) {
77                 iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
78                 fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
79                 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
80                 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
81                 prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
82                 while (prm_read_mod_reg(CORE_MOD, PM_WKST1));
83                 cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
84                 cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
85         }
86         wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
87         if (wkst) {
88                 iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
89                 fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
90                 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
91                 cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
92                 prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
93                 while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3));
94                 cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
95                 cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
96         }
97
98         /* PER */
99         wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
100         if (wkst) {
101                 iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
102                 fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
103                 cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
104                 cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
105                 prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
106                 while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST));
107                 cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
108                 cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
109         }
110
111         if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) {
112                 /* USBHOST */
113                 wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
114                 if (wkst) {
115                         iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
116                                                CM_ICLKEN);
117                         fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
118                                                CM_FCLKEN);
119                         cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
120                                          CM_ICLKEN);
121                         cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
122                                          CM_FCLKEN);
123                         prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
124                                           PM_WKST);
125                         while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
126                                                 PM_WKST));
127                         cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
128                                          CM_ICLKEN);
129                         cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
130                                          CM_FCLKEN);
131                 }
132         }
133
134         irqstatus_mpu = __raw_readl(OMAP3430_PRM_IRQSTATUS_MPU);
135         __raw_writel(irqstatus_mpu, OMAP3430_PRM_IRQSTATUS_MPU);
136         while (__raw_readl(OMAP3430_PRM_IRQSTATUS_MPU));
137
138         return IRQ_HANDLED;
139 }
140
141 static void omap_sram_idle(void)
142 {
143         /* Variable to tell what needs to be saved and restored
144          * in omap_sram_idle*/
145         /* save_state = 0 => Nothing to save and restored */
146         /* save_state = 1 => Only L1 and logic lost */
147         /* save_state = 2 => Only L2 lost */
148         /* save_state = 3 => L1, L2 and logic lost */
149         int save_state = 0, mpu_next_state;
150
151         if (!_omap_sram_idle)
152                 return;
153
154         mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
155         switch (mpu_next_state) {
156         case PWRDM_POWER_RET:
157                 /* No need to save context */
158                 save_state = 0;
159                 break;
160         default:
161                 /* Invalid state */
162                 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
163                 return;
164         }
165
166         omap2_gpio_prepare_for_retention();
167
168         _omap_sram_idle(NULL, save_state);
169
170         omap2_gpio_resume_after_retention();
171 }
172
173 static int omap3_can_sleep(void)
174 {
175         if (!enable_dyn_sleep)
176                 return 0;
177         if (atomic_read(&sleep_block) > 0)
178                 return 0;
179         return 1;
180 }
181
182 /* This sets pwrdm state (other than mpu & core. Currently only ON &
183  * RET are supported. Function is assuming that clkdm doesn't have
184  * hw_sup mode enabled. */
185 static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
186 {
187         u32 cur_state;
188         int ret = 0;
189         int i = 0;
190
191         if (pwrdm == NULL || IS_ERR(pwrdm))
192                 return -EINVAL;
193
194         cur_state = pwrdm_read_next_pwrst(pwrdm);
195
196         if (cur_state == state)
197                 return ret;
198
199         for (i = 0; pwrdm->pwrdm_clkdms[i]; i++)
200                 omap2_clkdm_deny_idle(pwrdm->pwrdm_clkdms[i]);
201
202         ret = pwrdm_set_next_pwrst(pwrdm, state);
203         if (ret) {
204                 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
205                        pwrdm->name);
206                 goto err;
207         }
208
209         for (i = 0; pwrdm->pwrdm_clkdms[i]; i++)
210                 omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[i]);
211
212 err:
213         return ret;
214 }
215
216 static void omap3_pm_idle(void)
217 {
218         local_irq_disable();
219         local_fiq_disable();
220
221         if (!omap3_can_sleep())
222                 goto out;
223
224         if (omap_irq_pending())
225                 goto out;
226
227         omap_sram_idle();
228
229 out:
230         local_fiq_enable();
231         local_irq_enable();
232 }
233
234 static int omap3_pm_prepare(void)
235 {
236         saved_idle = pm_idle;
237         pm_idle = NULL;
238         return 0;
239 }
240
241 static int omap3_pm_suspend(void)
242 {
243         struct power_state *pwrst;
244         int state, ret = 0;
245
246         /* Read current next_pwrsts */
247         list_for_each_entry(pwrst, &pwrst_list, node)
248                 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
249         /* Set ones wanted by suspend */
250         list_for_each_entry(pwrst, &pwrst_list, node) {
251                 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
252                         goto restore;
253                 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
254                         goto restore;
255         }
256
257         omap_sram_idle();
258
259 restore:
260         /* Restore next_pwrsts */
261         list_for_each_entry(pwrst, &pwrst_list, node) {
262                 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
263                 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
264                 if (state != pwrst->next_state) {
265                         printk(KERN_INFO "Powerdomain (%s) didn't enter "
266                                "target state %d\n",
267                                pwrst->pwrdm->name, pwrst->next_state);
268                         ret = -1;
269                 }
270         }
271         if (ret)
272                 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
273         else
274                 printk(KERN_INFO "Successfully put all powerdomains "
275                        "to target state\n");
276
277         return ret;
278 }
279
280 static int omap3_pm_enter(suspend_state_t state)
281 {
282         int ret = 0;
283
284         switch (state) {
285         case PM_SUSPEND_STANDBY:
286         case PM_SUSPEND_MEM:
287                 ret = omap3_pm_suspend();
288                 break;
289         default:
290                 ret = -EINVAL;
291         }
292
293         return ret;
294 }
295
296 static void omap3_pm_finish(void)
297 {
298         pm_idle = saved_idle;
299 }
300
301 static struct platform_suspend_ops omap_pm_ops = {
302         .prepare        = omap3_pm_prepare,
303         .enter          = omap3_pm_enter,
304         .finish         = omap3_pm_finish,
305         .valid          = suspend_valid_only_mem,
306 };
307
308 static void __init prcm_setup_regs(void)
309 {
310         u32 v;
311
312         /* setup wakup source */
313         prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
314                           WKUP_MOD, PM_WKEN);
315         /* No need to write EN_IO, that is always enabled */
316         prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
317                           WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
318         /* For some reason IO doesn't generate wakeup event even if
319          * it is selected to mpu wakeup goup */
320         __raw_writel(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
321                      OMAP3430_PRM_IRQENABLE_MPU);
322 }
323
324 static int __init pwrdms_setup(struct powerdomain *pwrdm)
325 {
326         struct power_state *pwrst;
327
328         if (!pwrdm->pwrsts)
329                 return 0;
330
331         pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
332         if (!pwrst)
333                 return -ENOMEM;
334         pwrst->pwrdm = pwrdm;
335         pwrst->next_state = PWRDM_POWER_RET;
336         list_add(&pwrst->node, &pwrst_list);
337         return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
338 }
339
340 int __init omap3_pm_init(void)
341 {
342         struct power_state *pwrst;
343         int ret;
344
345         printk(KERN_ERR "Power Management for TI OMAP3.\n");
346
347         ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
348                           (irq_handler_t)prcm_interrupt_handler,
349                           IRQF_DISABLED, "prcm", NULL);
350         if (ret) {
351                 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
352                        INT_34XX_PRCM_MPU_IRQ);
353                 goto err1;
354         }
355
356         ret = pwrdm_for_each(pwrdms_setup);
357         if (ret) {
358                 printk(KERN_ERR "Failed to setup powerdomains\n");
359                 goto err2;
360         }
361
362         mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
363         if (mpu_pwrdm == NULL) {
364                 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
365                 goto err2;
366         }
367
368         _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
369                                         omap34xx_cpu_suspend_sz);
370
371         suspend_set_ops(&omap_pm_ops);
372
373         prcm_setup_regs();
374
375         pm_idle = omap3_pm_idle;
376
377 err1:
378         return ret;
379 err2:
380         free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
381         list_for_each_entry(pwrst, &pwrst_list, node) {
382                 list_del(&pwrst->node);
383                 kfree(pwrst);
384         }
385         return ret;
386 }