Skip to content

Commit b18c1ad

Browse files
Sakari Ailusrafaeljw
authored andcommitted
i2c: Allow an ACPI driver to manage the device's power state during probe
Enable drivers to tell ACPI that there's no need to power on a device for probe. Drivers should still perform this by themselves if there's a need to. In some cases powering on the device during probe is undesirable, and this change enables a driver to choose what fits best for it. Add a field called "flags" into struct i2c_driver for driver flags, and a flag I2C_DRV_ACPI_WAIVE_D0_PROBE to tell a driver supports probe in ACPI D states other than 0. Signed-off-by: Sakari Ailus <[email protected]> Reviewed-by: Tomasz Figa <[email protected]> Acked-by: Wolfram Sang <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent b340c7d commit b18c1ad

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

drivers/i2c/i2c-core-acpi.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,16 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
526526
}
527527
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
528528

529+
bool i2c_acpi_waive_d0_probe(struct device *dev)
530+
{
531+
struct i2c_driver *driver = to_i2c_driver(dev->driver);
532+
struct acpi_device *adev = ACPI_COMPANION(dev);
533+
534+
return driver->flags & I2C_DRV_ACPI_WAIVE_D0_PROBE &&
535+
adev && adev->power.state_for_enumeration >= adev->power.state;
536+
}
537+
EXPORT_SYMBOL_GPL(i2c_acpi_waive_d0_probe);
538+
529539
#ifdef CONFIG_ACPI_I2C_OPREGION
530540
static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
531541
u8 cmd, u8 *data, u8 data_len)

drivers/i2c/i2c-core-base.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,8 @@ static int i2c_device_probe(struct device *dev)
551551
if (status < 0)
552552
goto err_clear_wakeup_irq;
553553

554-
status = dev_pm_domain_attach(&client->dev, true);
554+
status = dev_pm_domain_attach(&client->dev,
555+
!i2c_acpi_waive_d0_probe(dev));
555556
if (status)
556557
goto err_clear_wakeup_irq;
557558

@@ -590,7 +591,7 @@ static int i2c_device_probe(struct device *dev)
590591
err_release_driver_resources:
591592
devres_release_group(&client->dev, client->devres_group_id);
592593
err_detach_pm_domain:
593-
dev_pm_domain_detach(&client->dev, true);
594+
dev_pm_domain_detach(&client->dev, !i2c_acpi_waive_d0_probe(dev));
594595
err_clear_wakeup_irq:
595596
dev_pm_clear_wake_irq(&client->dev);
596597
device_init_wakeup(&client->dev, false);
@@ -621,7 +622,7 @@ static void i2c_device_remove(struct device *dev)
621622

622623
devres_release_group(&client->dev, client->devres_group_id);
623624

624-
dev_pm_domain_detach(&client->dev, true);
625+
dev_pm_domain_detach(&client->dev, !i2c_acpi_waive_d0_probe(dev));
625626
if (!pm_runtime_status_suspended(&client->dev) && adap->bus_regulator)
626627
regulator_disable(adap->bus_regulator);
627628

include/linux/i2c.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define _LINUX_I2C_H
1212

1313
#include <linux/acpi.h> /* for acpi_handle */
14+
#include <linux/bits.h>
1415
#include <linux/mod_devicetable.h>
1516
#include <linux/device.h> /* for struct device */
1617
#include <linux/sched.h> /* for completion */
@@ -222,6 +223,15 @@ enum i2c_alert_protocol {
222223
I2C_PROTOCOL_SMBUS_HOST_NOTIFY,
223224
};
224225

226+
/**
227+
* enum i2c_driver_flags - Flags for an I2C device driver
228+
*
229+
* @I2C_DRV_ACPI_WAIVE_D0_PROBE: Don't put the device in D0 state for probe
230+
*/
231+
enum i2c_driver_flags {
232+
I2C_DRV_ACPI_WAIVE_D0_PROBE = BIT(0),
233+
};
234+
225235
/**
226236
* struct i2c_driver - represent an I2C device driver
227237
* @class: What kind of i2c device we instantiate (for detect)
@@ -236,6 +246,7 @@ enum i2c_alert_protocol {
236246
* @detect: Callback for device detection
237247
* @address_list: The I2C addresses to probe (for detect)
238248
* @clients: List of detected clients we created (for i2c-core use only)
249+
* @flags: A bitmask of flags defined in &enum i2c_driver_flags
239250
*
240251
* The driver.owner field should be set to the module owner of this driver.
241252
* The driver.name field should be set to the name of this driver.
@@ -294,6 +305,8 @@ struct i2c_driver {
294305
int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
295306
const unsigned short *address_list;
296307
struct list_head clients;
308+
309+
u32 flags;
297310
};
298311
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
299312

@@ -1015,6 +1028,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev);
10151028
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
10161029
struct i2c_board_info *info);
10171030
struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle);
1031+
bool i2c_acpi_waive_d0_probe(struct device *dev);
10181032
#else
10191033
static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
10201034
struct acpi_resource_i2c_serialbus **i2c)
@@ -1038,6 +1052,10 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha
10381052
{
10391053
return NULL;
10401054
}
1055+
static inline bool i2c_acpi_waive_d0_probe(struct device *dev)
1056+
{
1057+
return false;
1058+
}
10411059
#endif /* CONFIG_ACPI */
10421060

10431061
#endif /* _LINUX_I2C_H */

0 commit comments

Comments
 (0)