OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [base/] [power/] [main.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * drivers/base/power/main.c - Where the driver meets power management.
3
 *
4
 * Copyright (c) 2003 Patrick Mochel
5
 * Copyright (c) 2003 Open Source Development Lab
6
 *
7
 * This file is released under the GPLv2
8
 *
9
 *
10
 * The driver model core calls device_pm_add() when a device is registered.
11
 * This will intialize the embedded device_pm_info object in the device
12
 * and add it to the list of power-controlled devices. sysfs entries for
13
 * controlling device power management will also be added.
14
 *
15
 * A different set of lists than the global subsystem list are used to
16
 * keep track of power info because we use different lists to hold
17
 * devices based on what stage of the power management process they
18
 * are in. The power domain dependencies may also differ from the
19
 * ancestral dependencies that the subsystem list maintains.
20
 */
21
 
22
#include <linux/device.h>
23
#include <linux/kallsyms.h>
24
#include <linux/mutex.h>
25
#include <linux/pm.h>
26
#include <linux/resume-trace.h>
27
 
28
#include "../base.h"
29
#include "power.h"
30
 
31
LIST_HEAD(dpm_active);
32
static LIST_HEAD(dpm_off);
33
static LIST_HEAD(dpm_off_irq);
34
 
35
static DEFINE_MUTEX(dpm_mtx);
36
static DEFINE_MUTEX(dpm_list_mtx);
37
 
38
int (*platform_enable_wakeup)(struct device *dev, int is_on);
39
 
40
 
41
void device_pm_add(struct device *dev)
42
{
43
        pr_debug("PM: Adding info for %s:%s\n",
44
                 dev->bus ? dev->bus->name : "No Bus",
45
                 kobject_name(&dev->kobj));
46
        mutex_lock(&dpm_list_mtx);
47
        list_add_tail(&dev->power.entry, &dpm_active);
48
        mutex_unlock(&dpm_list_mtx);
49
}
50
 
51
void device_pm_remove(struct device *dev)
52
{
53
        pr_debug("PM: Removing info for %s:%s\n",
54
                 dev->bus ? dev->bus->name : "No Bus",
55
                 kobject_name(&dev->kobj));
56
        mutex_lock(&dpm_list_mtx);
57
        dpm_sysfs_remove(dev);
58
        list_del_init(&dev->power.entry);
59
        mutex_unlock(&dpm_list_mtx);
60
}
61
 
62
 
63
/*------------------------- Resume routines -------------------------*/
64
 
65
/**
66
 *      resume_device - Restore state for one device.
67
 *      @dev:   Device.
68
 *
69
 */
70
 
71
static int resume_device(struct device * dev)
72
{
73
        int error = 0;
74
 
75
        TRACE_DEVICE(dev);
76
        TRACE_RESUME(0);
77
 
78
        down(&dev->sem);
79
 
80
        if (dev->bus && dev->bus->resume) {
81
                dev_dbg(dev,"resuming\n");
82
                error = dev->bus->resume(dev);
83
        }
84
 
85
        if (!error && dev->type && dev->type->resume) {
86
                dev_dbg(dev,"resuming\n");
87
                error = dev->type->resume(dev);
88
        }
89
 
90
        if (!error && dev->class && dev->class->resume) {
91
                dev_dbg(dev,"class resume\n");
92
                error = dev->class->resume(dev);
93
        }
94
 
95
        up(&dev->sem);
96
 
97
        TRACE_RESUME(error);
98
        return error;
99
}
100
 
101
 
102
static int resume_device_early(struct device * dev)
103
{
104
        int error = 0;
105
 
106
        TRACE_DEVICE(dev);
107
        TRACE_RESUME(0);
108
        if (dev->bus && dev->bus->resume_early) {
109
                dev_dbg(dev,"EARLY resume\n");
110
                error = dev->bus->resume_early(dev);
111
        }
112
        TRACE_RESUME(error);
113
        return error;
114
}
115
 
116
/*
117
 * Resume the devices that have either not gone through
118
 * the late suspend, or that did go through it but also
119
 * went through the early resume
120
 */
121
static void dpm_resume(void)
122
{
123
        mutex_lock(&dpm_list_mtx);
124
        while(!list_empty(&dpm_off)) {
125
                struct list_head * entry = dpm_off.next;
126
                struct device * dev = to_device(entry);
127
 
128
                get_device(dev);
129
                list_move_tail(entry, &dpm_active);
130
 
131
                mutex_unlock(&dpm_list_mtx);
132
                resume_device(dev);
133
                mutex_lock(&dpm_list_mtx);
134
                put_device(dev);
135
        }
136
        mutex_unlock(&dpm_list_mtx);
137
}
138
 
139
 
140
/**
141
 *      device_resume - Restore state of each device in system.
142
 *
143
 *      Walk the dpm_off list, remove each entry, resume the device,
144
 *      then add it to the dpm_active list.
145
 */
146
 
147
void device_resume(void)
148
{
149
        might_sleep();
150
        mutex_lock(&dpm_mtx);
151
        dpm_resume();
152
        mutex_unlock(&dpm_mtx);
153
}
154
 
155
EXPORT_SYMBOL_GPL(device_resume);
156
 
157
 
158
/**
159
 *      dpm_power_up - Power on some devices.
160
 *
161
 *      Walk the dpm_off_irq list and power each device up. This
162
 *      is used for devices that required they be powered down with
163
 *      interrupts disabled. As devices are powered on, they are moved
164
 *      to the dpm_active list.
165
 *
166
 *      Interrupts must be disabled when calling this.
167
 */
168
 
169
static void dpm_power_up(void)
170
{
171
        while(!list_empty(&dpm_off_irq)) {
172
                struct list_head * entry = dpm_off_irq.next;
173
                struct device * dev = to_device(entry);
174
 
175
                list_move_tail(entry, &dpm_off);
176
                resume_device_early(dev);
177
        }
178
}
179
 
180
 
181
/**
182
 *      device_power_up - Turn on all devices that need special attention.
183
 *
184
 *      Power on system devices then devices that required we shut them down
185
 *      with interrupts disabled.
186
 *      Called with interrupts disabled.
187
 */
188
 
189
void device_power_up(void)
190
{
191
        sysdev_resume();
192
        dpm_power_up();
193
}
194
 
195
EXPORT_SYMBOL_GPL(device_power_up);
196
 
197
 
198
/*------------------------- Suspend routines -------------------------*/
199
 
200
/*
201
 * The entries in the dpm_active list are in a depth first order, simply
202
 * because children are guaranteed to be discovered after parents, and
203
 * are inserted at the back of the list on discovery.
204
 *
205
 * All list on the suspend path are done in reverse order, so we operate
206
 * on the leaves of the device tree (or forests, depending on how you want
207
 * to look at it ;) first. As nodes are removed from the back of the list,
208
 * they are inserted into the front of their destintation lists.
209
 *
210
 * Things are the reverse on the resume path - iterations are done in
211
 * forward order, and nodes are inserted at the back of their destination
212
 * lists. This way, the ancestors will be accessed before their descendents.
213
 */
214
 
215
static inline char *suspend_verb(u32 event)
216
{
217
        switch (event) {
218
        case PM_EVENT_SUSPEND:  return "suspend";
219
        case PM_EVENT_FREEZE:   return "freeze";
220
        case PM_EVENT_PRETHAW:  return "prethaw";
221
        default:                return "(unknown suspend event)";
222
        }
223
}
224
 
225
 
226
static void
227
suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
228
{
229
        dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
230
                ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
231
                ", may wakeup" : "");
232
}
233
 
