]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap2/pm34xx.c
7e775cc2b2013a606ea050113b2a6bfab281bf8f
[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 /* _clkdm_deny_idle - private callback function used by set_pwrdm_state() */
183 static int _clkdm_deny_idle(struct powerdomain *pwrdm,
184                             struct clockdomain *clkdm)
185 {
186         omap2_clkdm_deny_idle(clkdm);
187         return 0;
188 }
189
190 /* _clkdm_allow_idle - private callback function used by set_pwrdm_state() */
191 static int _clkdm_allow_idle(struct powerdomain *pwrdm,
192                              struct clockdomain *clkdm)
193 {
194         omap2_clkdm_allow_idle(clkdm);
195         return 0;
196 }
197
198 /* This sets pwrdm state (other than mpu & core. Currently only ON &
199  * RET are supported. Function is assuming that clkdm doesn't have
200  * hw_sup mode enabled. */
201 static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
202 {
203         u32 cur_state;
204         int ret = 0;
205
206         if (pwrdm == NULL || IS_ERR(pwrdm))
207                 return -EINVAL;
208
209         cur_state = pwrdm_read_next_pwrst(pwrdm);
210
211         if (cur_state == state)
212                 return ret;
213
214         pwrdm_for_each_clkdm(pwrdm, _clkdm_deny_idle);
215
216         ret = pwrdm_set_next_pwrst(pwrdm, state);
217         if (ret) {
218                 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
219                        pwrdm->name);
220                 goto err;
221         }
222
223         pwrdm_for_each_clkdm(pwrdm, _clkdm_allow_idle);
224
225 err:
226         return ret;
227 }
228
229 static void omap3_pm_idle(void)
230 {
231         local_irq_disable();
232         local_fiq_disable();
233
234         if (!omap3_can_sleep())
235                 goto out;
236
237         if (omap_irq_pending())
238                 goto out;
239
240         omap_sram_idle();
241
242 out:
243         local_fiq_enable();
244         local_irq_enable();
245 }
246
247 static int omap3_pm_prepare(void)
248 {
249         saved_idle = pm_idle;
250         pm_idle = NULL;
251         return 0;
252 }
253
254 static int omap3_pm_suspend(void)
255 {
256         struct power_state *pwrst;
257         int state, ret = 0;
258
259         /* Read current next_pwrsts */
260         list_for_each_entry(pwrst, &pwrst_list, node)
261                 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
262         /* Set ones wanted by suspend */
263         list_for_each_entry(pwrst, &pwrst_list, node) {
264                 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
265                         goto restore;
266                 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
267                         goto restore;
268         }
269
270         omap_sram_idle();
271
272 restore:
273         /* Restore next_pwrsts */
274         list_for_each_entry(pwrst, &pwrst_list, node) {
275                 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
276                 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
277                 if (state != pwrst->next_state) {
278                         printk(KERN_INFO "Powerdomain (%s) didn't enter "
279                                "target state %d\n",
280                                pwrst->pwrdm->name, pwrst->next_state);
281                         ret = -1;
282                 }
283         }
284         if (ret)
285                 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
286         else
287                 printk(KERN_INFO "Successfully put all powerdomains "
288                        "to target state\n");
289
290         return ret;
291 }
292
293 static int omap3_pm_enter(suspend_state_t state)
294 {
295         int ret = 0;
296
297         switch (state) {
298         case PM_SUSPEND_STANDBY:
299         case PM_SUSPEND_MEM:
300                 ret = omap3_pm_suspend();
301                 break;
302         default:
303                 ret = -EINVAL;
304         }
305
306         return ret;
307 }
308
309 static void omap3_pm_finish(void)
310 {
311         pm_idle = saved_idle;
312 }
313
314 static struct platform_suspend_ops omap_pm_ops = {
315         .prepare        = omap3_pm_prepare,
316         .enter          = omap3_pm_enter,
317         .finish         = omap3_pm_finish,
318         .valid          = suspend_valid_only_mem,
319 };
320
321 static void __init prcm_setup_regs(void)
322 {
323         u32 v;
324
325         /* setup wakup source */
326         prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
327                           WKUP_MOD, PM_WKEN);
328         /* No need to write EN_IO, that is always enabled */
329         prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
330                           WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
331         /* For some reason IO doesn't generate wakeup event even if
332          * it is selected to mpu wakeup goup */
333         __raw_writel(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
334                      OMAP3430_PRM_IRQENABLE_MPU);
335 }
336
337 static int __init pwrdms_setup(struct powerdomain *pwrdm)
338 {
339         struct power_state *pwrst;
340
341         if (!pwrdm->pwrsts)
342                 return 0;
343
344         pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
345         if (!pwrst)
346                 return -ENOMEM;
347         pwrst->pwrdm = pwrdm;
348         pwrst->next_state = PWRDM_POWER_RET;
349         list_add(&pwrst->node, &pwrst_list);
350         return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
351 }
352
353 int __init omap3_pm_init(void)
354 {
355         struct power_state *pwrst;
356         int ret;
357
358         printk(KERN_ERR "Power Management for TI OMAP3.\n");
359
360         ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
361                           (irq_handler_t)prcm_interrupt_handler,
362                           IRQF_DISABLED, "prcm", NULL);
363         if (ret) {
364                 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
365                        INT_34XX_PRCM_MPU_IRQ);
366                 goto err1;
367         }
368
369         ret = pwrdm_for_each(pwrdms_setup);
370         if (ret) {
371                 printk(KERN_ERR "Failed to setup powerdomains\n");
372                 goto err2;
373         }
374
375         mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
376         if (mpu_pwrdm == NULL) {
377                 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
378                 goto err2;
379         }
380
381         _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
382                                         omap34xx_cpu_suspend_sz);
383
384         suspend_set_ops(&omap_pm_ops);
385
386         prcm_setup_regs();
387
388         pm_idle = omap3_pm_idle;
389
390 err1:
391         return ret;
392 err2:
393         free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
394         list_for_each_entry(pwrst, &pwrst_list, node) {
395                 list_del(&pwrst->node);
396                 kfree(pwrst);
397         }
398         return ret;
399 }