2 * arch/sh/kernel/cpu/shmobile/pm_runtime.c
4 * Runtime PM support code for SuperH Mobile
6 * Copyright (C) 2009 Magnus Damm
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
12 #include <linux/init.h>
13 #include <linux/kernel.h>
15 #include <linux/pm_runtime.h>
16 #include <linux/platform_device.h>
17 #include <linux/mutex.h>
18 #include <asm/hwblk.h>
20 static DEFINE_SPINLOCK(hwblk_lock
);
21 static LIST_HEAD(hwblk_idle_list
);
22 static struct work_struct hwblk_work
;
24 extern struct hwblk_info
*hwblk_info
;
26 static void platform_pm_runtime_not_idle(struct platform_device
*pdev
)
30 /* remove device from idle list */
31 spin_lock_irqsave(&hwblk_lock
, flags
);
32 if (test_bit(PDEV_ARCHDATA_FLAG_IDLE
, &pdev
->archdata
.flags
)) {
33 list_del(&pdev
->archdata
.entry
);
34 __clear_bit(PDEV_ARCHDATA_FLAG_IDLE
, &pdev
->archdata
.flags
);
36 spin_unlock_irqrestore(&hwblk_lock
, flags
);
39 static int __platform_pm_runtime_resume(struct platform_device
*pdev
)
41 struct device
*d
= &pdev
->dev
;
42 struct pdev_archdata
*ad
= &pdev
->archdata
;
43 int hwblk
= ad
->hwblk_id
;
46 dev_dbg(d
, "__platform_pm_runtime_resume() [%d]\n", hwblk
);
48 if (d
->driver
&& d
->driver
->pm
&& d
->driver
->pm
->runtime_resume
) {
49 hwblk_enable(hwblk_info
, hwblk
);
52 if (test_bit(PDEV_ARCHDATA_FLAG_SUSP
, &ad
->flags
)) {
53 ret
= d
->driver
->pm
->runtime_resume(d
);
55 clear_bit(PDEV_ARCHDATA_FLAG_SUSP
, &ad
->flags
);
57 hwblk_disable(hwblk_info
, hwblk
);
61 dev_dbg(d
, "__platform_pm_runtime_resume() [%d] - returns %d\n",
67 static int __platform_pm_runtime_suspend(struct platform_device
*pdev
)
69 struct device
*d
= &pdev
->dev
;
70 struct pdev_archdata
*ad
= &pdev
->archdata
;
71 int hwblk
= ad
->hwblk_id
;
74 dev_dbg(d
, "__platform_pm_runtime_suspend() [%d]\n", hwblk
);
76 if (d
->driver
&& d
->driver
->pm
&& d
->driver
->pm
->runtime_suspend
) {
77 BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE
, &ad
->flags
));
79 hwblk_enable(hwblk_info
, hwblk
);
80 ret
= d
->driver
->pm
->runtime_suspend(d
);
81 hwblk_disable(hwblk_info
, hwblk
);
84 set_bit(PDEV_ARCHDATA_FLAG_SUSP
, &ad
->flags
);
85 platform_pm_runtime_not_idle(pdev
);
86 hwblk_cnt_dec(hwblk_info
, hwblk
, HWBLK_CNT_IDLE
);
90 dev_dbg(d
, "__platform_pm_runtime_suspend() [%d] - returns %d\n",
96 static void platform_pm_runtime_work(struct work_struct
*work
)
98 struct platform_device
*pdev
;
102 /* go through the idle list and suspend one device at a time */
104 spin_lock_irqsave(&hwblk_lock
, flags
);
105 if (list_empty(&hwblk_idle_list
))
108 pdev
= list_first_entry(&hwblk_idle_list
,
109 struct platform_device
,
111 spin_unlock_irqrestore(&hwblk_lock
, flags
);
114 mutex_lock(&pdev
->archdata
.mutex
);
115 ret
= __platform_pm_runtime_suspend(pdev
);
117 /* at this point the platform device may be:
118 * suspended: ret = 0, FLAG_SUSP set, clock stopped
119 * failed: ret < 0, FLAG_IDLE set, clock stopped
121 mutex_unlock(&pdev
->archdata
.mutex
);
128 /* this function gets called from cpuidle context when all devices in the
129 * main power domain are unused but some are counted as idle, ie the hwblk
130 * counter values are (HWBLK_CNT_USAGE == 0) && (HWBLK_CNT_IDLE != 0)
132 void platform_pm_runtime_suspend_idle(void)
134 queue_work(pm_wq
, &hwblk_work
);
137 int platform_pm_runtime_suspend(struct device
*dev
)
139 struct platform_device
*pdev
= to_platform_device(dev
);
140 struct pdev_archdata
*ad
= &pdev
->archdata
;
142 int hwblk
= ad
->hwblk_id
;
145 dev_dbg(dev
, "platform_pm_runtime_suspend() [%d]\n", hwblk
);
147 /* ignore off-chip platform devices */
151 /* interrupt context not allowed */
154 /* catch misconfigured drivers not starting with resume */
155 if (test_bit(PDEV_ARCHDATA_FLAG_INIT
, &pdev
->archdata
.flags
)) {
161 mutex_lock(&ad
->mutex
);
164 hwblk_disable(hwblk_info
, hwblk
);
166 /* put device on idle list */
167 spin_lock_irqsave(&hwblk_lock
, flags
);
168 list_add_tail(&pdev
->archdata
.entry
, &hwblk_idle_list
);
169 __set_bit(PDEV_ARCHDATA_FLAG_IDLE
, &pdev
->archdata
.flags
);
170 spin_unlock_irqrestore(&hwblk_lock
, flags
);
172 /* increase idle count */
173 hwblk_cnt_inc(hwblk_info
, hwblk
, HWBLK_CNT_IDLE
);
175 /* at this point the platform device is:
176 * idle: ret = 0, FLAG_IDLE set, clock stopped
178 mutex_unlock(&ad
->mutex
);
181 dev_dbg(dev
, "platform_pm_runtime_suspend() [%d] returns %d\n",
187 int platform_pm_runtime_resume(struct device
*dev
)
189 struct platform_device
*pdev
= to_platform_device(dev
);
190 struct pdev_archdata
*ad
= &pdev
->archdata
;
191 int hwblk
= ad
->hwblk_id
;
194 dev_dbg(dev
, "platform_pm_runtime_resume() [%d]\n", hwblk
);
196 /* ignore off-chip platform devices */
200 /* interrupt context not allowed */
204 mutex_lock(&ad
->mutex
);
206 /* make sure device is removed from idle list */
207 platform_pm_runtime_not_idle(pdev
);
209 /* decrease idle count */
210 if (!test_bit(PDEV_ARCHDATA_FLAG_INIT
, &pdev
->archdata
.flags
) &&
211 !test_bit(PDEV_ARCHDATA_FLAG_SUSP
, &pdev
->archdata
.flags
))
212 hwblk_cnt_dec(hwblk_info
, hwblk
, HWBLK_CNT_IDLE
);
214 /* resume the device if needed */
215 ret
= __platform_pm_runtime_resume(pdev
);
217 /* the driver has been initialized now, so clear the init flag */
218 clear_bit(PDEV_ARCHDATA_FLAG_INIT
, &pdev
->archdata
.flags
);
220 /* at this point the platform device may be:
221 * resumed: ret = 0, flags = 0, clock started
222 * failed: ret < 0, FLAG_SUSP set, clock stopped
224 mutex_unlock(&ad
->mutex
);
226 dev_dbg(dev
, "platform_pm_runtime_resume() [%d] returns %d\n",
232 int platform_pm_runtime_idle(struct device
*dev
)
234 struct platform_device
*pdev
= to_platform_device(dev
);
235 int hwblk
= pdev
->archdata
.hwblk_id
;
238 dev_dbg(dev
, "platform_pm_runtime_idle() [%d]\n", hwblk
);
240 /* ignore off-chip platform devices */
244 /* interrupt context not allowed, use pm_runtime_put()! */
247 /* suspend synchronously to disable clocks immediately */
248 ret
= pm_runtime_suspend(dev
);
250 dev_dbg(dev
, "platform_pm_runtime_idle() [%d] done!\n", hwblk
);
254 static int platform_bus_notify(struct notifier_block
*nb
,
255 unsigned long action
, void *data
)
257 struct device
*dev
= data
;
258 struct platform_device
*pdev
= to_platform_device(dev
);
259 int hwblk
= pdev
->archdata
.hwblk_id
;
261 /* ignore off-chip platform devices */
266 case BUS_NOTIFY_ADD_DEVICE
:
267 INIT_LIST_HEAD(&pdev
->archdata
.entry
);
268 mutex_init(&pdev
->archdata
.mutex
);
269 /* platform devices without drivers should be disabled */
270 hwblk_enable(hwblk_info
, hwblk
);
271 hwblk_disable(hwblk_info
, hwblk
);
272 /* make sure driver re-inits itself once */
273 __set_bit(PDEV_ARCHDATA_FLAG_INIT
, &pdev
->archdata
.flags
);
275 /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */
276 case BUS_NOTIFY_BOUND_DRIVER
:
277 /* keep track of number of devices in use per hwblk */
278 hwblk_cnt_inc(hwblk_info
, hwblk
, HWBLK_CNT_DEVICES
);
280 case BUS_NOTIFY_UNBOUND_DRIVER
:
281 /* keep track of number of devices in use per hwblk */
282 hwblk_cnt_dec(hwblk_info
, hwblk
, HWBLK_CNT_DEVICES
);
283 /* make sure driver re-inits itself once */
284 __set_bit(PDEV_ARCHDATA_FLAG_INIT
, &pdev
->archdata
.flags
);
286 case BUS_NOTIFY_DEL_DEVICE
:
292 static struct notifier_block platform_bus_notifier
= {
293 .notifier_call
= platform_bus_notify
296 static int __init
sh_pm_runtime_init(void)
298 INIT_WORK(&hwblk_work
, platform_pm_runtime_work
);
300 bus_register_notifier(&platform_bus_type
, &platform_bus_notifier
);
303 core_initcall(sh_pm_runtime_init
);