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
This commit is contained in:
Rafael J. Wysocki 2013-10-28 01:17:49 +01:00
commit dd6c26be3b
4 changed files with 28 additions and 6 deletions

View File

@ -118,9 +118,10 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
/*
* If we were unsure about the device parent's power state up to this
* point, the fact that the device is in D0 implies that the parent has
* to be in D0 too.
* to be in D0 too, except if ignore_parent is set.
*/
if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
if (!device->power.flags.ignore_parent && device->parent
&& device->parent->power.state == ACPI_STATE_UNKNOWN
&& result == ACPI_STATE_D0)
device->parent->power.state = ACPI_STATE_D0;
@ -177,7 +178,8 @@ int acpi_device_set_power(struct acpi_device *device, int state)
acpi_power_state_string(state));
return -ENODEV;
}
if (device->parent && (state < device->parent->power.state)) {
if (!device->power.flags.ignore_parent &&
device->parent && (state < device->parent->power.state)) {
dev_warn(&device->dev,
"Cannot transition to power state %s for parent in %s\n",
acpi_power_state_string(state),

View File

@ -254,10 +254,12 @@ static int i2c_device_probe(struct device *dev)
client->flags & I2C_CLIENT_WAKE);
dev_dbg(dev, "probe\n");
acpi_dev_pm_attach(&client->dev, true);
status = driver->probe(client, i2c_match_id(driver->id_table, client));
if (status) {
client->driver = NULL;
i2c_set_clientdata(client, NULL);
acpi_dev_pm_detach(&client->dev, true);
}
return status;
}
@ -283,6 +285,7 @@ static int i2c_device_remove(struct device *dev)
client->driver = NULL;
i2c_set_clientdata(client, NULL);
}
acpi_dev_pm_detach(&client->dev, true);
return status;
}
@ -1111,8 +1114,10 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
if (ret < 0 || !info.addr)
return AE_OK;
adev->power.flags.ignore_parent = true;
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
if (!i2c_new_device(adapter, &info)) {
adev->power.flags.ignore_parent = false;
dev_err(&adapter->dev,
"failed to add I2C device %s from ACPI\n",
dev_name(&adev->dev));

View File

@ -240,15 +240,27 @@ EXPORT_SYMBOL_GPL(spi_bus_type);
static int spi_drv_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
struct spi_device *spi = to_spi_device(dev);
int ret;
return sdrv->probe(to_spi_device(dev));
acpi_dev_pm_attach(&spi->dev, true);
ret = sdrv->probe(spi);
if (ret)
acpi_dev_pm_detach(&spi->dev, true);
return ret;
}
static int spi_drv_remove(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
struct spi_device *spi = to_spi_device(dev);
int ret;
return sdrv->remove(to_spi_device(dev));
ret = sdrv->remove(spi);
acpi_dev_pm_detach(&spi->dev, true);
return ret;
}
static void spi_drv_shutdown(struct device *dev)
@ -1025,8 +1037,10 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
return AE_OK;
}
adev->power.flags.ignore_parent = true;
strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
if (spi_add_device(spi)) {
adev->power.flags.ignore_parent = false;
dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
dev_name(&adev->dev));
spi_dev_put(spi);

View File

@ -222,7 +222,8 @@ struct acpi_device_power_flags {
u32 power_resources:1; /* Power resources */
u32 inrush_current:1; /* Serialize Dx->D0 */
u32 power_removed:1; /* Optimize Dx->D0 */
u32 reserved:28;
u32 ignore_parent:1; /* Power is independent of parent power state */
u32 reserved:27;
};
struct acpi_device_power_state {