Skip to content

Commit 2c49dab

Browse files
committed
Merge branch 'acpi-dsc'
Merge new ACPI device configuration object _DSC support for 5.16-rc1. * acpi-dsc: Documentation: ACPI: Fix non-D0 probe _DSC object example at24: Support probing while in non-zero ACPI D state media: i2c: imx319: Support device probe in non-zero ACPI D state ACPI: Add a convenience function to tell a device is in D0 state Documentation: ACPI: Document _DSC object usage for enum power state i2c: Allow an ACPI driver to manage the device's power state during probe ACPI: scan: Obtain device's desired enumeration power state
2 parents 452a3e7 + dff5acf commit 2c49dab

File tree

11 files changed

+218
-51
lines changed

11 files changed

+218
-51
lines changed

Documentation/firmware-guide/acpi/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ ACPI Support
2626
acpi-lid
2727
lpit
2828
video_extension
29+
non-d0-probe
2930
extcon-intel-int3496
3031
intel-pmc-mux
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
========================================
4+
Probing devices in other D states than 0
5+
========================================
6+
7+
Introduction
8+
============
9+
10+
In some cases it may be preferred to leave certain devices powered off for the
11+
entire system bootup if powering on these devices has adverse side effects,
12+
beyond just powering on the said device.
13+
14+
How it works
15+
============
16+
17+
The _DSC (Device State for Configuration) object that evaluates to an integer
18+
may be used to tell Linux the highest allowed D state for a device during
19+
probe. The support for _DSC requires support from the kernel bus type if the
20+
bus driver normally sets the device in D0 state for probe.
21+
22+
The downside of using _DSC is that as the device is not powered on, even if
23+
there's a problem with the device, the driver likely probes just fine but the
24+
first user will find out the device doesn't work, instead of a failure at probe
25+
time. This feature should thus be used sparingly.
26+
27+
I²C
28+
---
29+
30+
If an I²C driver indicates its support for this by setting the
31+
I2C_DRV_ACPI_WAIVE_D0_PROBE flag in struct i2c_driver.flags field and the
32+
_DSC object evaluates to integer higher than the D state of the device,
33+
the device will not be powered on (put in D0 state) for probe.
34+
35+
D states
36+
--------
37+
38+
The D states and thus also the allowed values for _DSC are listed below. Refer
39+
to [1] for more information on device power states.
40+
41+
.. code-block:: text
42+
43+
Number State Description
44+
0 D0 Device fully powered on
45+
1 D1
46+
2 D2
47+
3 D3hot
48+
4 D3cold Off
49+
50+
References
51+
==========
52+
53+
[1] https://uefi.org/specifications/ACPI/6.4/02_Definition_of_Terms/Definition_of_Terms.html#device-power-state-definitions
54+
55+
Example
56+
=======
57+
58+
An ASL example describing an ACPI device using _DSC object to tell Operating
59+
System the device should remain powered off during probe looks like this. Some
60+
objects not relevant from the example point of view have been omitted.
61+
62+
.. code-block:: text
63+
64+
Device (CAM0)
65+
{
66+
Name (_HID, "SONY319A")
67+
Name (_UID, Zero)
68+
Name (_CRS, ResourceTemplate ()
69+
{
70+
I2cSerialBus(0x0020, ControllerInitiated, 0x00061A80,
71+
AddressingMode7Bit, "\\_SB.PCI0.I2C0",
72+
0x00, ResourceConsumer)
73+
})
74+
Method (_DSC, 0, NotSerialized)
75+
{
76+
Return (0x4)
77+
}
78+
}

drivers/acpi/device_pm.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,4 +1400,30 @@ bool acpi_storage_d3(struct device *dev)
14001400
}
14011401
EXPORT_SYMBOL_GPL(acpi_storage_d3);
14021402

1403+
/**
1404+
* acpi_dev_state_d0 - Tell if the device is in D0 power state
1405+
* @dev: Physical device the ACPI power state of which to check
1406+
*
1407+
* On a system without ACPI, return true. On a system with ACPI, return true if
1408+
* the current ACPI power state of the device is D0, or false otherwise.
1409+
*
1410+
* Note that the power state of a device is not well-defined after it has been
1411+
* passed to acpi_device_set_power() and before that function returns, so it is
1412+
* not valid to ask for the ACPI power state of the device in that time frame.
1413+
*
1414+
* This function is intended to be used in a driver's probe or remove
1415+
* function. See Documentation/firmware-guide/acpi/low-power-probe.rst for
1416+
* more information.
1417+
*/
1418+
bool acpi_dev_state_d0(struct device *dev)
1419+
{
1420+
struct acpi_device *adev = ACPI_COMPANION(dev);
1421+
1422+
if (!adev)
1423+
return true;
1424+
1425+
return adev->power.state == ACPI_STATE_D0;
1426+
}
1427+
EXPORT_SYMBOL_GPL(acpi_dev_state_d0);
1428+
14031429
#endif /* CONFIG_PM */

