diff options
author | Shaohua Li <shaohua.li@intel.com> | 2007-07-17 16:40:25 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-07-22 04:17:47 -0400 |
commit | fd4aff1a28eecbd729b409bf7d3eff5948f20414 (patch) | |
tree | af015ea8c001dd4d405a453c91a8e74dc0fa91b7 | |
parent | e9b3aba887f47f9cd64de20fec9c333a932b70dc (diff) |
ACPI: Add acpi_pm_device_sleep_state helper routine
Based on the David Brownell's patch at
http://marc.info/?l=linux-acpi&m=117873972806360&w=2
updated by: Rafael J. Wysocki <rjw@sisk.pl>
Add a helper routine returning the lowest power (highest number) ACPI device
power state that given device can be in while the system is in the sleep state
indicated by acpi_target_sleep_state .
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/sleep/main.c | 75 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 2 |
2 files changed, 77 insertions, 0 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 19f8557c711c..55eca6eabcd8 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -260,6 +260,81 @@ static struct hibernation_ops acpi_hibernation_ops = { | |||
260 | }; | 260 | }; |
261 | #endif /* CONFIG_SOFTWARE_SUSPEND */ | 261 | #endif /* CONFIG_SOFTWARE_SUSPEND */ |
262 | 262 | ||
263 | /** | ||
264 | * acpi_pm_device_sleep_state - return preferred power state of ACPI device | ||
265 | * in the system sleep state given by %acpi_target_sleep_state | ||
266 | * @dev: device to examine | ||
267 | * @wake: if set, the device should be able to wake up the system | ||
268 | * @d_min_p: used to store the upper limit of allowed states range | ||
269 | * Return value: preferred power state of the device on success, -ENODEV on | ||
270 | * failure (ie. if there's no 'struct acpi_device' for @dev) | ||
271 | * | ||
272 | * Find the lowest power (highest number) ACPI device power state that | ||
273 | * device @dev can be in while the system is in the sleep state represented | ||
274 | * by %acpi_target_sleep_state. If @wake is nonzero, the device should be | ||
275 | * able to wake up the system from this sleep state. If @d_min_p is set, | ||
276 | * the highest power (lowest number) device power state of @dev allowed | ||
277 | * in this system sleep state is stored at the location pointed to by it. | ||
278 | * | ||
279 | * The caller must ensure that @dev is valid before using this function. | ||
280 | * The caller is also responsible for figuring out if the device is | ||
281 | * supposed to be able to wake up the system and passing this information | ||
282 | * via @wake. | ||
283 | */ | ||
284 | |||
285 | int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p) | ||
286 | { | ||
287 | acpi_handle handle = DEVICE_ACPI_HANDLE(dev); | ||
288 | struct acpi_device *adev; | ||
289 | char acpi_method[] = "_SxD"; | ||
290 | unsigned long d_min, d_max; | ||
291 | |||
292 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { | ||
293 | printk(KERN_ERR "ACPI handle has no context!\n"); | ||
294 | return -ENODEV; | ||
295 | } | ||
296 | |||
297 | acpi_method[2] = '0' + acpi_target_sleep_state; | ||
298 | /* | ||
299 | * If the sleep state is S0, we will return D3, but if the device has | ||
300 | * _S0W, we will use the value from _S0W | ||
301 | */ | ||
302 | d_min = ACPI_STATE_D0; | ||
303 | d_max = ACPI_STATE_D3; | ||
304 | |||
305 | /* | ||
306 | * If present, _SxD methods return the minimum D-state (highest power | ||
307 | * state) we can use for the corresponding S-states. Otherwise, the | ||
308 | * minimum D-state is D0 (ACPI 3.x). | ||
309 | * | ||
310 | * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer | ||
311 | * provided -- that's our fault recovery, we ignore retval. | ||
312 | */ | ||
313 | if (acpi_target_sleep_state > ACPI_STATE_S0) | ||
314 | acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); | ||
315 | |||
316 | /* | ||
317 | * If _PRW says we can wake up the system from the target sleep state, | ||
318 | * the D-state returned by _SxD is sufficient for that (we assume a | ||
319 | * wakeup-aware driver if wake is set). Still, if _SxW exists | ||
320 | * (ACPI 3.x), it should return the maximum (lowest power) D-state that | ||
321 | * can wake the system. _S0W may be valid, too. | ||
322 | */ | ||
323 | if (acpi_target_sleep_state == ACPI_STATE_S0 || | ||
324 | (wake && adev->wakeup.state.enabled && | ||
325 | adev->wakeup.sleep_state <= acpi_target_sleep_state)) { | ||
326 | acpi_method[3] = 'W'; | ||
327 | acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); | ||
328 | /* Sanity check */ | ||
329 | if (d_max < d_min) | ||
330 | d_min = d_max; | ||
331 | } | ||
332 | |||
333 | if (d_min_p) | ||
334 | *d_min_p = d_min; | ||
335 | return d_max; | ||
336 | } | ||
337 | |||
263 | /* | 338 | /* |
264 | * Toshiba fails to preserve interrupts over S1, reinitialization | 339 | * Toshiba fails to preserve interrupts over S1, reinitialization |
265 | * of 8259 is needed after S1 resume. | 340 | * of 8259 is needed after S1 resume. |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c6fa5e023bc7..529d03554c7a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -364,6 +364,8 @@ acpi_handle acpi_get_child(acpi_handle, acpi_integer); | |||
364 | acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); | 364 | acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); |
365 | #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) | 365 | #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle)) |
366 | 366 | ||
367 | int acpi_pm_device_sleep_state(struct device *, int, int *); | ||
368 | |||
367 | #endif /* CONFIG_ACPI */ | 369 | #endif /* CONFIG_ACPI */ |
368 | 370 | ||
369 | #endif /*__ACPI_BUS_H__*/ | 371 | #endif /*__ACPI_BUS_H__*/ |