OMAP3: PM: Added resource refresh to OPP unlock requests
[linux-ginger.git] / arch / arm / mach-omap2 / pm.c
blobc15154450d129f5fb4086dc07190a430eda4bb75
1 /*
2 * linux/arch/arm/mach-omap2/pm.c
4 * OMAP Power Management Common Routines
6 * Copyright (C) 2005 Texas Instruments, Inc.
7 * Copyright (C) 2006-2008 Nokia Corporation
9 * Written by:
10 * Richard Woodruff <r-woodruff2@ti.com>
11 * Tony Lindgren
12 * Juha Yrjola
13 * Amit Kucheria <amit.kucheria@nokia.com>
14 * Igor Stoppa <igor.stoppa@nokia.com>
15 * Jouni Hogander
17 * Based on pm.c for omap1
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License version 2 as
21 * published by the Free Software Foundation.
24 #include <linux/suspend.h>
25 #include <linux/time.h>
26 #include <linux/platform_device.h>
27 #include <linux/device.h>
29 #include <plat/cpu.h>
30 #include <asm/mach/time.h>
31 #include <asm/atomic.h>
33 #include <plat/powerdomain.h>
34 #include <plat/omapdev.h>
35 #include <plat/resource.h>
36 #include <plat/omap34xx.h>
38 #include "prm-regbits-34xx.h"
39 #include "pm.h"
41 atomic_t sleep_block = ATOMIC_INIT(0);
43 static ssize_t idle_show(struct kobject *, struct kobj_attribute *, char *);
44 static ssize_t idle_store(struct kobject *k, struct kobj_attribute *,
45 const char *buf, size_t n);
47 #ifdef CONFIG_OMAP_PM_SRF
48 static ssize_t vdd_opp_show(struct kobject *, struct kobj_attribute *, char *);
49 static ssize_t vdd_opp_store(struct kobject *k, struct kobj_attribute *,
50 const char *buf, size_t n);
51 static struct kobj_attribute vdd1_opp_attr =
52 __ATTR(vdd1_opp, 0644, vdd_opp_show, vdd_opp_store);
54 static struct kobj_attribute vdd2_opp_attr =
55 __ATTR(vdd2_opp, 0644, vdd_opp_show, vdd_opp_store);
56 static struct kobj_attribute vdd1_lock_attr =
57 __ATTR(vdd1_lock, 0644, vdd_opp_show, vdd_opp_store);
58 static struct kobj_attribute vdd2_lock_attr =
59 __ATTR(vdd2_lock, 0644, vdd_opp_show, vdd_opp_store);
61 #endif
63 static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
64 char *buf)
66 return -EINVAL;
69 static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
70 const char *buf, size_t n)
72 unsigned short value;
74 if (sscanf(buf, "%hu", &value) != 1 ||
75 (value != 0 && value != 1)) {
76 printk(KERN_ERR "idle_store: Invalid value\n");
77 return -EINVAL;
80 return n;
83 #ifdef CONFIG_OMAP_PM_SRF
84 #include <plat/omap34xx.h>
85 static int vdd1_locked;
86 static int vdd2_locked;
88 static ssize_t vdd_opp_show(struct kobject *kobj, struct kobj_attribute *attr,
89 char *buf)
91 if (attr == &vdd1_opp_attr)
92 return sprintf(buf, "%hu\n", resource_get_level("vdd1_opp"));
93 else if (attr == &vdd2_opp_attr)
94 return sprintf(buf, "%hu\n", resource_get_level("vdd2_opp"));
95 else if (attr == &vdd1_lock_attr)
96 return sprintf(buf, "%hu\n", resource_get_opp_lock(VDD1_OPP));
97 else if (attr == &vdd2_lock_attr)
98 return sprintf(buf, "%hu\n", resource_get_opp_lock(VDD2_OPP));
99 else
100 return -EINVAL;
103 static ssize_t vdd_opp_store(struct kobject *kobj, struct kobj_attribute *attr,
104 const char *buf, size_t n)
106 unsigned short value;
107 int flags = 0;
109 if (sscanf(buf, "%hu", &value) != 1)
110 return -EINVAL;
112 /* Check locks */
113 if (attr == &vdd1_lock_attr) {
114 flags = OPP_IGNORE_LOCK;
115 attr = &vdd1_opp_attr;
116 if (vdd1_locked && value == 0) {
117 resource_unlock_opp(VDD1_OPP);
118 resource_refresh();
119 vdd1_locked = 0;
120 return n;
122 if (vdd1_locked == 0 && value != 0) {
123 resource_lock_opp(VDD1_OPP);
124 vdd1_locked = 1;
126 } else if (attr == &vdd2_lock_attr) {
127 flags = OPP_IGNORE_LOCK;
128 attr = &vdd2_opp_attr;
129 if (vdd2_locked && value == 0) {
130 resource_unlock_opp(VDD2_OPP);
131 resource_refresh();
132 vdd2_locked = 0;
133 return n;
135 if (vdd2_locked == 0 && value != 0) {
136 resource_lock_opp(VDD2_OPP);
137 vdd2_locked = 1;
141 if (attr == &vdd1_opp_attr) {
142 if (value < 1 || value > 5) {
143 printk(KERN_ERR "vdd_opp_store: Invalid value\n");
144 return -EINVAL;
146 resource_set_opp_level(VDD1_OPP, value, flags);
147 } else if (attr == &vdd2_opp_attr) {
148 if (value < 1 || value > 3) {
149 printk(KERN_ERR "vdd_opp_store: Invalid value\n");
150 return -EINVAL;
152 resource_set_opp_level(VDD2_OPP, value, flags);
153 } else {
154 return -EINVAL;
156 return n;
158 #endif
160 void omap2_block_sleep(void)
162 atomic_inc(&sleep_block);
165 void omap2_allow_sleep(void)
167 int i;
169 i = atomic_dec_return(&sleep_block);
170 BUG_ON(i < 0);
173 unsigned get_last_off_on_transaction_id(struct device *dev)
175 struct platform_device *pdev = to_platform_device(dev);
176 struct omapdev *odev = omapdev_find_pdev(pdev);
177 struct powerdomain *pwrdm;
179 if (odev) {
180 pwrdm = omapdev_get_pwrdm(odev);
181 if (pwrdm)
182 return pwrdm->state_counter[0];
185 return 0;
188 static int __init omap_pm_init(void)
190 int error = -1;
192 #ifdef CONFIG_OMAP_PM_SRF
193 error = sysfs_create_file(power_kobj,
194 &vdd1_opp_attr.attr);
195 if (error) {
196 printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
197 return error;
199 error = sysfs_create_file(power_kobj,
200 &vdd2_opp_attr.attr);
201 if (error) {
202 printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
203 return error;
206 error = sysfs_create_file(power_kobj, &vdd1_lock_attr.attr);
207 if (error) {
208 printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
209 return error;
212 error = sysfs_create_file(power_kobj, &vdd2_lock_attr.attr);
213 if (error) {
214 printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
215 return error;
217 #endif
219 return error;
221 late_initcall(omap_pm_init);