Merge tag 'acpi-5.16-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Nov 2021 19:52:40 +0000 (11:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Nov 2021 19:52:40 +0000 (11:52 -0800)
Pull more ACPI updates from Rafael Wysocki:
 "These add support for a new ACPI device configuration object called
  _DSC, fix some issues including one recent regression, add two new
  items to quirk lists and clean up assorted pieces of code.

  Specifics:

   - Add support for new ACPI device configuration object called _DSC
     ("Deepest State for Configuration") to allow certain devices to be
     probed without changing their power states, document it and make
     two drivers use it (Sakari Ailus, Rajmohan Mani).

   - Fix device wakeup power reference counting broken recently by
     mistake (Rafael Wysocki).

   - Drop unused symbol and macros depending on it from acgcc.h (Rafael
     Wysocki).

   - Add HP ZHAN 66 Pro to the "no EC wakeup" quirk list (Binbin Zhou).

   - Add Xiaomi Mi Pad 2 to the backlight quirk list and drop an unused
     piece of data from all of the list entries (Hans de Goede).

   - Fix register read accesses handling in the Intel PMIC operation
     region driver (Hans de Goede).

   - Clean up static variables initialization in the EC driver
     (wangzhitong)"

* tag 'acpi-5.16-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  Documentation: ACPI: Fix non-D0 probe _DSC object example
  ACPI: Drop ACPI_USE_BUILTIN_STDARG ifdef from acgcc.h
  ACPI: PM: Fix device wakeup power reference counting error
  ACPI: video: use platform backlight driver on Xiaomi Mi Pad 2
  ACPI: video: Drop dmi_system_id.ident settings from video_detect_dmi_table[]
  ACPI: PMIC: Fix intel_pmic_regs_handler() read accesses
  ACPI: EC: Remove initialization of static variables to false
  ACPI: EC: Use ec_no_wakeup on HP ZHAN 66 Pro
  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

16 files changed:
Documentation/firmware-guide/acpi/index.rst
Documentation/firmware-guide/acpi/non-d0-probe.rst [new file with mode: 0644]
drivers/acpi/device_pm.c
drivers/acpi/ec.c
drivers/acpi/pmic/intel_pmic.c
drivers/acpi/power.c
drivers/acpi/scan.c
drivers/acpi/video_detect.c
drivers/i2c/i2c-core-acpi.c
drivers/i2c/i2c-core-base.c
drivers/media/i2c/imx319.c
drivers/misc/eeprom/at24.c
include/acpi/acpi_bus.h
include/acpi/platform/acgcc.h
include/linux/acpi.h
include/linux/i2c.h

index a99ee40..b053b0c 100644 (file)
@@ -26,5 +26,6 @@ ACPI Support
    acpi-lid
    lpit
    video_extension
+   non-d0-probe
    extcon-intel-int3496
    intel-pmc-mux
