]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
i2c: add ACPI support for I2C mux ports
authorDustin Byford <dustin@cumulusnetworks.com>
Fri, 23 Oct 2015 19:27:07 +0000 (12:27 -0700)
committerWolfram Sang <wsa@the-dreams.de>
Sun, 25 Oct 2015 14:49:46 +0000 (15:49 +0100)
Although I2C mux devices are easily enumerated using ACPI (_HID/_CID or
device property compatible string match), enumerating I2C client devices
connected through an I2C mux needs a little extra work.

This change implements a method for describing an I2C device hierarchy that
includes mux devices by using an ACPI Device() for each mux channel along
with an _ADR to set the channel number for the device.  See
Documentation/acpi/i2c-muxes.txt for a simple example.

To make this work the ismt, i801, and designware pci/platform devs now
share an ACPI companion with their I2C adapter dev similar to how it's done
in OF.  This is done on the assumption that power management functions will
not be called directly on the I2C dev that is sharing the ACPI node.

Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Dustin Byford <dustin@cumulusnetworks.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Documentation/acpi/i2c-muxes.txt [new file with mode: 0644]
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-mux.c

diff --git a/Documentation/acpi/i2c-muxes.txt b/Documentation/acpi/i2c-muxes.txt
new file mode 100644 (file)
index 0000000..9fcc4f0
--- /dev/null
@@ -0,0 +1,58 @@
+ACPI I2C Muxes
+--------------
+
+Describing an I2C device hierarchy that includes I2C muxes requires an ACPI
+Device () scope per mux channel.
+
+Consider this topology:
+
++------+   +------+
+| SMB1 |-->| MUX0 |--CH00--> i2c client A (0x50)
+|      |   | 0x70 |--CH01--> i2c client B (0x50)
++------+   +------+
+
+which corresponds to the following ASL:
+
+Device (SMB1)
+{
+    Name (_HID, ...)
+    Device (MUX0)
+    {
+        Name (_HID, ...)
+        Name (_CRS, ResourceTemplate () {
+            I2cSerialBus (0x70, ControllerInitiated, I2C_SPEED,
+                          AddressingMode7Bit, "^SMB1", 0x00,
+                          ResourceConsumer,,)
+        }
+
+        Device (CH00)
+        {
+            Name (_ADR, 0)
+
+            Device (CLIA)
+            {
+                Name (_HID, ...)
+                Name (_CRS, ResourceTemplate () {
+                    I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
+                                  AddressingMode7Bit, "^CH00", 0x00,
+                                  ResourceConsumer,,)
+                }
+            }
+        }
+
+        Device (CH01)
+        {
+            Name (_ADR, 1)
+
+            Device (CLIB)
+            {
+                Name (_HID, ...)
+                Name (_CRS, ResourceTemplate () {
+                    I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
+                                  AddressingMode7Bit, "^CH01", 0x00,
+                                  ResourceConsumer,,)
+                }
+            }
+        }
+    }
+}
index 169be1e2624101a43f8f6806fec0ad76d811f530..1543d35d228dfaf9c02f9b19a3a59c82503d0870 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <linux/acpi.h>
 #include "i2c-designware-core.h"
 
 #define DRIVER_NAME "i2c-designware-pci"
@@ -244,6 +245,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
        adap = &dev->adapter;
        adap->owner = THIS_MODULE;
        adap->class = 0;
+       ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
        adap->nr = controller->bus_num;
 
        r = i2c_dw_probe(dev);
index f830da6bf25a8ac184be22619a784cc0b95feaf3..190a0d2b94e79edf4208e7d07193918a5762a486 100644 (file)
@@ -207,6 +207,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
        adap = &dev->adapter;
        adap->owner = THIS_MODULE;
        adap->class = I2C_CLASS_DEPRECATED;
+       ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
        adap->dev.of_node = pdev->dev.of_node;
 
        r = i2c_dw_probe(dev);
index d8219bc2ac4ea6faa90e27734fe892b24610bb73..c306751ceadb44c24757b02281de24779038b1cb 100644 (file)
@@ -1257,6 +1257,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
        priv->adapter.owner = THIS_MODULE;
        priv->adapter.class = i801_get_adapter_class(priv);
        priv->adapter.algo = &smbus_algorithm;
+       priv->adapter.dev.parent = &dev->dev;
+       ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
+       priv->adapter.retries = 3;
 
        priv->pci_dev = dev;
        switch (dev->device) {
@@ -1388,12 +1391,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        i801_add_tco(priv);
 
-       /* set up the sysfs linkage to our parent device */
-       priv->adapter.dev.parent = &dev->dev;
-
-       /* Retry up to 3 times on lost arbitration */
-       priv->adapter.retries = 3;
-
        snprintf(priv->adapter.name, sizeof(priv->adapter.name),
                "SMBus I801 adapter at %04lx", priv->smba);
        err = i2c_add_adapter(&priv->adapter);
index 80648be36cce8840d6f853423dda58def46aa6ce..ebff8205a000b949887c8e7c2f6d8300d3438026 100644 (file)
@@ -842,17 +842,13 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENOMEM;
 
        pci_set_drvdata(pdev, priv);
+
        i2c_set_adapdata(&priv->adapter, priv);
        priv->adapter.owner = THIS_MODULE;
-
        priv->adapter.class = I2C_CLASS_HWMON;
-
        priv->adapter.algo = &smbus_algorithm;
-
-       /* set up the sysfs linkage to our parent device */
        priv->adapter.dev.parent = &pdev->dev;
-
-       /* number of retries on lost arbitration */
+       ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
        priv->adapter.retries = ISMT_MAX_RETRIES;
 
        priv->pci_dev = pdev;
index 3a4c54ef290dd496f43027349c9d13ad54f75446..5897fdb2480d3497169a9f2f2712c85ef3b36338 100644 (file)
@@ -156,7 +156,7 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
        info.fwnode = acpi_fwnode_handle(adev);
 
        memset(&lookup, 0, sizeof(lookup));
-       lookup.adapter_handle = ACPI_HANDLE(adapter->dev.parent);
+       lookup.adapter_handle = ACPI_HANDLE(&adapter->dev);
        lookup.device_handle = handle;
        lookup.info = &info;
 
@@ -212,7 +212,7 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap)
 {
        acpi_status status;
 
-       if (!adap->dev.parent || !has_acpi_companion(adap->dev.parent))
+       if (!has_acpi_companion(&adap->dev))
                return;
 
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
index 2ba7c0fbc6150b46835dffdae06de3cd5f8617d1..00fc5b1c7b66bb20f6ab1a54e6add6875f546c48 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/of.h>
+#include <linux/acpi.h>
 
 /* multiplexer per channel data */
 struct i2c_mux_priv {
@@ -173,6 +174,13 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
                }
        }
 
+       /*
+        * Associate the mux channel with an ACPI node.
+        */
+       if (has_acpi_companion(mux_dev))
+               acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
+                                     chan_id);
+
        if (force_nr) {
                priv->adap.nr = force_nr;
                ret = i2c_add_numbered_adapter(&priv->adap);