drivers/acpi/scan.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
10171017

10181018
static void acpi_bus_get_power_flags(struct acpi_device *device)
10191019
{
1020+
unsigned long long dsc = ACPI_STATE_D0;
10201021
u32 i;
10211022

10221023
/* Presence of _PS0|_PR0 indicates 'power manageable' */
@@ -1038,6 +1039,9 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
10381039
if (acpi_has_method(device->handle, "_DSW"))
10391040
device->power.flags.dsw_present = 1;
10401041

1042+
acpi_evaluate_integer(device->handle, "_DSC", NULL, &dsc);
1043+
device->power.state_for_enumeration = dsc;
1044+
10411045
/*
10421046
* Enumerate supported power management states
10431047
*/

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

drivers/media/i2c/imx319.c

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ struct imx319 {
140140

141141
/* Streaming on/off */
142142
bool streaming;
143+
/* True if the device has been identified */
144+
bool identified;
143145
};
144146

145147
static const struct imx319_reg imx319_global_regs[] = {
@@ -2084,13 +2086,42 @@ imx319_set_pad_format(struct v4l2_subdev *sd,
20842086
return 0;
20852087
}
20862088

2089+
/* Verify chip ID */
2090+
static int imx319_identify_module(struct imx319 *imx319)
2091+
{
2092+
struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
2093+
int ret;
2094+
u32 val;
2095+
2096+
if (imx319->identified)
2097+
return 0;
2098+
2099+
ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val);
2100+
if (ret)
2101+
return ret;
2102+
2103+
if (val != IMX319_CHIP_ID) {
2104+
dev_err(&client->dev, "chip id mismatch: %x!=%x",
2105+
IMX319_CHIP_ID, val);
2106+
return -EIO;
2107+
}
2108+
2109+
imx319->identified = true;
2110+
2111+
return 0;
2112+
}
2113+
20872114
/* Start streaming */
20882115
static int imx319_start_streaming(struct imx319 *imx319)
20892116
{
20902117
struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
20912118
const struct imx319_reg_list *reg_list;
20922119
int ret;
20932120

2121+
ret = imx319_identify_module(imx319);
2122+
if (ret)
2123+
return ret;
2124+
20942125
/* Global Setting */
20952126
reg_list = &imx319_global_setting;
20962127
ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs);
@@ -2206,26 +2237,6 @@ static int __maybe_unused imx319_resume(struct device *dev)
22062237
return ret;
22072238
}
22082239