diff --git a/Documentation/firmware-guide/acpi/non-d0-probe.rst b/Documentation/firmware-guide/acpi/non-d0-probe.rst
new file mode 100644 (file)
index 0000000..7afd167
--- /dev/null
@@ -0,0 +1,78 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================================
+Probing devices in other D states than 0
+========================================
+
+Introduction
+============
+
+In some cases it may be preferred to leave certain devices powered off for the
+entire system bootup if powering on these devices has adverse side effects,
+beyond just powering on the said device.
+
+How it works
+============
+
+The _DSC (Device State for Configuration) object that evaluates to an integer
+may be used to tell Linux the highest allowed D state for a device during
+probe. The support for _DSC requires support from the kernel bus type if the
+bus driver normally sets the device in D0 state for probe.
+
+The downside of using _DSC is that as the device is not powered on, even if
+there's a problem with the device, the driver likely probes just fine but the
+first user will find out the device doesn't work, instead of a failure at probe
+time. This feature should thus be used sparingly.
+
+I²C
+---
+
+If an I²C driver indicates its support for this by setting the
+I2C_DRV_ACPI_WAIVE_D0_PROBE flag in struct i2c_driver.flags field and the
+_DSC object evaluates to integer higher than the D state of the device,
+the device will not be powered on (put in D0 state) for probe.
+
+D states
+--------
+
+The D states and thus also the allowed values for _DSC are listed below. Refer
+to [1] for more information on device power states.
+
+.. code-block:: text
+
+       Number  State   Description
+       0       D0      Device fully powered on
+       1       D1
+       2       D2
+       3       D3hot
+       4       D3cold  Off
+
+References
+==========
+
+[1] https://uefi.org/specifications/ACPI/6.4/02_Definition_of_Terms/Definition_of_Terms.html#device-power-state-definitions
+
+Example
+=======
+
+An ASL example describing an ACPI device using _DSC object to tell Operating
+System the device should remain powered off during probe looks like this. Some
+objects not relevant from the example point of view have been omitted.
+
+.. code-block:: text
+
+       Device (CAM0)
+       {
+               Name (_HID, "SONY319A")
+               Name (_UID, Zero)
+               Name (_CRS, ResourceTemplate ()
+               {
+                       I2cSerialBus(0x0020, ControllerInitiated, 0x00061A80,
+                                    AddressingMode7Bit, "\\_SB.PCI0.I2C0",
+                                    0x00, ResourceConsumer)
+               })
+               Method (_DSC, 0, NotSerialized)
+               {
+                       Return (0x4)
+               }
+       }
index 0028b6b..19b33c0 100644 (file)
@@ -1400,4 +1400,30 @@ bool acpi_storage_d3(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(acpi_storage_d3);
 
+/**
+ * acpi_dev_state_d0 - Tell if the device is in D0 power state
+ * @dev: Physical device the ACPI power state of which to check
+ *
+ * On a system without ACPI, return true. On a system with ACPI, return true if
+ * the current ACPI power state of the device is D0, or false otherwise.
+ *
+ * Note that the power state of a device is not well-defined after it has been
+ * passed to acpi_device_set_power() and before that function returns, so it is
+ * not valid to ask for the ACPI power state of the device in that time frame.
+ *
+ * This function is intended to be used in a driver's probe or remove
+ * function. See Documentation/firmware-guide/acpi/low-power-probe.rst for
+ * more information.
+ */
+bool acpi_dev_state_d0(struct device *dev)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       if (!adev)
+               return true;
+
+       return adev->power.state == ACPI_STATE_D0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_state_d0);
+
 #endif /* CONFIG_PM */
index e629e89..a6366d3 100644 (file)
@@ -133,7 +133,7 @@ static unsigned int ec_storm_threshold  __read_mostly = 8;
 module_param(ec_storm_threshold, uint, 0644);
 MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm");
 
-static bool ec_freeze_events __read_mostly = false;
+static bool ec_freeze_events __read_mostly;
 module_param(ec_freeze_events, bool, 0644);
 MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume");
 
@@ -177,7 +177,7 @@ struct acpi_ec *first_ec;
 EXPORT_SYMBOL(first_ec);
 
 static struct acpi_ec *boot_ec;
-static bool boot_ec_is_ecdt = false;
+static bool boot_ec_is_ecdt;
 static struct workqueue_struct *ec_wq;
 static struct workqueue_struct *ec_query_wq;
 
@@ -2152,6 +2152,13 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = {
                        DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Yoga 3rd"),
                },
        },
+       {
+               .ident = "HP ZHAN 66 Pro",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_FAMILY, "103C_5336AN HP ZHAN 66 Pro"),
+               },
+       },
        { },
 };
 
