From: Peter Rosin <p...@axentia.se>

All muxes have slave side adapters, many have some arbitrary number of
them. Handle this in the mux core, so that drivers are simplified.

Add i2c_mux_reserve_adapter that can be used when it is known in advance
how many child adapters that is to be added. This avoids reallocating
memory.

Drop i2c_del_mux_adapter and replace it with i2c_del_mux_adapters, since
no mux driver is dynamically deleting individual child adapters anyway.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/i2c/i2c-mux.c                        | 71 ++++++++++++++++++++++------
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 10 ++--
 drivers/i2c/muxes/i2c-mux-gpio.c             | 23 +++------
 drivers/i2c/muxes/i2c-mux-pca9541.c          | 13 ++---
 drivers/i2c/muxes/i2c-mux-pca954x.c          | 26 ++++------
 drivers/i2c/muxes/i2c-mux-pinctrl.c          | 27 +++--------
 drivers/i2c/muxes/i2c-mux-reg.c              | 28 ++++-------
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 12 ++---
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 -
 drivers/media/dvb-frontends/m88ds3103.c      | 11 ++---
 drivers/media/dvb-frontends/m88ds3103_priv.h |  1 -
 drivers/media/dvb-frontends/rtl2830.c        | 10 ++--
 drivers/media/dvb-frontends/rtl2830_priv.h   |  1 -
 drivers/media/dvb-frontends/rtl2832.c        | 11 ++---
 drivers/media/dvb-frontends/rtl2832_priv.h   |  1 -
 drivers/media/dvb-frontends/si2168.c         | 10 ++--
 drivers/media/dvb-frontends/si2168_priv.h    |  1 -
 drivers/media/usb/cx231xx/cx231xx-core.c     |  3 +-
 drivers/media/usb/cx231xx/cx231xx-i2c.c      | 26 +++++-----
 drivers/media/usb/cx231xx/cx231xx.h          |  2 +-
 drivers/of/unittest.c                        | 28 ++++-------
 include/linux/i2c-mux.h                      | 15 ++++--
 22 files changed, 149 insertions(+), 182 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 6c5cb9f7649b..7ba0308537a8 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -99,6 +99,29 @@ static unsigned int i2c_mux_parent_classes(struct 
i2c_adapter *parent)
        return class;
 }
 
+int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
+{
+       struct i2c_adapter **adapter;
+
+       if (adapters <= muxc->max_adapters)
+               return 0;
+
+       adapter = devm_kmalloc_array(muxc->dev,
+                                    adapters, sizeof(*adapter),
+                                    GFP_KERNEL);
+       if (!adapter)
+               return -ENOMEM;
+
+       memcpy(adapter, muxc->adapter,
+              muxc->max_adapters * sizeof(*adapter));
+
+       devm_kfree(muxc->dev, muxc->adapter);
+       muxc->adapter = adapter;
+       muxc->max_adapters = adapters;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_reserve_adapters);
+
 struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 {
        struct i2c_mux_core *muxc;
@@ -113,19 +136,29 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, 
int sizeof_priv)
 }
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
 
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-                                       struct device *mux_dev,
-                                       u32 force_nr, u32 chan_id,
-                                       unsigned int class)
+int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
+                       struct device *mux_dev,
+                       u32 force_nr, u32 chan_id,
+                       unsigned int class)
 {
        struct i2c_adapter *parent = muxc->parent;
        struct i2c_mux_priv *priv;
        char symlink_name[20];
        int ret;
 
+       if (muxc->adapters >= muxc->max_adapters) {
+               int new_max = 2 * muxc->max_adapters;
+
+               if (!new_max)
+                       new_max = 1;
+               ret = i2c_mux_reserve_adapters(muxc, new_max);
+               if (ret)
+                       return ret;
+       }
+
        priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
        if (!priv)
-               return NULL;
+               return -ENOMEM;
 
        /* Set up private adapter data */
        priv->muxc = muxc;
@@ -197,7 +230,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core 
*muxc,
                        "failed to add mux-adapter (error=%d)\n",
                        ret);
                kfree(priv);