2209-
/* Verify chip ID */
2210-
static int imx319_identify_module(struct imx319 *imx319)
2211-
{
2212-
struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
2213-
int ret;
2214-
u32 val;
2215-
2216-
ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val);
2217-
if (ret)
2218-
return ret;
2219-
2220-
if (val != IMX319_CHIP_ID) {
2221-
dev_err(&client->dev, "chip id mismatch: %x!=%x",
2222-
IMX319_CHIP_ID, val);
2223-
return -EIO;
2224-
}
2225-
2226-
return 0;
2227-
}
2228-
22292240
static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = {
22302241
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
22312242
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
@@ -2420,6 +2431,7 @@ static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev)
24202431
static int imx319_probe(struct i2c_client *client)
24212432
{
24222433
struct imx319 *imx319;
2434+
bool full_power;
24232435
int ret;
24242436
u32 i;
24252437

@@ -2432,11 +2444,14 @@ static int imx319_probe(struct i2c_client *client)
24322444
/* Initialize subdev */
24332445
v4l2_i2c_subdev_init(&imx319->sd, client, &imx319_subdev_ops);
24342446

2435-
/* Check module identity */
2436-
ret = imx319_identify_module(imx319);
2437-
if (ret) {
2438-
dev_err(&client->dev, "failed to find sensor: %d", ret);
2439-
goto error_probe;
2447+
full_power = acpi_dev_state_d0(&client->dev);
2448+
if (full_power) {
2449+
/* Check module identity */
2450+
ret = imx319_identify_module(imx319);
2451+
if (ret) {
2452+
dev_err(&client->dev, "failed to find sensor: %d", ret);
2453+
goto error_probe;
2454+
}
24402455
}
24412456

24422457
imx319->hwcfg = imx319_get_hwcfg(&client->dev);
@@ -2488,11 +2503,9 @@ static int imx319_probe(struct i2c_client *client)
24882503
if (ret < 0)
24892504
goto error_media_entity;
24902505

2491-
/*
2492-
* Device is already turned on by i2c-core with ACPI domain PM.
2493-
* Enable runtime PM and turn off the device.
2494-
*/
2495-
pm_runtime_set_active(&client->dev);
2506+
/* Set the device's state to active if it's in D0 state. */
2507+
if (full_power)
2508+
pm_runtime_set_active(&client->dev);
24962509
pm_runtime_enable(&client->dev);
24972510
pm_runtime_idle(&client->dev);
24982511

@@ -2545,6 +2558,7 @@ static struct i2c_driver imx319_i2c_driver = {
25452558
},
25462559
.probe_new = imx319_probe,
25472560
.remove = imx319_remove,
2561+
.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
25482562
};
25492563
module_i2c_driver(imx319_i2c_driver);
25502564

drivers/misc/eeprom/at24.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ static int at24_probe(struct i2c_client *client)
595595
bool i2c_fn_i2c, i2c_fn_block;
596596
unsigned int i, num_addresses;
597597
struct at24_data *at24;
598+
bool full_power;
598599
struct regmap *regmap;
599600
bool writable;
600601
u8 test_byte;
@@ -747,14 +748,16 @@ static int at24_probe(struct i2c_client *client)
747748

748749
i2c_set_clientdata(client, at24);
749750

750-
err = regulator_enable(at24->vcc_reg);
751-
if (err) {
752-
dev_err(dev, "Failed to enable vcc regulator\n");
753-
return err;
754-
}
751+
full_power = acpi_dev_state_d0(&client->dev);
752+
if (full_power) {
753+
err = regulator_enable(at24->vcc_reg);
754+
if (err) {
755+
dev_err(dev, "Failed to enable vcc regulator\n");
756+
return err;
757+
}
755758

756-
/* enable runtime pm */
757-
pm_runtime_set_active(dev);
759+
pm_runtime_set_active(dev);
760+
}
758761
pm_runtime_enable(dev);
759762

760763
at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
@@ -766,15 +769,18 @@ static int at24_probe(struct i2c_client *client)
766769
}
767770

768771
/*
769-
* Perform a one-byte test read to verify that the
770-
* chip is functional.
772+
* Perform a one-byte test read to verify that the chip is functional,
773+
* unless powering on the device is to be avoided during probe (i.e.
774+
* it's powered off right now).
771775
*/
772-
err = at24_read(at24, 0, &test_byte, 1);
773-
if (err) {
774-
pm_runtime_disable(dev);
775-
if (!pm_runtime_status_suspended(dev))
776-
regulator_disable(at24->vcc_reg);
777-
return -ENODEV;
776+
if (full_power) {
777+
err = at24_read(at24, 0, &test_byte, 1);
778+
if (err) {
779+
pm_runtime_disable(dev);
780+
if (!pm_runtime_status_suspended(dev))
781+
regulator_disable(at24->vcc_reg);
782+
return -ENODEV;
783+
}
778784
}
779785

780786
pm_runtime_idle(dev);
@@ -794,9 +800,11 @@ static int at24_remove(struct i2c_client *client)
794800
struct at24_data *at24 = i2c_get_clientdata(client);
795801

796802
pm_runtime_disable(&client->dev);
797-
if (!pm_runtime_status_suspended(&client->dev))
798-
regulator_disable(at24->vcc_reg);
799-
pm_runtime_set_suspended(&client->dev);
803+
if (acpi_dev_state_d0(&client->dev)) {
804+
if (!pm_runtime_status_suspended(&client->dev))
805+
regulator_disable(at24->vcc_reg);
806+
pm_runtime_set_suspended(&client->dev);
807+
}
800808

801809
return 0;
802810
}
@@ -833,6 +841,7 @@ static struct i2c_driver at24_driver = {
833841
.probe_new = at24_probe,
834842
.remove = at24_remove,
835843
.id_table = at24_ids,
844+
.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
836845
};
837846

838847
static int __init at24_init(void)

include/acpi/acpi_bus.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ struct acpi_device_power {
278278
int state; /* Current state */
279279
struct acpi_device_power_flags flags;
280280
struct acpi_device_power_state states[ACPI_D_STATE_COUNT]; /* Power states (D0-D3Cold) */
281+
u8 state_for_enumeration; /* Deepest power state for enumeration */
281282
};
282283

283284
struct acpi_dep_data {

0 commit comments

Comments
 (0)