index a371f27..9cde299 100644 (file)
@@ -211,31 +211,36 @@ static acpi_status intel_pmic_regs_handler(u32 function,
                void *handler_context, void *region_context)
 {
        struct intel_pmic_opregion *opregion = region_context;
-       int result = 0;
+       int result = -EINVAL;
+
+       if (function == ACPI_WRITE) {
+               switch (address) {
+               case 0:
+                       return AE_OK;
+               case 1:
+                       opregion->ctx.addr |= (*value64 & 0xff) << 8;
+                       return AE_OK;
+               case 2:
+                       opregion->ctx.addr |= *value64 & 0xff;
+                       return AE_OK;
+               case 3:
+                       opregion->ctx.val = *value64 & 0xff;
+                       return AE_OK;
+               case 4:
+                       if (*value64) {
+                               result = regmap_write(opregion->regmap, opregion->ctx.addr,
+                                                     opregion->ctx.val);
+                       } else {
+                               result = regmap_read(opregion->regmap, opregion->ctx.addr,
+                                                    &opregion->ctx.val);
+                       }
+                       opregion->ctx.addr = 0;
+               }
+       }
 
-       switch (address) {
-       case 0:
-               return AE_OK;
-       case 1:
-               opregion->ctx.addr |= (*value64 & 0xff) << 8;
-               return AE_OK;
-       case 2:
-               opregion->ctx.addr |= *value64 & 0xff;
+       if (function == ACPI_READ && address == 3) {
+               *value64 = opregion->ctx.val;
                return AE_OK;
-       case 3:
-               opregion->ctx.val = *value64 & 0xff;
-               return AE_OK;
-       case 4:
-               if (*value64) {
-                       result = regmap_write(opregion->regmap, opregion->ctx.addr,
-                                             opregion->ctx.val);
-               } else {
-                       result = regmap_read(opregion->regmap, opregion->ctx.addr,
-                                            &opregion->ctx.val);
-                       if (result == 0)
-                               *value64 = opregion->ctx.val;
-               }
-               memset(&opregion->ctx, 0x00, sizeof(opregion->ctx));
        }
 
        if (result < 0) {
index 1122561..5dcb02e 100644 (file)
@@ -757,13 +757,11 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
 
        mutex_lock(&acpi_device_lock);
 
-       if (dev->wakeup.prepare_count > 1) {
-               dev->wakeup.prepare_count--;
+       /* Do nothing if wakeup power has not been enabled for this device. */
+       if (dev->wakeup.prepare_count <= 0)
                goto out;
-       }
 
-       /* Do nothing if wakeup power has not been enabled for this device. */
-       if (!dev->wakeup.prepare_count)
+       if (--dev->wakeup.prepare_count > 0)
                goto out;
 
        err = acpi_device_sleep_wake(dev, 0, 0, 0);
index dce2c29..a50f196 100644 (file)
@@ -1017,6 +1017,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
 
 static void acpi_bus_get_power_flags(struct acpi_device *device)
 {
+       unsigned long long dsc = ACPI_STATE_D0;
        u32 i;
 
        /* Presence of _PS0|_PR0 indicates 'power manageable' */
@@ -1038,6 +1039,9 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
        if (acpi_has_method(device->handle, "_DSW"))
                device->power.flags.dsw_present = 1;
 
+       acpi_evaluate_integer(device->handle, "_DSC", NULL, &dsc);
+       device->power.state_for_enumeration = dsc;
+
        /*
         * Enumerate supported power management states
         */
index 33474fd..068e393 100644 (file)
@@ -115,7 +115,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
         */
        {
         .callback = video_detect_force_vendor,
-        .ident = "X360",
+        /* X360 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
@@ -124,7 +124,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_vendor,
-       .ident = "Asus UL30VT",
+       /* Asus UL30VT */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
@@ -132,7 +132,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_vendor,
-       .ident = "Asus UL30A",
+       /* Asus UL30A */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
@@ -140,7 +140,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_vendor,
-       .ident = "GIGABYTE GB-BXBT-2807",
+       /* GIGABYTE GB-BXBT-2807 */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
                DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
@@ -148,12 +148,20 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_vendor,
-       .ident = "Sony VPCEH3U1E",
+       /* Sony VPCEH3U1E */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
                DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
                },
        },
+       {
+       .callback = video_detect_force_vendor,
+       /* Xiaomi Mi Pad 2 */
+       .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
+               },
+       },
 
        /*
         * These models have a working acpi_video backlight control, and using
@@ -164,7 +172,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
         */
        {
         .callback = video_detect_force_video,
-        .ident = "ThinkPad T420",
+        /* ThinkPad T420 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
@@ -172,7 +180,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_video,
-        .ident = "ThinkPad T520",
+        /* ThinkPad T520 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
@@ -180,7 +188,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_video,
-        .ident = "ThinkPad X201s",
+        /* ThinkPad X201s */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
@@ -188,7 +196,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_video,
-        .ident = "ThinkPad X201T",
+        /* ThinkPad X201T */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
@@ -199,7 +207,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
         .callback = video_detect_force_video,
-        .ident = "HP ENVY 15 Notebook",
+        /* HP ENVY 15 Notebook */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
@@ -207,7 +215,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
+        /* SAMSUNG 870Z5E/880Z5E/680Z5E */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
@@ -215,7 +223,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
+        /* SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME,
@@ -225,7 +233,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
+        /* SAMSUNG 3570R/370R/470R/450R/510R/4450RV */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME,
@@ -235,7 +243,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 670Z5E",
+        /* SAMSUNG 670Z5E */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
@@ -244,7 +252,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 730U3E/740U3E",
+        /* SAMSUNG 730U3E/740U3E */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
@@ -253,7 +261,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
+        /* SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME,
@@ -263,7 +271,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */
         .callback = video_detect_force_video,
-        .ident = "Dell XPS14 L421X",
+        /* Dell XPS14 L421X */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
@@ -272,7 +280,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
         .callback = video_detect_force_video,
-        .ident = "Dell XPS15 L521X",
+        /* Dell XPS15 L521X */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
@@ -281,7 +289,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.kernel.org/show_bug.cgi?id=108971 */
         .callback = video_detect_force_video,
-        .ident = "SAMSUNG 530U4E/540U4E",
+        /* SAMSUNG 530U4E/540U4E */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
                DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
@@ -290,7 +298,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        /* https://bugs.launchpad.net/bugs/1894667 */
        {
         .callback = video_detect_force_video,
-        .ident = "HP 635 Notebook",
+        /* HP 635 Notebook */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
                DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"),
@@ -301,7 +309,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1201530 */
         .callback = video_detect_force_native,
-        .ident = "Lenovo Ideapad S405",
+        /* Lenovo Ideapad S405 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"),
@@ -310,7 +318,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
         .callback = video_detect_force_native,
-        .ident = "Lenovo Ideapad Z570",
+        /* Lenovo Ideapad Z570 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
@@ -318,7 +326,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
-        .ident = "Lenovo E41-25",
+        /* Lenovo E41-25 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_NAME, "81FS"),
@@ -326,7 +334,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
-        .ident = "Lenovo E41-45",
+        /* Lenovo E41-45 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
                DMI_MATCH(DMI_PRODUCT_NAME, "82BK"),
@@ -335,7 +343,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
         .callback = video_detect_force_native,
-        .ident = "Apple MacBook Pro 12,1",
+        /* Apple MacBook Pro 12,1 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
@@ -343,7 +351,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
-        .ident = "Dell Vostro V131",
+        /* Dell Vostro V131 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
@@ -352,7 +360,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */
         .callback = video_detect_force_native,
-        .ident = "Dell XPS 17 L702X",
+        /* Dell XPS 17 L702X */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
@@ -360,7 +368,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
-        .ident = "Dell Precision 7510",
+        /* Dell Precision 7510 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"),
@@ -368,7 +376,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
-        .ident = "Acer Aspire 5738z",
+        /* Acer Aspire 5738z */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
@@ -378,7 +386,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        {
         /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
         .callback = video_detect_force_native,
-        .ident = "Acer TravelMate 5735Z",
+        /* Acer TravelMate 5735Z */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
                DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
@@ -387,7 +395,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_native,
-       .ident = "ASUSTeK COMPUTER INC. GA401",
+       /* ASUSTeK COMPUTER INC. GA401 */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
@@ -395,7 +403,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_native,
-       .ident = "ASUSTeK COMPUTER INC. GA502",
+       /* ASUSTeK COMPUTER INC. GA502 */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
@@ -403,7 +411,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
        .callback = video_detect_force_native,
-       .ident = "ASUSTeK COMPUTER INC. GA503",
+       /* ASUSTeK COMPUTER INC. GA503 */
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
@@ -416,7 +424,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
         */
        {
         .callback = video_detect_force_none,
-        .ident = "Dell OptiPlex 9020M",
+        /* Dell OptiPlex 9020M */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"),
@@ -424,7 +432,7 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_none,
-        .ident = "MSI MS-7721",
+        /* MSI MS-7721 */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
                DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"),
index 80631f9..92c1cc0 100644 (file)
@@ -522,6 +522,16 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
 }
 EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
 
+bool i2c_acpi_waive_d0_probe(struct device *dev)
+{
+       struct i2c_driver *driver = to_i2c_driver(dev->driver);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       return driver->flags & I2C_DRV_ACPI_WAIVE_D0_PROBE &&
+               adev && adev->power.state_for_enumeration >= adev->power.state;
+}
+EXPORT_SYMBOL_GPL(i2c_acpi_waive_d0_probe);
+
 #ifdef CONFIG_ACPI_I2C_OPREGION
 static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
                u8 cmd, u8 *data, u8 data_len)
index 54964fb..f193f90 100644 (file)
@@ -551,7 +551,8 @@ static int i2c_device_probe(struct device *dev)
        if (status < 0)
                goto err_clear_wakeup_irq;
 
-       status = dev_pm_domain_attach(&client->dev, true);
+       status = dev_pm_domain_attach(&client->dev,
+                                     !i2c_acpi_waive_d0_probe(dev));
        if (status)
                goto err_clear_wakeup_irq;
 
@@ -590,7 +591,7 @@ static int i2c_device_probe(struct device *dev)
 err_release_driver_resources:
        devres_release_group(&client->dev, client->devres_group_id);
 err_detach_pm_domain:
-       dev_pm_domain_detach(&client->dev, true);
+       dev_pm_domain_detach(&client->dev, !i2c_acpi_waive_d0_probe(dev));
 err_clear_wakeup_irq:
        dev_pm_clear_wake_irq(&client->dev);
        device_init_wakeup(&client->dev, false);
@@ -621,7 +622,7 @@ static void i2c_device_remove(struct device *dev)
 
        devres_release_group(&client->dev, client->devres_group_id);
 
-       dev_pm_domain_detach(&client->dev, true);
+       dev_pm_domain_detach(&client->dev, !i2c_acpi_waive_d0_probe(dev));
        if (!pm_runtime_status_suspended(&client->dev) && adap->bus_regulator)
                regulator_disable(adap->bus_regulator);
 
index dba0854..daa9768 100644 (file)
@@ -140,6 +140,8 @@ struct imx319 {
 
        /* Streaming on/off */
        bool streaming;
+       /* True if the device has been identified */
+       bool identified;
 };
 
 static const struct imx319_reg imx319_global_regs[] = {
@@ -2084,6 +2086,31 @@ imx319_set_pad_format(struct v4l2_subdev *sd,
        return 0;
 }
 
+/* Verify chip ID */
+static int imx319_identify_module(struct imx319 *imx319)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
+       int ret;
+       u32 val;
+
+       if (imx319->identified)
+               return 0;
+
+       ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val);
+       if (ret)
+               return ret;
+
+       if (val != IMX319_CHIP_ID) {
+               dev_err(&client->dev, "chip id mismatch: %x!=%x",
+                       IMX319_CHIP_ID, val);
+               return -EIO;
+       }
+
+       imx319->identified = true;
+
+       return 0;
+}
+
 /* Start streaming */
 static int imx319_start_streaming(struct imx319 *imx319)
 {
@@ -2091,6 +2118,10 @@ static int imx319_start_streaming(struct imx319 *imx319)
        const struct imx319_reg_list *reg_list;
        int ret;
 
+       ret = imx319_identify_module(imx319);
+       if (ret)
+               return ret;
+
        /* Global Setting */
        reg_list = &imx319_global_setting;
        ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs);
@@ -2206,26 +2237,6 @@ error:
        return ret;
 }
 
-/* Verify chip ID */
-static int imx319_identify_module(struct imx319 *imx319)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd);
-       int ret;
-       u32 val;
-
-       ret = imx319_read_reg(imx319, IMX319_REG_CHIP_ID, 2, &val);
-       if (ret)
-               return ret;
-
-       if (val != IMX319_CHIP_ID) {
-               dev_err(&client->dev, "chip id mismatch: %x!=%x",
-                       IMX319_CHIP_ID, val);
-               return -EIO;
-       }
-
-       return 0;
-}
-
 static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = {
        .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
        .unsubscribe_event = v4l2_event_subdev_unsubscribe,
@@ -2420,6 +2431,7 @@ out_err:
 static int imx319_probe(struct i2c_client *client)
 {
        struct imx319 *imx319;
+       bool full_power;
        int ret;
        u32 i;
 
@@ -2432,11 +2444,14 @@ static int imx319_probe(struct i2c_client *client)
        /* Initialize subdev */
        v4l2_i2c_subdev_init(&imx319->sd, client, &imx319_subdev_ops);
 
-       /* Check module identity */
-       ret = imx319_identify_module(imx319);
-       if (ret) {
-               dev_err(&client->dev, "failed to find sensor: %d", ret);
-               goto error_probe;
+       full_power = acpi_dev_state_d0(&client->dev);
+       if (full_power) {
+               /* Check module identity */
+               ret = imx319_identify_module(imx319);
+               if (ret) {
+                       dev_err(&client->dev, "failed to find sensor: %d", ret);
+                       goto error_probe;
+               }
        }
 
        imx319->hwcfg = imx319_get_hwcfg(&client->dev);
@@ -2488,11 +2503,9 @@ static int imx319_probe(struct i2c_client *client)
        if (ret < 0)
                goto error_media_entity;
 
-       /*
-        * Device is already turned on by i2c-core with ACPI domain PM.
-        * Enable runtime PM and turn off the device.
-        */
-       pm_runtime_set_active(&client->dev);
+       /* Set the device's state to active if it's in D0 state. */
+       if (full_power)
+               pm_runtime_set_active(&client->dev);
        pm_runtime_enable(&client->dev);
        pm_runtime_idle(&client->dev);
 
@@ -2545,6 +2558,7 @@ static struct i2c_driver imx319_i2c_driver = {
        },
        .probe_new = imx319_probe,
        .remove = imx319_remove,
+       .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
 };
 module_i2c_driver(imx319_i2c_driver);
 
index 305ffad..49ab656 100644 (file)
@@ -595,6 +595,7 @@ static int at24_probe(struct i2c_client *client)
        bool i2c_fn_i2c, i2c_fn_block;
        unsigned int i, num_addresses;
        struct at24_data *at24;
+       bool full_power;
        struct regmap *regmap;
        bool writable;
        u8 test_byte;
@@ -747,14 +748,16 @@ static int at24_probe(struct i2c_client *client)
 
        i2c_set_clientdata(client, at24);
 
-       err = regulator_enable(at24->vcc_reg);
-       if (err) {
-               dev_err(dev, "Failed to enable vcc regulator\n");
-               return err;
-       }
+       full_power = acpi_dev_state_d0(&client->dev);
+       if (full_power) {
+               err = regulator_enable(at24->vcc_reg);
+               if (err) {
+                       dev_err(dev, "Failed to enable vcc regulator\n");
+                       return err;
+               }
 
-       /* enable runtime pm */
-       pm_runtime_set_active(dev);
+               pm_runtime_set_active(dev);
+       }
        pm_runtime_enable(dev);
 
        at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
@@ -766,15 +769,18 @@ static int at24_probe(struct i2c_client *client)
        }
 
        /*
-        * Perform a one-byte test read to verify that the
-        * chip is functional.
+        * Perform a one-byte test read to verify that the chip is functional,
+        * unless powering on the device is to be avoided during probe (i.e.
+        * it's powered off right now).
         */
-       err = at24_read(at24, 0, &test_byte, 1);
-       if (err) {
-               pm_runtime_disable(dev);
-               if (!pm_runtime_status_suspended(dev))
-                       regulator_disable(at24->vcc_reg);
-               return -ENODEV;
+       if (full_power) {
+               err = at24_read(at24, 0, &test_byte, 1);
+               if (err) {
+                       pm_runtime_disable(dev);
+                       if (!pm_runtime_status_suspended(dev))
+                               regulator_disable(at24->vcc_reg);
+                       return -ENODEV;
+               }
        }
 
        pm_runtime_idle(dev);
@@ -794,9 +800,11 @@ static int at24_remove(struct i2c_client *client)
        struct at24_data *at24 = i2c_get_clientdata(client);
 
        pm_runtime_disable(&client->dev);
-       if (!pm_runtime_status_suspended(&client->dev))
-               regulator_disable(at24->vcc_reg);
-       pm_runtime_set_suspended(&client->dev);
+       if (acpi_dev_state_d0(&client->dev)) {
+               if (!pm_runtime_status_suspended(&client->dev))
+                       regulator_disable(at24->vcc_reg);
+               pm_runtime_set_suspended(&client->dev);
+       }
 
        return 0;
 }
@@ -833,6 +841,7 @@ static struct i2c_driver at24_driver = {
        .probe_new = at24_probe,
        .remove = at24_remove,
        .id_table = at24_ids,
+       .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
 };
 
 static int __init at24_init(void)
index 53b6e9f..480f920 100644 (file)
@@ -278,6 +278,7 @@ struct acpi_device_power {
        int state;              /* Current state */
        struct acpi_device_power_flags flags;
        struct acpi_device_power_state states[ACPI_D_STATE_COUNT];      /* Power states (D0-D3Cold) */
+       u8 state_for_enumeration; /* Deepest power state for enumeration */
 };
 
 struct acpi_dep_data {
index 20ecb00..33ad282 100644 (file)
 #ifndef __ACGCC_H__
 #define __ACGCC_H__
 
-/*
- * Use compiler specific <stdarg.h> is a good practice for even when
- * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
- */
 #ifndef va_arg
-#ifdef ACPI_USE_BUILTIN_STDARG
-typedef __builtin_va_list va_list;
-#define va_start(v, l)          __builtin_va_start(v, l)
-#define va_end(v)               __builtin_va_end(v)
-#define va_arg(v, l)            __builtin_va_arg(v, l)
-#define va_copy(d, s)           __builtin_va_copy(d, s)
-#else
 #ifdef __KERNEL__
 #include <linux/stdarg.h>
 #else
-/* Used to build acpi tools */
 #include <stdarg.h>
 #endif /* __KERNEL__ */
-#endif /* ACPI_USE_BUILTIN_STDARG */
 #endif /* ! va_arg */
 
 #define ACPI_INLINE             __inline__
index 375715b..143ce7e 100644 (file)
@@ -1014,6 +1014,7 @@ int acpi_subsys_runtime_suspend(struct device *dev);
 int acpi_subsys_runtime_resume(struct device *dev);
 int acpi_dev_pm_attach(struct device *dev, bool power_on);
 bool acpi_storage_d3(struct device *dev);
+bool acpi_dev_state_d0(struct device *dev);
 #else
 static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; }
 static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; }
