diff options
| -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__*/ |