-               return NULL;
+               return ret;
        }
 
        WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, 
"mux_device"),
@@ -209,23 +242,31 @@ struct i2c_adapter *i2c_add_mux_adapter(struct 
i2c_mux_core *muxc,
        dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
                 i2c_adapter_id(&priv->adap));
 
-       return &priv->adap;
+       muxc->adapter[muxc->adapters++] = &priv->adap;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
 
-void i2c_del_mux_adapter(struct i2c_adapter *adap)
+void i2c_del_mux_adapters(struct i2c_mux_core *muxc)
 {
-       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);
+       while (muxc->adapters) {
+               struct i2c_adapter *adap = muxc->adapter[--muxc->adapters];
+               struct i2c_mux_priv *priv = adap->algo_data;
 
-       sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
-       i2c_del_adapter(adap);
-       kfree(priv);
+               muxc->adapter[muxc->adapters] = NULL;
+
+               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);
+       }
 }
-EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
+EXPORT_SYMBOL_GPL(i2c_del_mux_adapters);
 
 MODULE_AUTHOR("Rodolfo Giometti <giome...@linux.it>");
 MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c 
b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 1e1a479d5b61..e0558e8a0e74 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -42,7 +42,6 @@
  */
 
 struct i2c_arbitrator_data {
-       struct i2c_adapter *child;
        int our_gpio;
        int our_gpio_release;
        int their_gpio;
@@ -205,10 +204,9 @@ static int i2c_arbitrator_probe(struct platform_device 
*pdev)
        }
 
        /* Actually add the mux adapter */