@@ -1025,6 +1026,10 @@ static inline bool acpi_storage_d3(struct device *dev)
 {
        return false;
 }
+static inline bool acpi_dev_state_d0(struct device *dev)
+{
+       return true;
+}
 #endif
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_PM_SLEEP)
index 2ce3efb..16119ac 100644 (file)
@@ -11,6 +11,7 @@
 #define _LINUX_I2C_H
 
 #include <linux/acpi.h>                /* for acpi_handle */
+#include <linux/bits.h>
 #include <linux/mod_devicetable.h>
 #include <linux/device.h>      /* for struct device */
 #include <linux/sched.h>       /* for completion */
@@ -222,6 +223,15 @@ enum i2c_alert_protocol {
        I2C_PROTOCOL_SMBUS_HOST_NOTIFY,
 };
 
+/**
+ * enum i2c_driver_flags - Flags for an I2C device driver
+ *
+ * @I2C_DRV_ACPI_WAIVE_D0_PROBE: Don't put the device in D0 state for probe
+ */
+enum i2c_driver_flags {
+       I2C_DRV_ACPI_WAIVE_D0_PROBE = BIT(0),
+};
+
 /**
  * struct i2c_driver - represent an I2C device driver
  * @class: What kind of i2c device we instantiate (for detect)
@@ -236,6 +246,7 @@ enum i2c_alert_protocol {
  * @detect: Callback for device detection
  * @address_list: The I2C addresses to probe (for detect)
  * @clients: List of detected clients we created (for i2c-core use only)
+ * @flags: A bitmask of flags defined in &enum i2c_driver_flags
  *
  * The driver.owner field should be set to the module owner of this driver.
  * The driver.name field should be set to the name of this driver.
@@ -294,6 +305,8 @@ struct i2c_driver {
        int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
        const unsigned short *address_list;
        struct list_head clients;
+
+       u32 flags;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
@@ -1015,6 +1028,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev);
 struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
                                       struct i2c_board_info *info);
 struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle);
+bool i2c_acpi_waive_d0_probe(struct device *dev);
 #else
 static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
                                             struct acpi_resource_i2c_serialbus **i2c)
@@ -1038,6 +1052,10 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha
 {
        return NULL;
 }
+static inline bool i2c_acpi_waive_d0_probe(struct device *dev)
+{
+       return false;
+}
 #endif /* CONFIG_ACPI */
 
 #endif /* _LINUX_I2C_H */