234
/**
235
 *      suspend_device - Save state of one device.
236
 *      @dev:   Device.
237
 *      @state: Power state device is entering.
238
 */
239
 
240
static int suspend_device(struct device * dev, pm_message_t state)
241
{
242
        int error = 0;
243
 
244
        down(&dev->sem);
245
        if (dev->power.power_state.event) {
246
                dev_dbg(dev, "PM: suspend %d-->%d\n",
247
                        dev->power.power_state.event, state.event);
248
        }
249
 
250
        if (dev->class && dev->class->suspend) {
251
                suspend_device_dbg(dev, state, "class ");
252
                error = dev->class->suspend(dev, state);
253
                suspend_report_result(dev->class->suspend, error);
254
        }
255
 
256
        if (!error && dev->type && dev->type->suspend) {
257
                suspend_device_dbg(dev, state, "type ");
258
                error = dev->type->suspend(dev, state);
259
                suspend_report_result(dev->type->suspend, error);
260
        }
261
 
262
        if (!error && dev->bus && dev->bus->suspend) {
263
                suspend_device_dbg(dev, state, "");
264
                error = dev->bus->suspend(dev, state);
265
                suspend_report_result(dev->bus->suspend, error);
266
        }
267
        up(&dev->sem);
268
        return error;
269
}
270
 
