From: Peter Rosin <peda@xxxxxxxxxx> 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_adapters 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@xxxxxxxxxx> --- drivers/i2c/i2c-mux.c | 73 ++++++++++++++++++++++------ 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_acpi.c | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 13 ++--- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 2 +- 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 ++++-- 23 files changed, 153 insertions(+), 184 deletions(-) diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 6c5cb9f7649b..3c56625ce13c 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -99,6 +99,31 @@ 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; + + if (muxc->adapter) { + 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 +138,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 +232,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 +244,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@xxxxxxxx>"); 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_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index 1c982a56acd5..d433e7b64011 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -182,7 +182,7 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) } else return 0; /* no secondary addr, which is OK */ } - st->mux_client = i2c_new_device(st->mux_adapter, &info); + st->mux_client = i2c_new_device(st->muxc->adapter[0], &info); if (!st->mux_client) return -ENODEV; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 0a47396bc5be..af9f54a2111d 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -23,7 +23,6 @@ #include <linux/kfifo.h> #include <linux/spinlock.h> #include <linux/iio/iio.h> -#include <linux/i2c-mux.h> #include <linux/acpi.h> #include "inv_mpu_iio.h" @@ -850,13 +849,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 +860,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 +876,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..61a3a04b84b8 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ #include <linux/i2c.h> +#include <linux/i2c-mux.h> #include <linux/kfifo.h> #include <linux/spinlock.h> #include <linux/iio/iio.h> @@ -121,7 +122,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-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html