-       arb->child = i2c_add_mux_adapter(muxc, dev, 0, 0, 0);
-       if (!arb->child) {
+       ret = i2c_add_mux_adapter(muxc, dev, 0, 0, 0);
+       if (ret) {
                dev_err(dev, "Failed to add adapter\n");
-               ret = -ENODEV;
                i2c_put_adapter(muxc->parent);
        }
 
@@ -218,11 +216,9 @@ static int i2c_arbitrator_probe(struct platform_device 
*pdev)
 static int i2c_arbitrator_remove(struct platform_device *pdev)
 {
        struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
-       struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 
-       i2c_del_mux_adapter(arb->child);
+       i2c_del_mux_adapters(muxc);
        i2c_put_adapter(muxc->parent);
-
        return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index d89a0fbca4bc..6bd41ace81d4 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -18,7 +18,6 @@
 #include <linux/of_gpio.h>
 
 struct gpiomux {
-       struct i2c_adapter **adap; /* child busses */
        struct i2c_mux_gpio_platform_data data;
        unsigned gpio_base;
 };
@@ -182,14 +181,9 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
        muxc->select = i2c_mux_gpio_select;
        mux->gpio_base = gpio_base;
 
-       mux->adap = devm_kzalloc(&pdev->dev,
-                                sizeof(*mux->adap) * mux->data.n_values,
-                                GFP_KERNEL);
-       if (!mux->adap) {
-               dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
-               ret = -ENOMEM;
+       ret = i2c_mux_reserve_adapters(muxc, mux->data.n_values);
+       if (ret)
                goto alloc_failed;
-       }
 
        if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
                initial_state = mux->data.idle;
@@ -222,10 +216,9 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
                u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
                unsigned int class = mux->data.classes ? mux->data.classes[i] : 
0;
 
-               mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
-                                                  mux->data.values[i], class);
-               if (!mux->adap[i]) {
-                       ret = -ENODEV;
+               ret = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
+                                         mux->data.values[i], class);
+               if (ret) {
                        dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
                        goto add_adapter_failed;
                }
@@ -237,8 +230,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
        return 0;
 
 add_adapter_failed:
-       for (; i > 0; i--)
-               i2c_del_mux_adapter(mux->adap[i - 1]);
+       i2c_del_mux_adapters(muxc);
        i = mux->data.n_gpios;
 err_request_gpio:
        for (; i > 0; i--)
@@ -255,8 +247,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
        struct gpiomux *mux = i2c_mux_priv(muxc);
        int i;
 
-       for (i = 0; i < mux->data.n_values; i++)
-               i2c_del_mux_adapter(mux->adap[i]);
+       i2c_del_mux_adapters(muxc);
 
        for (i = 0; i < mux->data.n_gpios; i++)
                gpio_free(mux->gpio_base + mux->data.gpios[i]);
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c 
b/drivers/i2c/muxes/i2c-mux-pca9541.c
index ae42039459d0..80de0a0977a5 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -74,7 +74,6 @@
 
 struct pca9541 {
        struct i2c_client *client;
-       struct i2c_adapter *mux_adap;
        unsigned long select_timeout;
        unsigned long arb_timeout;
 };
@@ -332,6 +331,7 @@ static int pca9541_probe(struct i2c_client *client,
        struct i2c_mux_core *muxc;
        struct pca9541 *data;
        int force;
+       int ret;
 
        if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -361,11 +361,10 @@ static int pca9541_probe(struct i2c_client *client,
        force = 0;
        if (pdata)
                force = pdata->modes[0].adap_id;
-       data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, force, 0, 0);
-
-       if (data->mux_adap == NULL) {
+       ret = i2c_add_mux_adapter(muxc, &client->dev, force, 0, 0);
+       if (ret) {
                dev_err(&client->dev, "failed to register master selector\n");
-               return -ENODEV;
+               return ret;
        }
 
        dev_info(&client->dev, "registered master selector for I2C %s\n",
@@ -377,10 +376,8 @@ static int pca9541_probe(struct i2c_client *client,
 static int pca9541_remove(struct i2c_client *client)
 {
        struct i2c_mux_core *muxc = i2c_get_clientdata(client);
-       struct pca9541 *data = i2c_mux_priv(muxc);
-
-       i2c_del_mux_adapter(data->mux_adap);
 
+       i2c_del_mux_adapters(muxc);
        return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c 
b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 9e9d708fb2cb..640670b604f5 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -60,7 +60,6 @@ enum pca_type {
 
 struct pca954x {
        enum pca_type type;
-       struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
        u8 last_chan;           /* last register value */
        u8 deselect;
@@ -231,6 +230,10 @@ static int pca954x_probe(struct i2c_client *client,
        data->type = id->driver_data;
        data->last_chan = 0;               /* force the first selection */
 
+       ret = i2c_mux_reserve_adapters(muxc, chips[data->type].nchans);
+       if (ret)
+               return ret;
+
        idle_disconnect_dt = of_node &&
                of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
 
@@ -253,12 +256,10 @@ static int pca954x_probe(struct i2c_client *client,
                                           || idle_disconnect_dt) << num;
                }
 
-               data->virt_adaps[num] =
-                       i2c_add_mux_adapter(muxc, &client->dev,
-                                           force, num, class);
+               ret = i2c_add_mux_adapter(muxc, &client->dev,
+                                         force, num, class);
 
-               if (data->virt_adaps[num] == NULL) {
-                       ret = -ENODEV;
+               if (ret) {
                        dev_err(&client->dev,
                                "failed to register multiplexed adapter"
                                " %d as bus %d\n", num, force);
@@ -274,24 +275,15 @@ static int pca954x_probe(struct i2c_client *client,
        return 0;
 
 virt_reg_failed:
-       for (num--; num >= 0; num--)
-               i2c_del_mux_adapter(data->virt_adaps[num]);
+       i2c_del_mux_adapters(muxc);
        return ret;
 }
 
 static int pca954x_remove(struct i2c_client *client)
 {
        struct i2c_mux_core *muxc = i2c_get_clientdata(client);
-       struct pca954x *data = i2c_mux_priv(muxc);
-       const struct chip_desc *chip = &chips[data->type];
-       int i;
-
-       for (i = 0; i < chip->nchans; ++i)
-               if (data->virt_adaps[i]) {
-                       i2c_del_mux_adapter(data->virt_adaps[i]);
-                       data->virt_adaps[i] = NULL;
-               }
 
+       i2c_del_mux_adapters(muxc);
        return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c 
b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index e87c8f77037a..3bbb3fb1d693 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -31,7 +31,6 @@ struct i2c_mux_pinctrl {
        struct pinctrl *pinctrl;
        struct pinctrl_state **states;
        struct pinctrl_state *state_idle;
-       struct i2c_adapter **busses;
 };
 
 static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
@@ -163,14 +162,9 @@ static int i2c_mux_pinctrl_probe(struct platform_device 
*pdev)
                goto err;
        }
 
-       mux->busses = devm_kzalloc(&pdev->dev,
-                                  sizeof(*mux->busses) * mux->pdata->bus_count,
-                                  GFP_KERNEL);
-       if (!mux->busses) {
-               dev_err(&pdev->dev, "Cannot allocate busses\n");
-               ret = -ENOMEM;
+       ret = i2c_mux_reserve_adapters(muxc, mux->pdata->bus_count);
+       if (ret)
                goto err;
-       }
 
        mux->pinctrl = devm_pinctrl_get(&pdev->dev);
        if (IS_ERR(mux->pinctrl)) {
@@ -218,10 +212,9 @@ static int i2c_mux_pinctrl_probe(struct platform_device 
*pdev)
                u32 bus = mux->pdata->base_bus_num ?
                                (mux->pdata->base_bus_num + i) : 0;
 
-               mux->busses[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
-                                                    bus, i, 0);
-               if (!mux->busses[i]) {
-                       ret = -ENODEV;
+               ret = i2c_add_mux_adapter(muxc, &pdev->dev,
+                                         bus, i, 0);
+               if (ret) {
                        dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
                        goto err_del_adapter;
                }
@@ -230,8 +223,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device 
*pdev)
        return 0;
 
 err_del_adapter:
-       for (; i > 0; i--)
-               i2c_del_mux_adapter(mux->busses[i - 1]);
+       i2c_del_mux_adapters(muxc);
        i2c_put_adapter(muxc->parent);
 err:
        return ret;
@@ -240,14 +232,9 @@ err:
 static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
 {
        struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
-       struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
-       int i;
-
-       for (i = 0; i < mux->pdata->bus_count; i++)
-               i2c_del_mux_adapter(mux->busses[i]);
 
+       i2c_del_mux_adapters(muxc);
        i2c_put_adapter(muxc->parent);
-
        return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 3b01e7809a66..5c004ff5b6ad 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -21,7 +21,6 @@
 #include <linux/slab.h>
 
 struct regmux {
-       struct i2c_adapter **adap; /* child busses */
        struct i2c_mux_reg_platform_data data;
 };
 
@@ -214,13 +213,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       mux->adap = devm_kzalloc(&pdev->dev,
-                                sizeof(*mux->adap) * mux->data.n_values,
-                                GFP_KERNEL);
-       if (!mux->adap) {
-               dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
-               return -ENOMEM;
-       }
+       ret = i2c_mux_reserve_adapters(muxc, mux->data.n_values);
+       if (ret)
+               return ret;
 
        muxc->select = i2c_mux_reg_select;
        if (mux->data.idle_in_use)
@@ -232,11 +227,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
                nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
                class = mux->data.classes ? mux->data.classes[i] : 0;
 
-               mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
-                                                  nr, mux->data.values[i],
-                                                  class);
-               if (!mux->adap[i]) {
-                       ret = -ENODEV;
+               ret = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
+                                         mux->data.values[i], class);
+               if (ret) {
                        dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
                        goto add_adapter_failed;
                }
@@ -248,8 +241,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
        return 0;
 
 add_adapter_failed:
-       for (; i > 0; i--)
-               i2c_del_mux_adapter(mux->adap[i - 1]);
+       i2c_del_mux_adapters(muxc);
 
        return ret;
 }
@@ -257,12 +249,8 @@ add_adapter_failed:
 static int i2c_mux_reg_remove(struct platform_device *pdev)
 {
        struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
-       struct regmux *mux = i2c_mux_priv(muxc);
-       int i;
-
-       for (i = 0; i < mux->data.n_values; i++)
-               i2c_del_mux_adapter(mux->adap[i]);
 
+       i2c_del_mux_adapters(muxc);
        i2c_put_adapter(muxc->parent);
 
        return 0;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c 
b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 0a47396bc5be..a9a163c1c22c 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -850,13 +850,9 @@ static int inv_mpu_probe(struct i2c_client *client,
        st->muxc->select = inv_mpu6050_select_bypass;
        st->muxc->deselect = inv_mpu6050_deselect_bypass;
 
-       st->mux_adapter = i2c_add_mux_adapter(st->muxc,
-                                             &client->dev,
-                                             0, 0, 0);
-       if (!st->mux_adapter) {
-               result = -ENODEV;
+       result = i2c_add_mux_adapter(st->muxc, &client->dev, 0, 0, 0);
+       if (result)
                goto out_unreg_device;
-       }
 
        result = inv_mpu_acpi_create_mux_client(st);
        if (result)
@@ -865,7 +861,7 @@ static int inv_mpu_probe(struct i2c_client *client,
        return 0;
 
 out_del_mux:
-       i2c_del_mux_adapter(st->mux_adapter);
+       i2c_del_mux_adapters(st->muxc);
 out_unreg_device:
        iio_device_unregister(indio_dev);
 out_remove_trigger:
@@ -881,7 +877,7 @@ static int inv_mpu_remove(struct i2c_client *client)
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
        inv_mpu_acpi_delete_mux_client(st);
-       i2c_del_mux_adapter(st->mux_adapter);
+       i2c_del_mux_adapters(st->muxc);
        iio_device_unregister(indio_dev);
        inv_mpu6050_remove_trigger(st);
        iio_triggered_buffer_cleanup(indio_dev);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h 
b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index d4929db4b40e..72113b59132e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -121,7 +121,6 @@ struct inv_mpu6050_state {
        spinlock_t time_stamp_lock;
        struct i2c_client *client;
        struct i2c_mux_core *muxc;
-       struct i2c_adapter *mux_adapter;
        struct i2c_client *mux_client;
        unsigned int powerup_count;
        struct inv_mpu6050_platform_data plat_data;
diff --git a/drivers/media/dvb-frontends/m88ds3103.c 
b/drivers/media/dvb-frontends/m88ds3103.c
index c9f8296ea421..deab5cdba01f 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1374,7 +1374,7 @@ static struct i2c_adapter 
*m88ds3103_get_i2c_adapter(struct i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
-       return dev->i2c_adapter;
+       return dev->muxc->adapter[0];
 }
 
 static int m88ds3103_probe(struct i2c_client *client,
@@ -1476,12 +1476,9 @@ static int m88ds3103_probe(struct i2c_client *client,
        dev->muxc->select = m88ds3103_select;
 
        /* create mux i2c adapter for tuner */
-       dev->i2c_adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-                                              0, 0, 0);
-       if (dev->i2c_adapter == NULL) {
-               ret = -ENOMEM;
+       ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+       if (ret)
                goto err_kfree;
-       }
 
        /* create dvb_frontend */
        memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
@@ -1510,7 +1507,7 @@ static int m88ds3103_remove(struct i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
-       i2c_del_mux_adapter(dev->i2c_adapter);
+       i2c_del_mux_adapters(dev->muxc);
 
        kfree(dev);
        return 0;
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h 
b/drivers/media/dvb-frontends/m88ds3103_priv.h
index 52d66c566ac1..c5b4e177c6ea 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -43,7 +43,6 @@ struct m88ds3103_dev {
        u32 dvbv3_ber; /* for old DVBv3 API read_ber */
        bool warm; /* FW running */
        struct i2c_mux_core *muxc;
-       struct i2c_adapter *i2c_adapter;
        /* auto detect chip id to do different config */
        u8 chip_id;
        /* main mclk is calculated for M88RS6000 dynamically */
diff --git a/drivers/media/dvb-frontends/rtl2830.c 
b/drivers/media/dvb-frontends/rtl2830.c
index d6330e8d5fa4..9864740722dd 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -712,7 +712,7 @@ static struct i2c_adapter *rtl2830_get_i2c_adapter(struct 
i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
-       return dev->adapter;
+       return dev->muxc->adapter[0];
 }
 
 /*
@@ -874,11 +874,9 @@ static int rtl2830_probe(struct i2c_client *client,
        dev->muxc->select = rtl2830_select;
 
        /* create muxed i2c adapter for tuner */
-       dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
-       if (dev->adapter == NULL) {
-               ret = -ENODEV;
+       ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+       if (ret)
                goto err_regmap_exit;
-       }
 
        /* create dvb frontend */
        memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops));
@@ -908,7 +906,7 @@ static int rtl2830_remove(struct i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
-       i2c_del_mux_adapter(dev->adapter);
+       i2c_del_mux_adapters(dev->muxc);
        regmap_exit(dev->regmap);
        kfree(dev);
 
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h 
b/drivers/media/dvb-frontends/rtl2830_priv.h
index 2169c8d9c99c..da4909543da2 100644
--- a/drivers/media/dvb-frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -30,7 +30,6 @@ struct rtl2830_dev {
        struct i2c_client *client;
        struct regmap *regmap;
        struct i2c_mux_core *muxc;
-       struct i2c_adapter *adapter;
        struct dvb_frontend fe;
        bool sleeping;
        unsigned long filters;
diff --git a/drivers/media/dvb-frontends/rtl2832.c 
b/drivers/media/dvb-frontends/rtl2832.c
index c8fd990fdae8..99d8dbf66fd7 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1074,7 +1074,7 @@ static struct i2c_adapter *rtl2832_get_i2c_adapter(struct 
i2c_client *client)
        struct rtl2832_dev *dev = i2c_get_clientdata(client);
 
        dev_dbg(&client->dev, "\n");
-       return dev->i2c_adapter_tuner;
+       return dev->muxc->adapter[0];
 }
 
 static int rtl2832_enable_slave_ts(struct i2c_client *client)
@@ -1271,12 +1271,9 @@ static int rtl2832_probe(struct i2c_client *client,
        dev->muxc->deselect = rtl2832_deselect;
 
        /* create muxed i2c adapter for demod tuner bus */
-       dev->i2c_adapter_tuner = i2c_add_mux_adapter(dev->muxc, &i2c->dev,
-                                                    0, 0, 0);
-       if (dev->i2c_adapter_tuner == NULL) {
-               ret = -ENODEV;
+       ret = i2c_add_mux_adapter(dev->muxc, &i2c->dev, 0, 0, 0);
+       if (ret)
                goto err_regmap_exit;
-       }
 
        /* create dvb_frontend */
        memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
@@ -1311,7 +1308,7 @@ static int rtl2832_remove(struct i2c_client *client)
 
        cancel_delayed_work_sync(&dev->i2c_gate_work);
 
-       i2c_del_mux_adapter(dev->i2c_adapter_tuner);
+       i2c_del_mux_adapters(dev->muxc);
 
        regmap_exit(dev->regmap);
 
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h 
b/drivers/media/dvb-frontends/rtl2832_priv.h
index 2d252bd5b8b1..6b3cd23a2c26 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -37,7 +37,6 @@ struct rtl2832_dev {
        struct regmap_config regmap_config;
        struct regmap *regmap;
        struct i2c_mux_core *muxc;
-       struct i2c_adapter *i2c_adapter_tuner;
        struct dvb_frontend fe;
        struct delayed_work stat_work;
        enum fe_status fe_status;
diff --git a/drivers/media/dvb-frontends/si2168.c 
b/drivers/media/dvb-frontends/si2168.c
index 5b1872b1bbf4..06aa496cc42c 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -719,16 +719,14 @@ static int si2168_probe(struct i2c_client *client,
        dev->muxc->deselect = si2168_deselect;
 
        /* create mux i2c adapter for tuner */
-       dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
-       if (dev->adapter == NULL) {
-               ret = -ENODEV;
+       ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+       if (ret)
                goto err_kfree;
-       }
 
        /* create dvb_frontend */
        memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
        dev->fe.demodulator_priv = client;
-       *config->i2c_adapter = dev->adapter;
+       *config->i2c_adapter = dev->muxc->adapter[0];
        *config->fe = &dev->fe;
        dev->ts_mode = config->ts_mode;
        dev->ts_clock_inv = config->ts_clock_inv;
@@ -752,7 +750,7 @@ static int si2168_remove(struct i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
-       i2c_del_mux_adapter(dev->adapter);
+       i2c_del_mux_adapters(dev->muxc);
 
        dev->fe.ops.release = NULL;
        dev->fe.demodulator_priv = NULL;
diff --git a/drivers/media/dvb-frontends/si2168_priv.h 
b/drivers/media/dvb-frontends/si2168_priv.h
index 53efb9d562da..165bf1412063 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -30,7 +30,6 @@
 /* state struct */
 struct si2168_dev {
        struct i2c_mux_core *muxc;
-       struct i2c_adapter *adapter;
        struct dvb_frontend fe;
        enum fe_delivery_system delivery_system;
        enum fe_status fe_status;
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c 
b/drivers/media/usb/cx231xx/cx231xx-core.c
index d805e192e4ca..7d7b04df6a22 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1416,8 +1416,7 @@ EXPORT_SYMBOL_GPL(cx231xx_dev_init);
 void cx231xx_dev_uninit(struct cx231xx *dev)
 {
        /* Un Initialize I2C bus */
-       cx231xx_i2c_mux_unregister(dev, 1);
-       cx231xx_i2c_mux_unregister(dev, 0);
+       cx231xx_i2c_mux_unregister(dev);
        cx231xx_i2c_unregister(&dev->i2c_bus[2]);
        cx231xx_i2c_unregister(&dev->i2c_bus[1]);
        cx231xx_i2c_unregister(&dev->i2c_bus[0]);
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c 
b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 51760bfc7cbc..2b5adb056827 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -579,23 +579,23 @@ int cx231xx_i2c_mux_register(struct cx231xx *dev, int 
mux_no)
 {
        /* what is the correct mux_dev? */
        struct device *mux_dev = dev->dev;
-
-       dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(dev->muxc,
-                               mux_dev,
-                               0,
-                               mux_no /* chan_id */,
-                               0 /* class */);
-       if (!dev->i2c_mux_adap[mux_no])
+       int rc;
+
+       rc = i2c_add_mux_adapter(dev->muxc,
+                                mux_dev,
+                                0,
+                                mux_no /* chan_id */,
+                                0 /* class */);
+       if (rc)
                dev_warn(dev->dev,
                         "i2c mux %d register FAILED\n", mux_no);
 
-       return 0;
+       return rc;
 }
 
-void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no)
+void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
 {
-       i2c_del_mux_adapter(dev->i2c_mux_adap[mux_no]);
-       dev->i2c_mux_adap[mux_no] = NULL;
+       i2c_del_mux_adapters(dev->muxc);
 }
 
 struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
@@ -608,9 +608,9 @@ struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx 
*dev, int i2c_port)
        case I2C_2:
                return &dev->i2c_bus[2].i2c_adap;
        case I2C_1_MUX_1:
-               return dev->i2c_mux_adap[0];
+               return dev->muxc->adapter[0];
        case I2C_1_MUX_3:
-               return dev->i2c_mux_adap[1];
+               return dev->muxc->adapter[1];
        default:
                return NULL;
        }
diff --git a/drivers/media/usb/cx231xx/cx231xx.h 
b/drivers/media/usb/cx231xx/cx231xx.h
index 72f8188e0b01..8c71fa8d777c 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -762,7 +762,7 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus);
 int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
 int cx231xx_i2c_mux_create(struct cx231xx *dev);
 int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no);
-void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no);
+void cx231xx_i2c_mux_unregister(struct cx231xx *dev);
 struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);
 
 /* Internal block control functions */
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index a4abd9b588b9..77ccc54cfdc9 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1677,11 +1677,6 @@ static struct i2c_driver unittest_i2c_dev_driver = {
 
 #if IS_BUILTIN(CONFIG_I2C_MUX)
 
-struct unittest_i2c_mux_data {
-       int nchans;
-       struct i2c_adapter *adap[];
-};
-
 static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
        return 0;
@@ -1690,12 +1685,11 @@ static int unittest_i2c_mux_select_chan(struct 
i2c_mux_core *muxc, u32 chan)
 static int unittest_i2c_mux_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       int ret, i, nchans, size;
+       int ret, i, nchans;
        struct device *dev = &client->dev;
        struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
        struct device_node *np = client->dev.of_node, *child;
        struct i2c_mux_core *muxc;
-       struct unittest_i2c_mux_data *stm;
        u32 reg, max_reg;
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@@ -1719,20 +1713,19 @@ static int unittest_i2c_mux_probe(struct i2c_client 
*client,
                return -EINVAL;
        }
 
-       size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
-       muxc = i2c_mux_alloc(dev, size);
+       muxc = i2c_mux_alloc(dev, 0);
        if (!muxc)
                return -ENOMEM;
        muxc->parent = adap;
        muxc->select = unittest_i2c_mux_select_chan;
-       stm = i2c_mux_priv(muxc);
-       stm->nchans = nchans;
+       ret = i2c_mux_reserve_adapters(muxc, nchans);
+       if (ret)
+               return ret;
        for (i = 0; i < nchans; i++) {
-               stm->adap[i] = i2c_add_mux_adapter(muxc, dev, 0, i, 0);
-               if (!stm->adap[i]) {
+               ret = i2c_add_mux_adapter(muxc, dev, 0, i, 0);
+               if (ret) {
                        dev_err(dev, "Failed to register mux #%d\n", i);
-                       for (i--; i >= 0; i--)
-                               i2c_del_mux_adapter(stm->adap[i]);
+                       i2c_del_mux_adapters(muxc);
                        return -ENODEV;
                }
        }
@@ -1747,12 +1740,9 @@ static int unittest_i2c_mux_remove(struct i2c_client 
*client)
        struct device *dev = &client->dev;
        struct device_node *np = client->dev.of_node;
        struct i2c_mux_core *muxc = i2c_get_clientdata(client);
-       struct unittest_i2c_mux_data *stm = i2c_mux_priv(muxc);
-       int i;
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
-       for (i = stm->nchans - 1; i >= 0; i--)
-               i2c_del_mux_adapter(stm->adap[i]);
+       i2c_del_mux_adapters(muxc);
        return 0;
 }
 
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 5cd6e1e664e0..bfcdcc46f2a6 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -29,6 +29,9 @@
 
 struct i2c_mux_core {
        struct i2c_adapter *parent;
+       struct i2c_adapter **adapter;
+       int adapters;
+       int max_adapters;
        struct device *dev;
 
        void *priv;
@@ -44,18 +47,20 @@ static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
        return muxc->priv;
 }
 
+int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters);
+
 /*
  * Called to create a i2c bus on a multiplexed bus segment.
  * The mux_dev and chan_id parameters are passed to the select
  * and deselect callback functions to perform hardware-specific
  * mux control.
  */
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-                                       struct device *mux_dev,
-                                       u32 force_nr, u32 chan_id,
-                                       unsigned int class);
+int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
+                       struct device *mux_dev,
+                       u32 force_nr, u32 chan_id,
+                       unsigned int class);
 
-void i2c_del_mux_adapter(struct i2c_adapter *adap);
+void i2c_del_mux_adapters(struct i2c_mux_core *muxc);
 
 #endif /* __KERNEL__ */
 
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to