271
 
272
/*
273
 * This is called with interrupts off, only a single CPU
274
 * running. We can't acquire a mutex or semaphore (and we don't
275
 * need the protection)
276
 */
277
static int suspend_device_late(struct device *dev, pm_message_t state)
278
{
279
        int error = 0;
280
 
281
        if (dev->bus && dev->bus->suspend_late) {
282
                suspend_device_dbg(dev, state, "LATE ");
283
                error = dev->bus->suspend_late(dev, state);
284
                suspend_report_result(dev->bus->suspend_late, error);
285
        }
286
        return error;
287
}
288
 
289
/**
290
 *      device_suspend - Save state and stop all devices in system.
291
 *      @state:         Power state to put each device in.
292
 *
293
 *      Walk the dpm_active list, call ->suspend() for each device, and move
294
 *      it to the dpm_off list.
295
 *
296
 *      (For historical reasons, if it returns -EAGAIN, that used to mean
297
 *      that the device would be called again with interrupts disabled.
298
 *      These days, we use the "suspend_late()" callback for that, so we
299
 *      print a warning and consider it an error).
300
 *
301
 *      If we get a different error, try and back out.
302
 *
303
 *      If we hit a failure with any of the devices, call device_resume()
304
 *      above to bring the suspended devices back to life.
305
 *
306
 */
307
 
308
int device_suspend(pm_message_t state)
309
{
310
        int error = 0;
311
 
312
        might_sleep();
313
        mutex_lock(&dpm_mtx);
314
        mutex_lock(&dpm_list_mtx);
315
        while (!list_empty(&dpm_active) && error == 0) {
316
                struct list_head * entry = dpm_active.prev;
317
                struct device * dev = to_device(entry);
318
 
319
                get_device(dev);
320
                mutex_unlock(&dpm_list_mtx);
321
 
322
                error = suspend_device(dev, state);
323
 
324
                mutex_lock(&dpm_list_mtx);
325
 
326
                /* Check if the device got removed */
327
                if (!list_empty(&dev->power.entry)) {
328
                        /* Move it to the dpm_off list */
329
                        if (!error)
330
                                list_move(&dev->power.entry, &dpm_off);
331
                }
332
                if (error)
333
                        printk(KERN_ERR "Could not suspend device %s: "
334
                                "error %d%s\n",
335
                                kobject_name(&dev->kobj), error,
336
                                error == -EAGAIN ? " (please convert to suspend_late)" : "");
337
                put_device(dev);
338
        }
339
        mutex_unlock(&dpm_list_mtx);
340
        if (error)
341
                dpm_resume();
342
 
343
        mutex_unlock(&dpm_mtx);
344
        return error;
345
}
346
 
347
EXPORT_SYMBOL_GPL(device_suspend);
348
 
349
/**
350
 *      device_power_down - Shut down special devices.
351
 *      @state:         Power state to enter.
352
 *
353
 *      Walk the dpm_off_irq list, calling ->power_down() for each device that
354
 *      couldn't power down the device with interrupts enabled. When we're
355
 *      done, power down system devices.
356
 */
357
 
358
int device_power_down(pm_message_t state)
359
{
360
        int error = 0;
361
        struct device * dev;
362
 
363
        while (!list_empty(&dpm_off)) {
364
                struct list_head * entry = dpm_off.prev;
365
 
366
                dev = to_device(entry);
367
                error = suspend_device_late(dev, state);
368
                if (error)
369
                        goto Error;
370
                list_move(&dev->power.entry, &dpm_off_irq);
371
        }
372
 
373
        error = sysdev_suspend(state);
374
 Done:
375
        return error;
376
 Error:
377
        printk(KERN_ERR "Could not power down device %s: "
378
                "error %d\n", kobject_name(&dev->kobj), error);
379
        dpm_power_up();
380
        goto Done;
381
}
382
 
383
EXPORT_SYMBOL_GPL(device_power_down);
384
 
385
void __suspend_report_result(const char *function, void *fn, int ret)
386
{
387
        if (ret) {
388
                printk(KERN_ERR "%s(): ", function);
389
                print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
390
                printk("%d\n", ret);
391
        }
392
}
393
EXPORT_SYMBOL_GPL(__suspend_report_result);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.