Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core

Peter Rosin
2016-01-05T22:17:27Z

Ouch, this got lost in the shuffle, don't bother testing without it.
It will be included in v3.

[the reason is that my test hw relies on vendor patches, and I have to
rebase before sending. I.e., I can only compile-test the stuff I'm
actually sending out. Inconvenient.]

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index c4d4b14a5399..c5a5886d8be1 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -215,10 +215,12 @@ int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
if (!adapter)
return -ENOMEM;

- memcpy(adapter, muxc->adapter,
- muxc->max_adapters * sizeof(*adapter));
+ if (muxc->adapter) {
+ memcpy(adapter, muxc->adapter,
+ muxc->max_adapters * sizeof(*adapter));
+ devm_kfree(muxc->dev, muxc->adapter);
+ }

- devm_kfree(muxc->dev, muxc->adapter);
muxc->adapter = adapter;
muxc->max_adapters = adapters;
return 0;
--

On 2016-01-05 16:57, Peter Rosin wrote:
> From: Peter Rosin <peda@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 <peda@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 <giometti@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__ */
>
>