diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-18 18:45:34 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-19 18:49:06 -0400 |
| commit | b9e95fc65ededbec083aa91b4faa58ad992c0891 (patch) | |
| tree | 9f2b2867d14e6ad7b6a3cef1a2a776518ae83517 | |
| parent | 6ee22e9d59151550a55d370b14109bdae8b58bda (diff) | |
ACPI / LPSS: Power up LPSS devices during enumeration
Commit 7cd8407 (ACPI / PM: Do not execute _PS0 for devices without
_PSC during initialization) introduced a regression on some systems
with Intel Lynxpoint Low-Power Subsystem (LPSS) where some devices
need to be powered up during initialization, but their device objects
in the ACPI namespace have _PS0 and _PS3 only (without _PSC or power
resources).
To work around this problem, make the ACPI LPSS driver power up
devices it knows about by using a new helper function
acpi_device_fix_up_power() that does all of the necessary
sanity checks and calls acpi_dev_pm_explicit_set() to put the
device into D0.
Reported-and-tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
| -rw-r--r-- | drivers/acpi/acpi_lpss.c | 21 | ||||
| -rw-r--r-- | drivers/acpi/device_pm.c | 20 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 1 |
3 files changed, 36 insertions, 6 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 652fd5ce303c..cab13f2fc28e 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c | |||
| @@ -164,15 +164,24 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
| 164 | if (dev_desc->clk_required) { | 164 | if (dev_desc->clk_required) { |
| 165 | ret = register_device_clock(adev, pdata); | 165 | ret = register_device_clock(adev, pdata); |
| 166 | if (ret) { | 166 | if (ret) { |
| 167 | /* | 167 | /* Skip the device, but continue the namespace scan. */ |
| 168 | * Skip the device, but don't terminate the namespace | 168 | ret = 0; |
| 169 | * scan. | 169 | goto err_out; |
| 170 | */ | ||
| 171 | kfree(pdata); | ||
| 172 | return 0; | ||
| 173 | } | 170 | } |
| 174 | } | 171 | } |
| 175 | 172 | ||
| 173 | /* | ||
| 174 | * This works around a known issue in ACPI tables where LPSS devices | ||
| 175 | * have _PS0 and _PS3 without _PSC (and no power resources), so | ||
| 176 | * acpi_bus_init_power() will assume that the BIOS has put them into D0. | ||
| 177 | */ | ||
| 178 | ret = acpi_device_fix_up_power(adev); | ||
| 179 | if (ret) { | ||
| 180 | /* Skip the device, but continue the namespace scan. */ | ||
| 181 | ret = 0; | ||
| 182 | goto err_out; | ||
| 183 | } | ||
| 184 | |||
| 176 | adev->driver_data = pdata; | 185 | adev->driver_data = pdata; |
| 177 | ret = acpi_create_platform_device(adev, id); | 186 | ret = acpi_create_platform_device(adev, id); |
| 178 | if (ret > 0) | 187 | if (ret > 0) |
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 318fa32a141e..31c217a42839 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
| @@ -290,6 +290,26 @@ int acpi_bus_init_power(struct acpi_device *device) | |||
| 290 | return 0; | 290 | return 0; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | /** | ||
| 294 | * acpi_device_fix_up_power - Force device with missing _PSC into D0. | ||
| 295 | * @device: Device object whose power state is to be fixed up. | ||
| 296 | * | ||
| 297 | * Devices without power resources and _PSC, but having _PS0 and _PS3 defined, | ||
| 298 | * are assumed to be put into D0 by the BIOS. However, in some cases that may | ||
| 299 | * not be the case and this function should be used then. | ||
| 300 | */ | ||
| 301 | int acpi_device_fix_up_power(struct acpi_device *device) | ||
| 302 | { | ||
| 303 | int ret = 0; | ||
| 304 | |||
| 305 | if (!device->power.flags.power_resources | ||
| 306 | && !device->power.flags.explicit_get | ||
| 307 | && device->power.state == ACPI_STATE_D0) | ||
| 308 | ret = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); | ||
| 309 | |||
| 310 | return ret; | ||
| 311 | } | ||
| 312 | |||
| 293 | int acpi_bus_update_power(acpi_handle handle, int *state_p) | 313 | int acpi_bus_update_power(acpi_handle handle, int *state_p) |
| 294 | { | 314 | { |
| 295 | struct acpi_device *device; | 315 | struct acpi_device *device; |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 636c59f2003a..c13c919ab99e 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -382,6 +382,7 @@ const char *acpi_power_state_string(int state); | |||
| 382 | int acpi_device_get_power(struct acpi_device *device, int *state); | 382 | int acpi_device_get_power(struct acpi_device *device, int *state); |
| 383 | int acpi_device_set_power(struct acpi_device *device, int state); | 383 | int acpi_device_set_power(struct acpi_device *device, int state); |
| 384 | int acpi_bus_init_power(struct acpi_device *device); | 384 | int acpi_bus_init_power(struct acpi_device *device); |
| 385 | int acpi_device_fix_up_power(struct acpi_device *device); | ||
| 385 | int acpi_bus_update_power(acpi_handle handle, int *state_p); | 386 | int acpi_bus_update_power(acpi_handle handle, int *state_p); |
| 386 | bool acpi_bus_power_manageable(acpi_handle handle); | 387 | bool acpi_bus_power_manageable(acpi_handle handle); |
| 387 | 388 | ||
