diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-10-27 20:17:49 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-10-27 20:17:49 -0400 |
commit | dd6c26be3bb3e98d4811780f831bbc246dae54c8 (patch) | |
tree | 5b0cce644ee725386b2c4539afc91459e1913cd9 | |
parent | c0ced86d38f418448dce1ca8a825dfd16ee9a23a (diff) | |
parent | 33cf00e5708290f7e57d949219ef443a2aef34e0 (diff) |
Merge branch 'acpi-pm'
* acpi-pm:
spi: attach/detach SPI device to the ACPI power domain
i2c: attach/detach I2C client device to the ACPI power domain
ACPI / PM: allow child devices to ignore parent power state
-rw-r--r-- | drivers/acpi/device_pm.c | 8 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 5 | ||||
-rw-r--r-- | drivers/spi/spi.c | 18 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 3 |
4 files changed, 28 insertions, 6 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index a94383d1f350..d42b2fb5a7e9 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
@@ -118,9 +118,10 @@ int acpi_device_get_power(struct acpi_device *device, int *state) | |||
118 | /* | 118 | /* |
119 | * If we were unsure about the device parent's power state up to this | 119 | * If we were unsure about the device parent's power state up to this |
120 | * point, the fact that the device is in D0 implies that the parent has | 120 | * point, the fact that the device is in D0 implies that the parent has |
121 | * to be in D0 too. | 121 | * to be in D0 too, except if ignore_parent is set. |
122 | */ | 122 | */ |
123 | if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN | 123 | if (!device->power.flags.ignore_parent && device->parent |
124 | && device->parent->power.state == ACPI_STATE_UNKNOWN | ||
124 | && result == ACPI_STATE_D0) | 125 | && result == ACPI_STATE_D0) |
125 | device->parent->power.state = ACPI_STATE_D0; | 126 | device->parent->power.state = ACPI_STATE_D0; |
126 | 127 | ||
@@ -177,7 +178,8 @@ int acpi_device_set_power(struct acpi_device *device, int state) | |||
177 | acpi_power_state_string(state)); | 178 | acpi_power_state_string(state)); |
178 | return -ENODEV; | 179 | return -ENODEV; |
179 | } | 180 | } |
180 | if (device->parent && (state < device->parent->power.state)) { | 181 | if (!device->power.flags.ignore_parent && |
182 | device->parent && (state < device->parent->power.state)) { | ||
181 | dev_warn(&device->dev, | 183 | dev_warn(&device->dev, |
182 | "Cannot transition to power state %s for parent in %s\n", | 184 | "Cannot transition to power state %s for parent in %s\n", |
183 | acpi_power_state_string(state), | 185 | acpi_power_state_string(state), |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3be58f89ac77..75ba8608383e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -254,10 +254,12 @@ static int i2c_device_probe(struct device *dev) | |||
254 | client->flags & I2C_CLIENT_WAKE); | 254 | client->flags & I2C_CLIENT_WAKE); |
255 | dev_dbg(dev, "probe\n"); | 255 | dev_dbg(dev, "probe\n"); |
256 | 256 | ||
257 | acpi_dev_pm_attach(&client->dev, true); | ||
257 | status = driver->probe(client, i2c_match_id(driver->id_table, client)); | 258 | status = driver->probe(client, i2c_match_id(driver->id_table, client)); |
258 | if (status) { | 259 | if (status) { |
259 | client->driver = NULL; | 260 | client->driver = NULL; |
260 | i2c_set_clientdata(client, NULL); | 261 | i2c_set_clientdata(client, NULL); |
262 | acpi_dev_pm_detach(&client->dev, true); | ||
261 | } | 263 | } |
262 | return status; | 264 | return status; |
263 | } | 265 | } |
@@ -283,6 +285,7 @@ static int i2c_device_remove(struct device *dev) | |||
283 | client->driver = NULL; | 285 | client->driver = NULL; |
284 | i2c_set_clientdata(client, NULL); | 286 | i2c_set_clientdata(client, NULL); |
285 | } | 287 | } |
288 | acpi_dev_pm_detach(&client->dev, true); | ||
286 | return status; | 289 | return status; |
287 | } | 290 | } |
288 | 291 | ||
@@ -1111,8 +1114,10 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, | |||
1111 | if (ret < 0 || !info.addr) | 1114 | if (ret < 0 || !info.addr) |
1112 | return AE_OK; | 1115 | return AE_OK; |
1113 | 1116 | ||
1117 | adev->power.flags.ignore_parent = true; | ||
1114 | strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); | 1118 | strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); |
1115 | if (!i2c_new_device(adapter, &info)) { | 1119 | if (!i2c_new_device(adapter, &info)) { |
1120 | adev->power.flags.ignore_parent = false; | ||
1116 | dev_err(&adapter->dev, | 1121 | dev_err(&adapter->dev, |
1117 | "failed to add I2C device %s from ACPI\n", | 1122 | "failed to add I2C device %s from ACPI\n", |
1118 | dev_name(&adev->dev)); | 1123 | dev_name(&adev->dev)); |
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9e039c60c068..740f9ddda227 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -240,15 +240,27 @@ EXPORT_SYMBOL_GPL(spi_bus_type); | |||
240 | static int spi_drv_probe(struct device *dev) | 240 | static int spi_drv_probe(struct device *dev) |
241 | { | 241 | { |
242 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); | 242 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); |
243 | struct spi_device *spi = to_spi_device(dev); | ||
244 | int ret; | ||
245 | |||
246 | acpi_dev_pm_attach(&spi->dev, true); | ||
247 | ret = sdrv->probe(spi); | ||
248 | if (ret) | ||
249 | acpi_dev_pm_detach(&spi->dev, true); | ||
243 | 250 | ||
244 | return sdrv->probe(to_spi_device(dev)); | 251 | return ret; |
245 | } | 252 | } |
246 | 253 | ||
247 | static int spi_drv_remove(struct device *dev) | 254 | static int spi_drv_remove(struct device *dev) |
248 | { | 255 | { |
249 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); | 256 | const struct spi_driver *sdrv = to_spi_driver(dev->driver); |
257 | struct spi_device *spi = to_spi_device(dev); | ||
258 | int ret; | ||
259 | |||
260 | ret = sdrv->remove(spi); | ||
261 | acpi_dev_pm_detach(&spi->dev, true); | ||
250 | 262 | ||
251 | return sdrv->remove(to_spi_device(dev)); | 263 | return ret; |
252 | } | 264 | } |
253 | 265 | ||
254 | static void spi_drv_shutdown(struct device *dev) | 266 | static void spi_drv_shutdown(struct device *dev) |
@@ -1025,8 +1037,10 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, | |||
1025 | return AE_OK; | 1037 | return AE_OK; |
1026 | } | 1038 | } |
1027 | 1039 | ||
1040 | adev->power.flags.ignore_parent = true; | ||
1028 | strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); | 1041 | strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); |
1029 | if (spi_add_device(spi)) { | 1042 | if (spi_add_device(spi)) { |
1043 | adev->power.flags.ignore_parent = false; | ||
1030 | dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", | 1044 | dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", |
1031 | dev_name(&adev->dev)); | 1045 | dev_name(&adev->dev)); |
1032 | spi_dev_put(spi); | 1046 | spi_dev_put(spi); |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index d9019821aa60..15100f625e65 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -222,7 +222,8 @@ struct acpi_device_power_flags { | |||
222 | u32 power_resources:1; /* Power resources */ | 222 | u32 power_resources:1; /* Power resources */ |
223 | u32 inrush_current:1; /* Serialize Dx->D0 */ | 223 | u32 inrush_current:1; /* Serialize Dx->D0 */ |
224 | u32 power_removed:1; /* Optimize Dx->D0 */ | 224 | u32 power_removed:1; /* Optimize Dx->D0 */ |
225 | u32 reserved:28; | 225 | u32 ignore_parent:1; /* Power is independent of parent power state */ |
226 | u32 reserved:27; | ||
226 | }; | 227 | }; |
227 | 228 | ||
228 | struct acpi_device_power_state { | 229 | struct acpi_device_power_state { |