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

Peter Rosin
2016-01-05T15:57:59Z

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__ */

--
2.1.4