usb: dwc3: rockchip: force dwc3 suspend immediately after disconneted
[firefly-linux-kernel-4.4.55.git] / drivers / i2c / i2c-mux.c
index 7409ebb33c47df7166087f937d0d5eb91d9d70c9..00fc5b1c7b66bb20f6ab1a54e6add6875f546c48 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/of.h>
-#include <linux/of_i2c.h>
+#include <linux/acpi.h>
 
 /* multiplexer per channel data */
 struct i2c_mux_priv {
@@ -33,8 +33,9 @@ struct i2c_mux_priv {
        struct i2c_algorithm algo;
 
        struct i2c_adapter *parent;
-       void *mux_priv; /* the mux chip/device */
-       u32  chan_id;   /* the channel id */
+       struct device *mux_dev;
+       void *mux_priv;
+       u32 chan_id;
 
        int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
        int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
@@ -51,7 +52,7 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 
        ret = priv->select(parent, priv->mux_priv, priv->chan_id);
        if (ret >= 0)
-               ret = parent->algo->master_xfer(parent, msgs, num);
+               ret = __i2c_transfer(parent, msgs, num);
        if (priv->deselect)
                priv->deselect(parent, priv->mux_priv, priv->chan_id);
 
@@ -111,6 +112,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
                                                 void *, u32))
 {
        struct i2c_mux_priv *priv;
+       char symlink_name[20];
        int ret;
 
        priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
@@ -119,6 +121,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 
        /* Set up private adapter data */
        priv->parent = parent;
+       priv->mux_dev = mux_dev;
        priv->mux_priv = mux_priv;
        priv->chan_id = chan_id;
        priv->select = select;
@@ -140,6 +143,9 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
        priv->adap.algo = &priv->algo;
        priv->adap.algo_data = priv;
        priv->adap.dev.parent = &parent->dev;
+       priv->adap.retries = parent->retries;
+       priv->adap.timeout = parent->timeout;
+       priv->adap.quirks = parent->quirks;
 
        /* Sanity check on class */
        if (i2c_mux_parent_classes(parent) & class)
@@ -168,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);
@@ -182,11 +195,15 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
                return NULL;
        }
 
+       WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
+                              "can't create symlink to mux device\n");
+
+       snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
+       WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
+                              "can't create symlink for channel %u\n", chan_id);
        dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
                 i2c_adapter_id(&priv->adap));
 
-       of_i2c_register_devices(&priv->adap);
-
        return &priv->adap;
 }
 EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
@@ -194,7 +211,12 @@ EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
 void i2c_del_mux_adapter(struct i2c_adapter *adap)
 {
        struct i2c_mux_priv *priv = adap->algo_data;
+       char symlink_name[20];
+
+       snprintf(symlink_name, sizeof(symlink_name), "channel-%u", priv->chan_id);
+       sysfs_remove_link(&priv->mux_dev->kobj, symlink_name);
 
+       sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
        i2c_del_adapter(adap);
        kfree(priv);
 }