2 * power.c - power management functions for the device tree.
4 * Copyright (c) 2002-3 Patrick Mochel
5 * 2002-3 Open Source Development Lab
7 * This file is released under the GPLv2
9 * Kai Germaschewski contributed to the list walking routines.
15 #include <linux/device.h>
16 #include <linux/module.h>
17 #include <asm/semaphore.h>
20 #define to_dev(node) container_of(node,struct device,kobj.entry)
22 extern struct subsystem devices_subsys;
25 * We handle system devices differently - we suspend and shut them
26 * down first and resume them first. That way, we do anything stupid like
27 * shutting down the interrupt controller before any devices..
29 * Note that there are not different stages for power management calls -
30 * they only get one called once when interrupts are disabled.
33 extern int sysdev_shutdown(void);
34 extern int sysdev_save(u32 state);
35 extern int sysdev_suspend(u32 state);
36 extern int sysdev_resume(void);
37 extern int sysdev_restore(void);
40 * device_suspend - suspend/remove all devices on the device ree
41 * @state: state we're entering
42 * @level: what stage of the suspend process we're at
43 * (emb: it seems that these two arguments are described backwards of what
44 * they actually mean .. is this correct?)
46 * The entries in the global device list are inserted such that they're in a
47 * depth-first ordering. So, simply interate over the list, and call the
48 * driver's suspend or remove callback for each device.
50 int device_suspend(u32 state, u32 level)
55 down_write(&devices_subsys.rwsem);
56 list_for_each_entry_reverse(dev,&devices_subsys.kset.list,kobj.entry) {
57 if (dev->driver && dev->driver->suspend) {
58 pr_debug("suspending device %s\n",dev->name);
59 error = dev->driver->suspend(dev,state,level);
61 printk(KERN_ERR "%s: suspend returned %d\n",
65 up_write(&devices_subsys.rwsem);
68 * Make sure system devices are suspended.
71 case SUSPEND_SAVE_STATE:
74 case SUSPEND_POWER_DOWN:
75 sysdev_suspend(state);
85 * device_resume - resume all the devices in the system
86 * @level: stage of resume process we're at
88 * Similar to device_suspend above, though we want to do a breadth-first
89 * walk of the tree to make sure we wake up parents before children.
90 * So, we iterate over the list backward.
92 void device_resume(u32 level)
100 case RESUME_RESTORE_STATE:
107 down_write(&devices_subsys.rwsem);
108 list_for_each_entry(dev,&devices_subsys.kset.list,kobj.entry) {
109 if (dev->driver && dev->driver->resume) {
110 pr_debug("resuming device %s\n",dev->name);
111 dev->driver->resume(dev,level);
114 up_write(&devices_subsys.rwsem);
118 * device_shutdown - call ->remove() on each device to shutdown.
120 void device_shutdown(void)
124 down_write(&devices_subsys.rwsem);
125 list_for_each_entry_reverse(dev,&devices_subsys.kset.list,kobj.entry) {
126 pr_debug("shutting down %s: ",dev->name);
127 if (dev->driver && dev->driver->shutdown) {
129 dev->driver->shutdown(dev);
131 pr_debug("Ignored.\n");
133 up_write(&devices_subsys.rwsem);
138 EXPORT_SYMBOL(device_suspend);
139 EXPORT_SYMBOL(device_resume);
140 EXPORT_SYMBOL(device_shutdown);