All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-05 15:57 ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

Hi!

I have a pair of boards with this i2c topology:

                       GPIO ---|  ------ BAT1
                        |      v /
   I2C  -----+------B---+---- MUX
             |                   \
           EEPROM                 ------ BAT2

	(B denotes the boundary between the boards)

The problem with this is that the GPIO controller sits on the same i2c bus
that it MUXes. For pca954x devices this is worked around by using unlocked
transfers when updating the MUX. I have no such luck as the GPIO is a general
purpose IO expander and the MUX is just a random bidirectional MUX, unaware
of the fact that it is muxing an i2c bus, and extending unlocked transfers
into the GPIO subsystem is too ugly to even think about. But the general hw
approach is sane in my opinion, with the number of connections between the
two boards minimized. To put is plainly, I need support for it.

So, I observe that while it is needed to have the i2c bus locked during the
actual MUX update in order to avoid random garbage on the slave side, it
is not strictly a must to have it locked over the whole sequence of a full
select-transfer-deselect operation. The MUX itself needs to be locked, so
transfers to clients behind the mux are serialized, and the MUX needs to be
stable during all i2c traffic (otherwise individual mux slave segments
might see garbage).

This series accomplishes this by adding a dt property to i2c-mux-gpio and
i2c-mux-pinctrl that can be used to state that the mux is updated by means
of the muxed master bus, and that the select-transfer-deselect operations
should be locked individually. When this holds, the i2c bus *is* locked
during muxing, since the muxing happens as part of i2c transfers. This
is true even if the MUX is updated with several transfers to the GPIO (at
least as long as *all* MUX changes are using the i2s master bus). A lock
is added to the mux so that transfers through the mux are serialized.

Concerns:
- The locking is perhaps too complex?
- I worry about the priority inheritance aspect of the adapter lock. When
  the transfers behind the mux are divided into select-transfer-deselect all
  locked individually, low priority transfers get more chances to interfere
  with high priority transfers.
- When doing an i2c_transfer() in_atomic() context of with irqs_disabled(),
  there is a higher possibility that the mux is not returned to its idle
  state after a failed (-EAGAIN) transfer due to trylock.

To summarize the series, there's some i2c-mux infrastructure cleanup work
first (I think that part stands by itself as desireable regardless), the
locking changes are in the last three patches of the series, with the real
meat in 8/8.

PS. needs a bunch of testing, I do not have access to all the involved hw

Changes since v1:
- Allocate mux core and (optional) priv in a combined allocation.
- Killed dev_err messages triggered by memory allocation failure.
- Fix the device specific i2c muxes that I had overlooked.
- Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously).

Cheers,
Peter

Peter Rosin (8):
  i2c-mux: add common core data for every mux instance
  i2c-mux: move select and deselect ops to i2c_mux_core
  i2c-mux: move the slave side adapter management to i2c_mux_core
  i2c-mux: remove the mux dev pointer from the mux per channel data
  i2c-mux: pinctrl: get rid of the driver private struct device pointer
  i2c: allow adapter drivers to override the adapter locking
  i2c: muxes always lock the parent adapter
  i2c-mux: relax locking of the top i2c adapter during i2c controlled
    muxing

 .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
 .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
 drivers/i2c/i2c-core.c                             |  59 ++---
 drivers/i2c/i2c-mux.c                              | 272 +++++++++++++++++----
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
 drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
 drivers/i2c/muxes/i2c-mux-pca9541.c                |  58 +++--
 drivers/i2c/muxes/i2c-mux-pca954x.c                |  66 ++---
 drivers/i2c/muxes/i2c-mux-pinctrl.c                |  89 +++----
 drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c         |  33 +--
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |   2 +-
 drivers/media/dvb-frontends/m88ds3103.c            |  23 +-
 drivers/media/dvb-frontends/m88ds3103_priv.h       |   2 +-
 drivers/media/dvb-frontends/rtl2830.c              |  24 +-
 drivers/media/dvb-frontends/rtl2830_priv.h         |   2 +-
 drivers/media/dvb-frontends/rtl2832.c              |  30 ++-
 drivers/media/dvb-frontends/rtl2832_priv.h         |   2 +-
 drivers/media/dvb-frontends/si2168.c               |  29 ++-
 drivers/media/dvb-frontends/si2168_priv.h          |   2 +-
 drivers/media/usb/cx231xx/cx231xx-core.c           |   6 +-
 drivers/media/usb/cx231xx/cx231xx-i2c.c            |  48 ++--
 drivers/media/usb/cx231xx/cx231xx.h                |   4 +-
 drivers/of/unittest.c                              |  41 ++--
 include/linux/i2c-mux-gpio.h                       |   2 +
 include/linux/i2c-mux-pinctrl.h                    |   2 +
 include/linux/i2c-mux.h                            |  39 ++-
 include/linux/i2c.h                                |  28 ++-
 28 files changed, 612 insertions(+), 424 deletions(-)

-- 
2.1.4


^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-05 15:57 ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

Hi!

I have a pair of boards with this i2c topology:

                       GPIO ---|  ------ BAT1
                        |      v /
   I2C  -----+------B---+---- MUX
             |                   \
           EEPROM                 ------ BAT2

	(B denotes the boundary between the boards)

The problem with this is that the GPIO controller sits on the same i2c bus
that it MUXes. For pca954x devices this is worked around by using unlocked
transfers when updating the MUX. I have no such luck as the GPIO is a general
purpose IO expander and the MUX is just a random bidirectional MUX, unaware
of the fact that it is muxing an i2c bus, and extending unlocked transfers
into the GPIO subsystem is too ugly to even think about. But the general hw
approach is sane in my opinion, with the number of connections between the
two boards minimized. To put is plainly, I need support for it.

So, I observe that while it is needed to have the i2c bus locked during the
actual MUX update in order to avoid random garbage on the slave side, it
is not strictly a must to have it locked over the whole sequence of a full
select-transfer-deselect operation. The MUX itself needs to be locked, so
transfers to clients behind the mux are serialized, and the MUX needs to be
stable during all i2c traffic (otherwise individual mux slave segments
might see garbage).

This series accomplishes this by adding a dt property to i2c-mux-gpio and
i2c-mux-pinctrl that can be used to state that the mux is updated by means
of the muxed master bus, and that the select-transfer-deselect operations
should be locked individually. When this holds, the i2c bus *is* locked
during muxing, since the muxing happens as part of i2c transfers. This
is true even if the MUX is updated with several transfers to the GPIO (at
least as long as *all* MUX changes are using the i2s master bus). A lock
is added to the mux so that transfers through the mux are serialized.

Concerns:
- The locking is perhaps too complex?
- I worry about the priority inheritance aspect of the adapter lock. When
  the transfers behind the mux are divided into select-transfer-deselect all
  locked individually, low priority transfers get more chances to interfere
  with high priority transfers.
- When doing an i2c_transfer() in_atomic() context of with irqs_disabled(),
  there is a higher possibility that the mux is not returned to its idle
  state after a failed (-EAGAIN) transfer due to trylock.

To summarize the series, there's some i2c-mux infrastructure cleanup work
first (I think that part stands by itself as desireable regardless), the
locking changes are in the last three patches of the series, with the real
meat in 8/8.

PS. needs a bunch of testing, I do not have access to all the involved hw

Changes since v1:
- Allocate mux core and (optional) priv in a combined allocation.
- Killed dev_err messages triggered by memory allocation failure.
- Fix the device specific i2c muxes that I had overlooked.
- Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously).

Cheers,
Peter

Peter Rosin (8):
  i2c-mux: add common core data for every mux instance
  i2c-mux: move select and deselect ops to i2c_mux_core
  i2c-mux: move the slave side adapter management to i2c_mux_core
  i2c-mux: remove the mux dev pointer from the mux per channel data
  i2c-mux: pinctrl: get rid of the driver private struct device pointer
  i2c: allow adapter drivers to override the adapter locking
  i2c: muxes always lock the parent adapter
  i2c-mux: relax locking of the top i2c adapter during i2c controlled
    muxing

 .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
 .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
 drivers/i2c/i2c-core.c                             |  59 ++---
 drivers/i2c/i2c-mux.c                              | 272 +++++++++++++++++----
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
 drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
 drivers/i2c/muxes/i2c-mux-pca9541.c                |  58 +++--
 drivers/i2c/muxes/i2c-mux-pca954x.c                |  66 ++---
 drivers/i2c/muxes/i2c-mux-pinctrl.c                |  89 +++----
 drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c         |  33 +--
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |   2 +-
 drivers/media/dvb-frontends/m88ds3103.c            |  23 +-
 drivers/media/dvb-frontends/m88ds3103_priv.h       |   2 +-
 drivers/media/dvb-frontends/rtl2830.c              |  24 +-
 drivers/media/dvb-frontends/rtl2830_priv.h         |   2 +-
 drivers/media/dvb-frontends/rtl2832.c              |  30 ++-
 drivers/media/dvb-frontends/rtl2832_priv.h         |   2 +-
 drivers/media/dvb-frontends/si2168.c               |  29 ++-
 drivers/media/dvb-frontends/si2168_priv.h          |   2 +-
 drivers/media/usb/cx231xx/cx231xx-core.c           |   6 +-
 drivers/media/usb/cx231xx/cx231xx-i2c.c            |  48 ++--
 drivers/media/usb/cx231xx/cx231xx.h                |   4 +-
 drivers/of/unittest.c                              |  41 ++--
 include/linux/i2c-mux-gpio.h                       |   2 +
 include/linux/i2c-mux-pinctrl.h                    |   2 +
 include/linux/i2c-mux.h                            |  39 ++-
 include/linux/i2c.h                                |  28 ++-
 28 files changed, 612 insertions(+), 424 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

The initial core mux structure starts off small with only the parent
adapter pointer, which all muxes have, and a priv pointer for mux
driver private data.

Add i2c_mux_alloc function to unify the creation of a mux.

Where appropriate, pass around the mux core structure instead of the
parent adapter or the driver private data.

Remove the parent adapter pointer from the driver private data for all
mux drivers.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-mux.c                        | 28 +++++++++++++++++-----
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 24 +++++++++----------
 drivers/i2c/muxes/i2c-mux-gpio.c             | 20 ++++++++--------
 drivers/i2c/muxes/i2c-mux-pca9541.c          | 35 ++++++++++++++--------------
 drivers/i2c/muxes/i2c-mux-pca954x.c          | 19 ++++++++++-----
 drivers/i2c/muxes/i2c-mux-pinctrl.c          | 23 +++++++++---------
 drivers/i2c/muxes/i2c-mux-reg.c              | 23 ++++++++++--------
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 10 +++++++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 +
 drivers/media/dvb-frontends/m88ds3103.c      | 10 +++++++-
 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        | 10 +++++++-
 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      | 13 +++++++++--
 drivers/media/usb/cx231xx/cx231xx.h          |  2 ++
 drivers/of/unittest.c                        | 16 +++++++------
 include/linux/i2c-mux.h                      | 14 ++++++++++-
 22 files changed, 187 insertions(+), 88 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 00fc5b1c7b66..c2163f6b51d5 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -31,8 +31,8 @@
 struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
+	struct i2c_mux_core *muxc;
 
-	struct i2c_adapter *parent;
 	struct device *mux_dev;
 	void *mux_priv;
 	u32 chan_id;
@@ -45,7 +45,8 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 			       struct i2c_msg msgs[], int num)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
@@ -65,7 +66,8 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 			      int size, union i2c_smbus_data *data)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
@@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 static u32 i2c_mux_functionality(struct i2c_adapter *adap)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_adapter *parent = priv->muxc->parent;
 
 	return parent->algo->functionality(parent);
 }
@@ -102,7 +104,20 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
+{
+	struct i2c_mux_core *muxc;
+
+	muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
+	if (!muxc)
+		return NULL;
+	if (sizeof_priv)
+		muxc->priv = muxc + 1;
+	return muxc;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_alloc);
+
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 				struct device *mux_dev,
 				void *mux_priv, u32 force_nr, u32 chan_id,
 				unsigned int class,
@@ -111,6 +126,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 				int (*deselect) (struct i2c_adapter *,
 						 void *, u32))
 {
+	struct i2c_adapter *parent = muxc->parent;
 	struct i2c_mux_priv *priv;
 	char symlink_name[20];
 	int ret;
@@ -120,7 +136,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 		return NULL;
 
 	/* Set up private adapter data */
-	priv->parent = parent;
+	priv->muxc = muxc;
 	priv->mux_dev = mux_dev;
 	priv->mux_priv = mux_priv;
 	priv->chan_id = chan_id;
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 402e3a6c671a..6e27ea4fb25a 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 *parent;
 	struct i2c_adapter *child;
 	int our_gpio;
 	int our_gpio_release;
@@ -119,6 +118,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct device_node *parent_np;
+	struct i2c_mux_core *muxc;
 	struct i2c_arbitrator_data *arb;
 	enum of_gpio_flags gpio_flags;
 	unsigned long out_init;
@@ -134,13 +134,12 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
-	if (!arb) {
-		dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
+	muxc = i2c_mux_alloc(dev, sizeof(*arb));
+	if (!muxc)
 		return -ENOMEM;
-	}
-	platform_set_drvdata(pdev, arb);
+	arb = i2c_mux_priv(muxc);
 
+	platform_set_drvdata(pdev, muxc);
 	/* Request GPIOs */
 	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
 	if (!gpio_is_valid(ret)) {
@@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 		dev_err(dev, "Cannot parse i2c-parent\n");
 		return -EINVAL;
 	}
-	arb->parent = of_get_i2c_adapter_by_node(parent_np);
+	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
 	of_node_put(parent_np);
-	if (!arb->parent) {
+	if (!muxc->parent) {
 		dev_err(dev, "Cannot find parent bus\n");
 		return -EPROBE_DEFER;
 	}
 
 	/* Actually add the mux adapter */
-	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
+	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
 					 i2c_arbitrator_select,
 					 i2c_arbitrator_deselect);
 	if (!arb->child) {
 		dev_err(dev, "Failed to add adapter\n");
 		ret = -ENODEV;
-		i2c_put_adapter(arb->parent);
+		i2c_put_adapter(muxc->parent);
 	}
 
 	return ret;
@@ -218,10 +217,11 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 
 static int i2c_arbitrator_remove(struct platform_device *pdev)
 {
-	struct i2c_arbitrator_data *arb = platform_get_drvdata(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_put_adapter(arb->parent);
+	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 b8e11c16d98c..ee43dd76a4d7 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 *parent;
 	struct i2c_adapter **adap; /* child busses */
 	struct i2c_mux_gpio_platform_data data;
 	unsigned gpio_base;
@@ -136,19 +135,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 
 static int i2c_mux_gpio_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct gpiomux *mux;
 	struct i2c_adapter *parent;
 	int (*deselect) (struct i2c_adapter *, void *, u32);
 	unsigned initial_state, gpio_base;
 	int i, ret;
 
-	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux) {
-		dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
+	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
+	if (!muxc)
 		return -ENOMEM;
-	}
+	mux = i2c_mux_priv(muxc);
 
-	platform_set_drvdata(pdev, mux);
+	platform_set_drvdata(pdev, muxc);
 
 	if (!dev_get_platdata(&pdev->dev)) {
 		ret = i2c_mux_gpio_probe_dt(mux, pdev);
@@ -180,7 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	if (!parent)
 		return -EPROBE_DEFER;
 
-	mux->parent = parent;
+	muxc->parent = parent;
 	mux->gpio_base = gpio_base;
 
 	mux->adap = devm_kzalloc(&pdev->dev,
@@ -223,7 +222,7 @@ 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(parent, &pdev->dev, mux, nr,
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux, nr,
 						   mux->data.values[i], class,
 						   i2c_mux_gpio_select, deselect);
 		if (!mux->adap[i]) {
@@ -253,7 +252,8 @@ alloc_failed:
 
 static int i2c_mux_gpio_remove(struct platform_device *pdev)
 {
-	struct gpiomux *mux = platform_get_drvdata(pdev);
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 	int i;
 
 	for (i = 0; i < mux->data.n_values; i++)
@@ -262,7 +262,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
 	for (i = 0; i < mux->data.n_gpios; i++)
 		gpio_free(mux->gpio_base + mux->data.gpios[i]);
 
-	i2c_put_adapter(mux->parent);
+	i2c_put_adapter(muxc->parent);
 
 	return 0;
 }
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index d0ba424adebc..47ae2259d1ca 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -73,6 +73,7 @@
 #define SELECT_DELAY_LONG	1000
 
 struct pca9541 {
+	struct i2c_client *client;
 	struct i2c_adapter *mux_adap;
 	unsigned long select_timeout;
 	unsigned long arb_timeout;
@@ -217,7 +218,8 @@ static const u8 pca9541_control[16] = {
  */
 static int pca9541_arbitrate(struct i2c_client *client)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
 	int reg;
 
 	reg = pca9541_reg_read(client, PCA9541_CONTROL);
@@ -324,20 +326,22 @@ static int pca9541_probe(struct i2c_client *client,
 {
 	struct i2c_adapter *adap = client->adapter;
 	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct i2c_mux_core *muxc;
 	struct pca9541 *data;
 	int force;
-	int ret = -ENODEV;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
-		goto err;
+		return -ENODEV;
 
-	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	muxc = i2c_mux_alloc(&client->dev, sizeof(*data));
+	if (!muxc)
+		return -ENOMEM;
+	data = i2c_mux_priv(muxc);
+
+	i2c_set_clientdata(client, muxc);
 
-	i2c_set_clientdata(client, data);
+	data->client = client;
+	muxc->parent = adap;
 
 	/*
 	 * I2C accesses are unprotected here.
@@ -352,34 +356,29 @@ 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(adap, &client->dev, client,
+	data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, client,
 					     force, 0, 0,
 					     pca9541_select_chan,
 					     pca9541_release_chan);
 
 	if (data->mux_adap == NULL) {
 		dev_err(&client->dev, "failed to register master selector\n");
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	dev_info(&client->dev, "registered master selector for I2C %s\n",
 		 client->name);
 
 	return 0;
-
-exit_free:
-	kfree(data);
-err:
-	return ret;
 }
 
 static int pca9541_remove(struct i2c_client *client)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
 
 	i2c_del_mux_adapter(data->mux_adap);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index acfcef3d4068..a4df831fae9d 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -63,6 +63,7 @@ struct pca954x {
 	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
 	u8 last_chan;		/* last register value */
+	struct i2c_client *client;
 };
 
 struct chip_desc {
@@ -191,17 +192,20 @@ static int pca954x_probe(struct i2c_client *client,
 	bool idle_disconnect_dt;
 	struct gpio_desc *gpio;
 	int num, force, class;
+	struct i2c_mux_core *muxc;
 	struct pca954x *data;
 	int ret;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
 		return -ENODEV;
 
-	data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
-	if (!data)
+	muxc = i2c_mux_alloc(&client->dev, sizeof(*data));
+	if (!muxc)
 		return -ENOMEM;
+	data = i2c_mux_priv(muxc);
 
-	i2c_set_clientdata(client, data);
+	i2c_set_clientdata(client, muxc);
+	data->client = client;
 
 	/* Get the mux out of reset if a reset GPIO is specified. */
 	gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
@@ -217,6 +221,7 @@ static int pca954x_probe(struct i2c_client *client,
 		return -ENODEV;
 	}
 
+	muxc->parent = adap;
 	data->type = id->driver_data;
 	data->last_chan = 0;		   /* force the first selection */
 
@@ -241,7 +246,7 @@ static int pca954x_probe(struct i2c_client *client,
 		}
 
 		data->virt_adaps[num] =
-			i2c_add_mux_adapter(adap, &client->dev, client,
+			i2c_add_mux_adapter(muxc, &client->dev, client,
 				force, num, class, pca954x_select_chan,
 				(idle_disconnect_pd || idle_disconnect_dt)
 					? pca954x_deselect_mux : NULL);
@@ -270,7 +275,8 @@ virt_reg_failed:
 
 static int pca954x_remove(struct i2c_client *client)
 {
-	struct pca954x *data = i2c_get_clientdata(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;
 
@@ -287,7 +293,8 @@ static int pca954x_remove(struct i2c_client *client)
 static int pca954x_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
 
 	data->last_chan = 0;
 	return i2c_smbus_write_byte(client, 0);
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index b5a982ba8898..810f75f114a7 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 *parent;
 	struct i2c_adapter **busses;
 };
 
@@ -131,17 +130,18 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 
 static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct i2c_mux_pinctrl *mux;
 	int (*deselect)(struct i2c_adapter *, void *, u32);
 	int i, ret;
 
-	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux) {
-		dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
+	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
+	if (!muxc) {
 		ret = -ENOMEM;
 		goto err;
 	}
-	platform_set_drvdata(pdev, mux);
+	mux = i2c_mux_priv(muxc);
+	platform_set_drvdata(pdev, muxc);
 
 	mux->dev = &pdev->dev;
 
@@ -208,8 +208,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 		deselect = NULL;
 	}
 
-	mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
-	if (!mux->parent) {
+	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
+	if (!muxc->parent) {
 		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
 			mux->pdata->parent_bus_num);
 		ret = -EPROBE_DEFER;
@@ -220,7 +220,7 @@ 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(mux->parent, &pdev->dev,
+		mux->busses[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
 						     mux, bus, i, 0,
 						     i2c_mux_pinctrl_select,
 						     deselect);
@@ -236,20 +236,21 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 err_del_adapter:
 	for (; i > 0; i--)
 		i2c_del_mux_adapter(mux->busses[i - 1]);
-	i2c_put_adapter(mux->parent);
+	i2c_put_adapter(muxc->parent);
 err:
 	return ret;
 }
 
 static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
 {
-	struct i2c_mux_pinctrl *mux = platform_get_drvdata(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_put_adapter(mux->parent);
+	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 5fbd5bd0878f..8bde4cfac512 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 *parent;
 	struct i2c_adapter **adap; /* child busses */
 	struct i2c_mux_reg_platform_data data;
 };
@@ -87,6 +86,7 @@ static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
 static int i2c_mux_reg_probe_dt(struct regmux *mux,
 					struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *adapter_np, *child;
 	struct i2c_adapter *adapter;
@@ -107,7 +107,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 	if (!adapter)
 		return -EPROBE_DEFER;
 
-	mux->parent = adapter;
+	muxc->parent = adapter;
 	mux->data.parent = i2c_adapter_id(adapter);
 	put_device(&adapter->dev);
 
@@ -169,6 +169,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 
 static int i2c_mux_reg_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct regmux *mux;
 	struct i2c_adapter *parent;
 	struct resource *res;
@@ -176,11 +177,12 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	unsigned int class;
 	int i, ret, nr;
 
-	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux)
+	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
+	if (!muxc)
 		return -ENOMEM;
+	mux = i2c_mux_priv(muxc);
 
-	platform_set_drvdata(pdev, mux);
+	platform_set_drvdata(pdev, muxc);
 
 	if (dev_get_platdata(&pdev->dev)) {
 		memcpy(&mux->data, dev_get_platdata(&pdev->dev),
@@ -190,7 +192,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 		if (!parent)
 			return -EPROBE_DEFER;
 
-		mux->parent = parent;
+		muxc->parent = parent;
 	} else {
 		ret = i2c_mux_reg_probe_dt(mux, pdev);
 		if (ret < 0) {
@@ -232,7 +234,7 @@ 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(mux->parent, &pdev->dev, mux,
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux,
 						   nr, mux->data.values[i],
 						   class, i2c_mux_reg_select,
 						   deselect);
@@ -244,7 +246,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	}
 
 	dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
-		 mux->data.n_values, mux->parent->name);
+		 mux->data.n_values, muxc->parent->name);
 
 	return 0;
 
@@ -257,13 +259,14 @@ add_adapter_failed:
 
 static int i2c_mux_reg_remove(struct platform_device *pdev)
 {
-	struct regmux *mux = platform_get_drvdata(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_put_adapter(mux->parent);
+	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 f0e06093b5e8..3aab0d7a1bdc 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -842,7 +842,15 @@ static int inv_mpu_probe(struct i2c_client *client,
 		goto out_remove_trigger;
 	}
 
-	st->mux_adapter = i2c_add_mux_adapter(client->adapter,
+	st->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!st->muxc) {
+		result = -ENOMEM;
+		goto out_unreg_device;
+	}
+	st->muxc->priv = indio_dev;
+	st->muxc->parent = client->adapter;
+
+	st->mux_adapter = i2c_add_mux_adapter(st->muxc,
 					      &client->dev,
 					      indio_dev,
 					      0, 0, 0,
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index db0a4a2758ab..d4929db4b40e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -120,6 +120,7 @@ struct inv_mpu6050_state {
 	enum   inv_devices chip_type;
 	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;
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index feeeb70d841e..a0006aec6937 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1466,8 +1466,16 @@ static int m88ds3103_probe(struct i2c_client *client,
 	if (ret)
 		goto err_kfree;
 
+	dev->muxc  = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+	dev->muxc->priv = dev;
+	dev->muxc->parent = client->adapter;
+
 	/* create mux i2c adapter for tuner */
-	dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+	dev->i2c_adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
 					       dev, 0, 0, 0, m88ds3103_select,
 					       NULL);
 	if (dev->i2c_adapter == NULL) {
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index eee8c22c51ec..52d66c566ac1 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -42,6 +42,7 @@ struct m88ds3103_dev {
 	enum fe_status fe_status;
 	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;
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index b792f305cf15..ebf28b49cab2 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -864,8 +864,16 @@ static int rtl2830_probe(struct i2c_client *client,
 	if (ret)
 		goto err_regmap_exit;
 
+	dev->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_regmap_exit;
+	}
+	dev->muxc->priv = client;
+	dev->muxc->parent = client->adapter;
+
 	/* create muxed i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
 			client, 0, 0, 0, rtl2830_select, NULL);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
index cf793f39a09b..2169c8d9c99c 100644
--- a/drivers/media/dvb-frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -29,6 +29,7 @@ struct rtl2830_dev {
 	struct rtl2830_platform_data *pdata;
 	struct i2c_client *client;
 	struct regmap *regmap;
+	struct i2c_mux_core *muxc;
 	struct i2c_adapter *adapter;
 	struct dvb_frontend fe;
 	bool sleeping;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 78b87b260d74..38402ad3ecdd 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1261,8 +1261,16 @@ static int rtl2832_probe(struct i2c_client *client,
 	if (ret)
 		goto err_regmap_exit;
 
+	dev->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_regmap_exit;
+	}
+	dev->muxc->priv = dev;
+	dev->muxc->parent = i2c;
+
 	/* create muxed i2c adapter for demod tuner bus */
-	dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
+	dev->i2c_adapter_tuner = i2c_add_mux_adapter(dev->muxc, &i2c->dev, dev,
 			0, 0, 0, rtl2832_select, rtl2832_deselect);
 	if (dev->i2c_adapter_tuner == NULL) {
 		ret = -ENODEV;
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 5dcd3a41d23f..2d252bd5b8b1 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -36,6 +36,7 @@ struct rtl2832_dev {
 	struct mutex regmap_mutex;
 	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;
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 821a8f481507..a52756bf9834 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -708,8 +708,16 @@ static int si2168_probe(struct i2c_client *client,
 		goto err;
 	}
 
+	dev->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+	dev->muxc->priv = client;
+	dev->muxc->parent = client->adapter;
+
 	/* create mux i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
 			client, 0, 0, 0, si2168_select, si2168_deselect);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index c07e6fe2cb10..53efb9d562da 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -29,6 +29,7 @@
 
 /* state struct */
 struct si2168_dev {
+	struct i2c_mux_core *muxc;
 	struct i2c_adapter *adapter;
 	struct dvb_frontend fe;
 	enum fe_delivery_system delivery_system;
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index a2fd49b6be83..d805e192e4ca 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1291,6 +1291,9 @@ int cx231xx_dev_init(struct cx231xx *dev)
 	cx231xx_i2c_register(&dev->i2c_bus[1]);
 	cx231xx_i2c_register(&dev->i2c_bus[2]);
 
+	errCode = cx231xx_i2c_mux_create(dev);
+	if (errCode < 0)
+		return errCode;
 	cx231xx_i2c_mux_register(dev, 0);
 	cx231xx_i2c_mux_register(dev, 1);
 
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index a29c345b027d..09c30e753ca5 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -565,13 +565,22 @@ static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
 	return cx231xx_enable_i2c_port_3(dev, chan_id);
 }
 
+int cx231xx_i2c_mux_create(struct cx231xx *dev)
+{
+	dev->muxc = i2c_mux_alloc(dev->dev, 0);
+	if (!dev->muxc)
+		return -ENOMEM;
+	dev->muxc->priv = dev;
+	dev->muxc->parent = &dev->i2c_bus[1].i2c_adap;
+	return 0;
+}
+
 int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
 {
-	struct i2c_adapter *i2c_parent = &dev->i2c_bus[1].i2c_adap;
 	/* what is the correct mux_dev? */
 	struct device *mux_dev = dev->dev;
 
-	dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
+	dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(dev->muxc,
 				mux_dev,
 				dev /* mux_priv */,
 				0,
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 54790fbe8fdc..72f8188e0b01 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -625,6 +625,7 @@ struct cx231xx {
 
 	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
 	struct cx231xx_i2c i2c_bus[3];
+	struct i2c_mux_core *muxc;
 	struct i2c_adapter *i2c_mux_adap[2];
 
 	unsigned int xc_fw_load_done:1;
@@ -759,6 +760,7 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev);
 void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port);
 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);
 struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e16ea5717b7f..6bfc2f9a5a24 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1695,6 +1695,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	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;
 
@@ -1720,14 +1721,14 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	}
 
 	size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
-	stm = devm_kzalloc(dev, size, GFP_KERNEL);
-	if (!stm) {
-		dev_err(dev, "Out of memory\n");
+	muxc = i2c_mux_alloc(dev, size);
+	if (!muxc)
 		return -ENOMEM;
-	}
+	muxc->parent = adap;
+	stm = i2c_mux_priv(muxc);
 	stm->nchans = nchans;
 	for (i = 0; i < nchans; i++) {
-		stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
+		stm->adap[i] = i2c_add_mux_adapter(muxc, dev, client,
 				0, i, 0, unittest_i2c_mux_select_chan, NULL);
 		if (!stm->adap[i]) {
 			dev_err(dev, "Failed to register mux #%d\n", i);
@@ -1737,7 +1738,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 		}
 	}
 
-	i2c_set_clientdata(client, stm);
+	i2c_set_clientdata(client, muxc);
 
 	return 0;
 };
@@ -1746,7 +1747,8 @@ static int unittest_i2c_mux_remove(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
 	struct device_node *np = client->dev.of_node;
-	struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
+	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);
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index b5f9a007a3ab..3ca1783b86ac 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -27,13 +27,25 @@
 
 #ifdef __KERNEL__
 
+struct i2c_mux_core {
+	struct i2c_adapter *parent;
+	void *priv;
+};
+
+struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv);
+
+static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
+{
+	return muxc->priv;
+}
+
 /*
  * 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_adapter *parent,
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 				struct device *mux_dev,
 				void *mux_priv, u32 force_nr, u32 chan_id,
 				unsigned int class,
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

The initial core mux structure starts off small with only the parent
adapter pointer, which all muxes have, and a priv pointer for mux
driver private data.

Add i2c_mux_alloc function to unify the creation of a mux.

Where appropriate, pass around the mux core structure instead of the
parent adapter or the driver private data.

Remove the parent adapter pointer from the driver private data for all
mux drivers.

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 drivers/i2c/i2c-mux.c                        | 28 +++++++++++++++++-----
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 24 +++++++++----------
 drivers/i2c/muxes/i2c-mux-gpio.c             | 20 ++++++++--------
 drivers/i2c/muxes/i2c-mux-pca9541.c          | 35 ++++++++++++++--------------
 drivers/i2c/muxes/i2c-mux-pca954x.c          | 19 ++++++++++-----
 drivers/i2c/muxes/i2c-mux-pinctrl.c          | 23 +++++++++---------
 drivers/i2c/muxes/i2c-mux-reg.c              | 23 ++++++++++--------
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 10 +++++++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 +
 drivers/media/dvb-frontends/m88ds3103.c      | 10 +++++++-
 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        | 10 +++++++-
 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      | 13 +++++++++--
 drivers/media/usb/cx231xx/cx231xx.h          |  2 ++
 drivers/of/unittest.c                        | 16 +++++++------
 include/linux/i2c-mux.h                      | 14 ++++++++++-
 22 files changed, 187 insertions(+), 88 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 00fc5b1c7b66..c2163f6b51d5 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -31,8 +31,8 @@
 struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
+	struct i2c_mux_core *muxc;
 
-	struct i2c_adapter *parent;
 	struct device *mux_dev;
 	void *mux_priv;
 	u32 chan_id;
@@ -45,7 +45,8 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 			       struct i2c_msg msgs[], int num)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
@@ -65,7 +66,8 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 			      int size, union i2c_smbus_data *data)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
@@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 static u32 i2c_mux_functionality(struct i2c_adapter *adap)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_adapter *parent = priv->muxc->parent;
 
 	return parent->algo->functionality(parent);
 }
@@ -102,7 +104,20 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
+{
+	struct i2c_mux_core *muxc;
+
+	muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
+	if (!muxc)
+		return NULL;
+	if (sizeof_priv)
+		muxc->priv = muxc + 1;
+	return muxc;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_alloc);
+
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 				struct device *mux_dev,
 				void *mux_priv, u32 force_nr, u32 chan_id,
 				unsigned int class,
@@ -111,6 +126,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 				int (*deselect) (struct i2c_adapter *,
 						 void *, u32))
 {
+	struct i2c_adapter *parent = muxc->parent;
 	struct i2c_mux_priv *priv;
 	char symlink_name[20];
 	int ret;
@@ -120,7 +136,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 		return NULL;
 
 	/* Set up private adapter data */
-	priv->parent = parent;
+	priv->muxc = muxc;
 	priv->mux_dev = mux_dev;
 	priv->mux_priv = mux_priv;
 	priv->chan_id = chan_id;
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 402e3a6c671a..6e27ea4fb25a 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 *parent;
 	struct i2c_adapter *child;
 	int our_gpio;
 	int our_gpio_release;
@@ -119,6 +118,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct device_node *parent_np;
+	struct i2c_mux_core *muxc;
 	struct i2c_arbitrator_data *arb;
 	enum of_gpio_flags gpio_flags;
 	unsigned long out_init;
@@ -134,13 +134,12 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
-	if (!arb) {
-		dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
+	muxc = i2c_mux_alloc(dev, sizeof(*arb));
+	if (!muxc)
 		return -ENOMEM;
-	}
-	platform_set_drvdata(pdev, arb);
+	arb = i2c_mux_priv(muxc);
 
+	platform_set_drvdata(pdev, muxc);
 	/* Request GPIOs */
 	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
 	if (!gpio_is_valid(ret)) {
@@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 		dev_err(dev, "Cannot parse i2c-parent\n");
 		return -EINVAL;
 	}
-	arb->parent = of_get_i2c_adapter_by_node(parent_np);
+	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
 	of_node_put(parent_np);
-	if (!arb->parent) {
+	if (!muxc->parent) {
 		dev_err(dev, "Cannot find parent bus\n");
 		return -EPROBE_DEFER;
 	}
 
 	/* Actually add the mux adapter */
-	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
+	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
 					 i2c_arbitrator_select,
 					 i2c_arbitrator_deselect);
 	if (!arb->child) {
 		dev_err(dev, "Failed to add adapter\n");
 		ret = -ENODEV;
-		i2c_put_adapter(arb->parent);
+		i2c_put_adapter(muxc->parent);
 	}
 
 	return ret;
@@ -218,10 +217,11 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 
 static int i2c_arbitrator_remove(struct platform_device *pdev)
 {
-	struct i2c_arbitrator_data *arb = platform_get_drvdata(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_put_adapter(arb->parent);
+	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 b8e11c16d98c..ee43dd76a4d7 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 *parent;
 	struct i2c_adapter **adap; /* child busses */
 	struct i2c_mux_gpio_platform_data data;
 	unsigned gpio_base;
@@ -136,19 +135,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 
 static int i2c_mux_gpio_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct gpiomux *mux;
 	struct i2c_adapter *parent;
 	int (*deselect) (struct i2c_adapter *, void *, u32);
 	unsigned initial_state, gpio_base;
 	int i, ret;
 
-	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux) {
-		dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
+	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
+	if (!muxc)
 		return -ENOMEM;
-	}
+	mux = i2c_mux_priv(muxc);
 
-	platform_set_drvdata(pdev, mux);
+	platform_set_drvdata(pdev, muxc);
 
 	if (!dev_get_platdata(&pdev->dev)) {
 		ret = i2c_mux_gpio_probe_dt(mux, pdev);
@@ -180,7 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	if (!parent)
 		return -EPROBE_DEFER;
 
-	mux->parent = parent;
+	muxc->parent = parent;
 	mux->gpio_base = gpio_base;
 
 	mux->adap = devm_kzalloc(&pdev->dev,
@@ -223,7 +222,7 @@ 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(parent, &pdev->dev, mux, nr,
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux, nr,
 						   mux->data.values[i], class,
 						   i2c_mux_gpio_select, deselect);
 		if (!mux->adap[i]) {
@@ -253,7 +252,8 @@ alloc_failed:
 
 static int i2c_mux_gpio_remove(struct platform_device *pdev)
 {
-	struct gpiomux *mux = platform_get_drvdata(pdev);
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 	int i;
 
 	for (i = 0; i < mux->data.n_values; i++)
@@ -262,7 +262,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
 	for (i = 0; i < mux->data.n_gpios; i++)
 		gpio_free(mux->gpio_base + mux->data.gpios[i]);
 
-	i2c_put_adapter(mux->parent);
+	i2c_put_adapter(muxc->parent);
 
 	return 0;
 }
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index d0ba424adebc..47ae2259d1ca 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -73,6 +73,7 @@
 #define SELECT_DELAY_LONG	1000
 
 struct pca9541 {
+	struct i2c_client *client;
 	struct i2c_adapter *mux_adap;
 	unsigned long select_timeout;
 	unsigned long arb_timeout;
@@ -217,7 +218,8 @@ static const u8 pca9541_control[16] = {
  */
 static int pca9541_arbitrate(struct i2c_client *client)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
 	int reg;
 
 	reg = pca9541_reg_read(client, PCA9541_CONTROL);
@@ -324,20 +326,22 @@ static int pca9541_probe(struct i2c_client *client,
 {
 	struct i2c_adapter *adap = client->adapter;
 	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct i2c_mux_core *muxc;
 	struct pca9541 *data;
 	int force;
-	int ret = -ENODEV;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
-		goto err;
+		return -ENODEV;
 
-	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	muxc = i2c_mux_alloc(&client->dev, sizeof(*data));
+	if (!muxc)
+		return -ENOMEM;
+	data = i2c_mux_priv(muxc);
+
+	i2c_set_clientdata(client, muxc);
 
-	i2c_set_clientdata(client, data);
+	data->client = client;
+	muxc->parent = adap;
 
 	/*
 	 * I2C accesses are unprotected here.
@@ -352,34 +356,29 @@ 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(adap, &client->dev, client,
+	data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, client,
 					     force, 0, 0,
 					     pca9541_select_chan,
 					     pca9541_release_chan);
 
 	if (data->mux_adap == NULL) {
 		dev_err(&client->dev, "failed to register master selector\n");
-		goto exit_free;
+		return -ENODEV;
 	}
 
 	dev_info(&client->dev, "registered master selector for I2C %s\n",
 		 client->name);
 
 	return 0;
-
-exit_free:
-	kfree(data);
-err:
-	return ret;
 }
 
 static int pca9541_remove(struct i2c_client *client)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
 
 	i2c_del_mux_adapter(data->mux_adap);
 
-	kfree(data);
 	return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index acfcef3d4068..a4df831fae9d 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -63,6 +63,7 @@ struct pca954x {
 	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
 	u8 last_chan;		/* last register value */
+	struct i2c_client *client;
 };
 
 struct chip_desc {
@@ -191,17 +192,20 @@ static int pca954x_probe(struct i2c_client *client,
 	bool idle_disconnect_dt;
 	struct gpio_desc *gpio;
 	int num, force, class;
+	struct i2c_mux_core *muxc;
 	struct pca954x *data;
 	int ret;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
 		return -ENODEV;
 
-	data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
-	if (!data)
+	muxc = i2c_mux_alloc(&client->dev, sizeof(*data));
+	if (!muxc)
 		return -ENOMEM;
+	data = i2c_mux_priv(muxc);
 
-	i2c_set_clientdata(client, data);
+	i2c_set_clientdata(client, muxc);
+	data->client = client;
 
 	/* Get the mux out of reset if a reset GPIO is specified. */
 	gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
@@ -217,6 +221,7 @@ static int pca954x_probe(struct i2c_client *client,
 		return -ENODEV;
 	}
 
+	muxc->parent = adap;
 	data->type = id->driver_data;
 	data->last_chan = 0;		   /* force the first selection */
 
@@ -241,7 +246,7 @@ static int pca954x_probe(struct i2c_client *client,
 		}
 
 		data->virt_adaps[num] =
-			i2c_add_mux_adapter(adap, &client->dev, client,
+			i2c_add_mux_adapter(muxc, &client->dev, client,
 				force, num, class, pca954x_select_chan,
 				(idle_disconnect_pd || idle_disconnect_dt)
 					? pca954x_deselect_mux : NULL);
@@ -270,7 +275,8 @@ virt_reg_failed:
 
 static int pca954x_remove(struct i2c_client *client)
 {
-	struct pca954x *data = i2c_get_clientdata(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;
 
@@ -287,7 +293,8 @@ static int pca954x_remove(struct i2c_client *client)
 static int pca954x_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
 
 	data->last_chan = 0;
 	return i2c_smbus_write_byte(client, 0);
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index b5a982ba8898..810f75f114a7 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 *parent;
 	struct i2c_adapter **busses;
 };
 
@@ -131,17 +130,18 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 
 static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct i2c_mux_pinctrl *mux;
 	int (*deselect)(struct i2c_adapter *, void *, u32);
 	int i, ret;
 
-	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux) {
-		dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
+	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
+	if (!muxc) {
 		ret = -ENOMEM;
 		goto err;
 	}
-	platform_set_drvdata(pdev, mux);
+	mux = i2c_mux_priv(muxc);
+	platform_set_drvdata(pdev, muxc);
 
 	mux->dev = &pdev->dev;
 
@@ -208,8 +208,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 		deselect = NULL;
 	}
 
-	mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
-	if (!mux->parent) {
+	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
+	if (!muxc->parent) {
 		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
 			mux->pdata->parent_bus_num);
 		ret = -EPROBE_DEFER;
@@ -220,7 +220,7 @@ 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(mux->parent, &pdev->dev,
+		mux->busses[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
 						     mux, bus, i, 0,
 						     i2c_mux_pinctrl_select,
 						     deselect);
@@ -236,20 +236,21 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 err_del_adapter:
 	for (; i > 0; i--)
 		i2c_del_mux_adapter(mux->busses[i - 1]);
-	i2c_put_adapter(mux->parent);
+	i2c_put_adapter(muxc->parent);
 err:
 	return ret;
 }
 
 static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
 {
-	struct i2c_mux_pinctrl *mux = platform_get_drvdata(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_put_adapter(mux->parent);
+	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 5fbd5bd0878f..8bde4cfac512 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 *parent;
 	struct i2c_adapter **adap; /* child busses */
 	struct i2c_mux_reg_platform_data data;
 };
@@ -87,6 +86,7 @@ static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
 static int i2c_mux_reg_probe_dt(struct regmux *mux,
 					struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *adapter_np, *child;
 	struct i2c_adapter *adapter;
@@ -107,7 +107,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 	if (!adapter)
 		return -EPROBE_DEFER;
 
-	mux->parent = adapter;
+	muxc->parent = adapter;
 	mux->data.parent = i2c_adapter_id(adapter);
 	put_device(&adapter->dev);
 
@@ -169,6 +169,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 
 static int i2c_mux_reg_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct regmux *mux;
 	struct i2c_adapter *parent;
 	struct resource *res;
@@ -176,11 +177,12 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	unsigned int class;
 	int i, ret, nr;
 
-	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux)
+	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
+	if (!muxc)
 		return -ENOMEM;
+	mux = i2c_mux_priv(muxc);
 
-	platform_set_drvdata(pdev, mux);
+	platform_set_drvdata(pdev, muxc);
 
 	if (dev_get_platdata(&pdev->dev)) {
 		memcpy(&mux->data, dev_get_platdata(&pdev->dev),
@@ -190,7 +192,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 		if (!parent)
 			return -EPROBE_DEFER;
 
-		mux->parent = parent;
+		muxc->parent = parent;
 	} else {
 		ret = i2c_mux_reg_probe_dt(mux, pdev);
 		if (ret < 0) {
@@ -232,7 +234,7 @@ 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(mux->parent, &pdev->dev, mux,
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux,
 						   nr, mux->data.values[i],
 						   class, i2c_mux_reg_select,
 						   deselect);
@@ -244,7 +246,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	}
 
 	dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
-		 mux->data.n_values, mux->parent->name);
+		 mux->data.n_values, muxc->parent->name);
 
 	return 0;
 
@@ -257,13 +259,14 @@ add_adapter_failed:
 
 static int i2c_mux_reg_remove(struct platform_device *pdev)
 {
-	struct regmux *mux = platform_get_drvdata(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_put_adapter(mux->parent);
+	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 f0e06093b5e8..3aab0d7a1bdc 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -842,7 +842,15 @@ static int inv_mpu_probe(struct i2c_client *client,
 		goto out_remove_trigger;
 	}
 
-	st->mux_adapter = i2c_add_mux_adapter(client->adapter,
+	st->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!st->muxc) {
+		result = -ENOMEM;
+		goto out_unreg_device;
+	}
+	st->muxc->priv = indio_dev;
+	st->muxc->parent = client->adapter;
+
+	st->mux_adapter = i2c_add_mux_adapter(st->muxc,
 					      &client->dev,
 					      indio_dev,
 					      0, 0, 0,
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index db0a4a2758ab..d4929db4b40e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -120,6 +120,7 @@ struct inv_mpu6050_state {
 	enum   inv_devices chip_type;
 	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;
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index feeeb70d841e..a0006aec6937 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1466,8 +1466,16 @@ static int m88ds3103_probe(struct i2c_client *client,
 	if (ret)
 		goto err_kfree;
 
+	dev->muxc  = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+	dev->muxc->priv = dev;
+	dev->muxc->parent = client->adapter;
+
 	/* create mux i2c adapter for tuner */
-	dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+	dev->i2c_adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
 					       dev, 0, 0, 0, m88ds3103_select,
 					       NULL);
 	if (dev->i2c_adapter == NULL) {
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index eee8c22c51ec..52d66c566ac1 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -42,6 +42,7 @@ struct m88ds3103_dev {
 	enum fe_status fe_status;
 	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;
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index b792f305cf15..ebf28b49cab2 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -864,8 +864,16 @@ static int rtl2830_probe(struct i2c_client *client,
 	if (ret)
 		goto err_regmap_exit;
 
+	dev->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_regmap_exit;
+	}
+	dev->muxc->priv = client;
+	dev->muxc->parent = client->adapter;
+
 	/* create muxed i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
 			client, 0, 0, 0, rtl2830_select, NULL);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
index cf793f39a09b..2169c8d9c99c 100644
--- a/drivers/media/dvb-frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -29,6 +29,7 @@ struct rtl2830_dev {
 	struct rtl2830_platform_data *pdata;
 	struct i2c_client *client;
 	struct regmap *regmap;
+	struct i2c_mux_core *muxc;
 	struct i2c_adapter *adapter;
 	struct dvb_frontend fe;
 	bool sleeping;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 78b87b260d74..38402ad3ecdd 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1261,8 +1261,16 @@ static int rtl2832_probe(struct i2c_client *client,
 	if (ret)
 		goto err_regmap_exit;
 
+	dev->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_regmap_exit;
+	}
+	dev->muxc->priv = dev;
+	dev->muxc->parent = i2c;
+
 	/* create muxed i2c adapter for demod tuner bus */
-	dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
+	dev->i2c_adapter_tuner = i2c_add_mux_adapter(dev->muxc, &i2c->dev, dev,
 			0, 0, 0, rtl2832_select, rtl2832_deselect);
 	if (dev->i2c_adapter_tuner == NULL) {
 		ret = -ENODEV;
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 5dcd3a41d23f..2d252bd5b8b1 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -36,6 +36,7 @@ struct rtl2832_dev {
 	struct mutex regmap_mutex;
 	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;
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 821a8f481507..a52756bf9834 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -708,8 +708,16 @@ static int si2168_probe(struct i2c_client *client,
 		goto err;
 	}
 
+	dev->muxc = i2c_mux_alloc(&client->dev, 0);
+	if (!dev->muxc) {
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+	dev->muxc->priv = client;
+	dev->muxc->parent = client->adapter;
+
 	/* create mux i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
 			client, 0, 0, 0, si2168_select, si2168_deselect);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index c07e6fe2cb10..53efb9d562da 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -29,6 +29,7 @@
 
 /* state struct */
 struct si2168_dev {
+	struct i2c_mux_core *muxc;
 	struct i2c_adapter *adapter;
 	struct dvb_frontend fe;
 	enum fe_delivery_system delivery_system;
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index a2fd49b6be83..d805e192e4ca 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1291,6 +1291,9 @@ int cx231xx_dev_init(struct cx231xx *dev)
 	cx231xx_i2c_register(&dev->i2c_bus[1]);
 	cx231xx_i2c_register(&dev->i2c_bus[2]);
 
+	errCode = cx231xx_i2c_mux_create(dev);
+	if (errCode < 0)
+		return errCode;
 	cx231xx_i2c_mux_register(dev, 0);
 	cx231xx_i2c_mux_register(dev, 1);
 
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index a29c345b027d..09c30e753ca5 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -565,13 +565,22 @@ static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
 	return cx231xx_enable_i2c_port_3(dev, chan_id);
 }
 
+int cx231xx_i2c_mux_create(struct cx231xx *dev)
+{
+	dev->muxc = i2c_mux_alloc(dev->dev, 0);
+	if (!dev->muxc)
+		return -ENOMEM;
+	dev->muxc->priv = dev;
+	dev->muxc->parent = &dev->i2c_bus[1].i2c_adap;
+	return 0;
+}
+
 int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
 {
-	struct i2c_adapter *i2c_parent = &dev->i2c_bus[1].i2c_adap;
 	/* what is the correct mux_dev? */
 	struct device *mux_dev = dev->dev;
 
-	dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
+	dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(dev->muxc,
 				mux_dev,
 				dev /* mux_priv */,
 				0,
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 54790fbe8fdc..72f8188e0b01 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -625,6 +625,7 @@ struct cx231xx {
 
 	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
 	struct cx231xx_i2c i2c_bus[3];
+	struct i2c_mux_core *muxc;
 	struct i2c_adapter *i2c_mux_adap[2];
 
 	unsigned int xc_fw_load_done:1;
@@ -759,6 +760,7 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev);
 void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port);
 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);
 struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e16ea5717b7f..6bfc2f9a5a24 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1695,6 +1695,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	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;
 
@@ -1720,14 +1721,14 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	}
 
 	size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
-	stm = devm_kzalloc(dev, size, GFP_KERNEL);
-	if (!stm) {
-		dev_err(dev, "Out of memory\n");
+	muxc = i2c_mux_alloc(dev, size);
+	if (!muxc)
 		return -ENOMEM;
-	}
+	muxc->parent = adap;
+	stm = i2c_mux_priv(muxc);
 	stm->nchans = nchans;
 	for (i = 0; i < nchans; i++) {
-		stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
+		stm->adap[i] = i2c_add_mux_adapter(muxc, dev, client,
 				0, i, 0, unittest_i2c_mux_select_chan, NULL);
 		if (!stm->adap[i]) {
 			dev_err(dev, "Failed to register mux #%d\n", i);
@@ -1737,7 +1738,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 		}
 	}
 
-	i2c_set_clientdata(client, stm);
+	i2c_set_clientdata(client, muxc);
 
 	return 0;
 };
@@ -1746,7 +1747,8 @@ static int unittest_i2c_mux_remove(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
 	struct device_node *np = client->dev.of_node;
-	struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
+	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);
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index b5f9a007a3ab..3ca1783b86ac 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -27,13 +27,25 @@
 
 #ifdef __KERNEL__
 
+struct i2c_mux_core {
+	struct i2c_adapter *parent;
+	void *priv;
+};
+
+struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv);
+
+static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
+{
+	return muxc->priv;
+}
+
 /*
  * 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_adapter *parent,
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 				struct device *mux_dev,
 				void *mux_priv, u32 force_nr, u32 chan_id,
 				unsigned int class,
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 2/8] i2c-mux: move select and deselect ops to i2c_mux_core
  2016-01-05 15:57 ` Peter Rosin
@ 2016-01-05 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

The mux select and deselect ops are common to the mux most of the time,
so store the ops in the mux core.

Change the select and deselect op to work in terms of the mux core instead
of the child adapter. No driver uses the child adapter anyway, and if it
is needed in a future mux driver it can be worked out from the channel id.

i2c-arb-gpio-challenge is special in that it needs the mux device pointer
in the select op, so store that device pointer in the mux core as well.
This pointer is going to get further use in later commits.

i2c-mux-pca954x is special since it does not add its deselect op to all
its child adapters, handle this by adding a mask that makes the deselect
op a no-operation for child adapters not wishing to deselect the mux.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-mux.c                      | 31 ++++++++++--------------------
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 18 ++++++++---------
 drivers/i2c/muxes/i2c-mux-gpio.c           | 19 +++++++++---------
 drivers/i2c/muxes/i2c-mux-pca9541.c        | 18 +++++++++--------
 drivers/i2c/muxes/i2c-mux-pca954x.c        | 30 +++++++++++++++++------------
 drivers/i2c/muxes/i2c-mux-pinctrl.c        | 20 ++++++++-----------
 drivers/i2c/muxes/i2c-mux-reg.c            | 21 +++++++++-----------
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 17 +++++++---------
 drivers/media/dvb-frontends/m88ds3103.c    |  8 ++++----
 drivers/media/dvb-frontends/rtl2830.c      |  8 ++++----
 drivers/media/dvb-frontends/rtl2832.c      | 15 ++++++++-------
 drivers/media/dvb-frontends/si2168.c       | 13 +++++++------
 drivers/media/usb/cx231xx/cx231xx-i2c.c    | 12 ++++--------
 drivers/of/unittest.c                      |  7 +++----
 include/linux/i2c-mux.h                    | 15 ++++++++-------
 15 files changed, 118 insertions(+), 134 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index c2163f6b51d5..6c5cb9f7649b 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -32,13 +32,8 @@ struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
 	struct i2c_mux_core *muxc;
-
 	struct device *mux_dev;
-	void *mux_priv;
 	u32 chan_id;
-
-	int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
-	int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
 };
 
 static int i2c_mux_master_xfer(struct i2c_adapter *adap,
@@ -51,11 +46,11 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = priv->select(parent, priv->mux_priv, priv->chan_id);
+	ret = muxc->select(muxc, priv->chan_id);
 	if (ret >= 0)
 		ret = __i2c_transfer(parent, msgs, num);
-	if (priv->deselect)
-		priv->deselect(parent, priv->mux_priv, priv->chan_id);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
 
 	return ret;
 }
@@ -72,12 +67,12 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = priv->select(parent, priv->mux_priv, priv->chan_id);
+	ret = muxc->select(muxc, priv->chan_id);
 	if (ret >= 0)
 		ret = parent->algo->smbus_xfer(parent, addr, flags,
 					read_write, command, size, data);
-	if (priv->deselect)
-		priv->deselect(parent, priv->mux_priv, priv->chan_id);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
 
 	return ret;
 }
@@ -113,18 +108,15 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 		return NULL;
 	if (sizeof_priv)
 		muxc->priv = muxc + 1;
+	muxc->dev = dev;
 	return muxc;
 }
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
 
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-				struct device *mux_dev,
-				void *mux_priv, u32 force_nr, u32 chan_id,
-				unsigned int class,
-				int (*select) (struct i2c_adapter *,
-					       void *, u32),
-				int (*deselect) (struct i2c_adapter *,
-						 void *, u32))
+					struct device *mux_dev,
+					u32 force_nr, u32 chan_id,
+					unsigned int class)
 {
 	struct i2c_adapter *parent = muxc->parent;
 	struct i2c_mux_priv *priv;
@@ -138,10 +130,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	/* Set up private adapter data */
 	priv->muxc = muxc;
 	priv->mux_dev = mux_dev;
-	priv->mux_priv = mux_priv;
 	priv->chan_id = chan_id;
-	priv->select = select;
-	priv->deselect = deselect;
 
 	/* Need to do algo dynamically because we don't know ahead
 	 * of time what sort of physical adapter we'll be dealing with.
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 6e27ea4fb25a..1e1a479d5b61 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -58,9 +58,9 @@ struct i2c_arbitrator_data {
  *
  * Use the GPIO-based signalling protocol; return -EBUSY if we fail.
  */
-static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	const struct i2c_arbitrator_data *arb = data;
+	const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 	unsigned long stop_retry, stop_time;
 
 	/* Start a round of trying to claim the bus */
@@ -92,7 +92,7 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
 	/* Give up, release our claim */
 	gpio_set_value(arb->our_gpio, arb->our_gpio_release);
 	udelay(arb->slew_delay_us);
-	dev_err(&adap->dev, "Could not claim bus, timeout\n");
+	dev_err(muxc->dev, "Could not claim bus, timeout\n");
 	return -EBUSY;
 }
 
@@ -101,10 +101,9 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
  *
  * Release the I2C bus using the GPIO-based signalling protocol.
  */
-static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data,
-				   u32 chan)
+static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	const struct i2c_arbitrator_data *arb = data;
+	const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 
 	/* Release the bus and wait for the other master to notice */
 	gpio_set_value(arb->our_gpio, arb->our_gpio_release);
@@ -140,6 +139,9 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	arb = i2c_mux_priv(muxc);
 
 	platform_set_drvdata(pdev, muxc);
+
+	muxc->select = i2c_arbitrator_select,
+	muxc->deselect = i2c_arbitrator_deselect;
 	/* Request GPIOs */
 	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
 	if (!gpio_is_valid(ret)) {
@@ -203,9 +205,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	}
 
 	/* Actually add the mux adapter */
-	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
-					 i2c_arbitrator_select,
-					 i2c_arbitrator_deselect);
+	arb->child = i2c_add_mux_adapter(muxc, dev, 0, 0, 0);
 	if (!arb->child) {
 		dev_err(dev, "Failed to add adapter\n");
 		ret = -ENODEV;
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index ee43dd76a4d7..d89a0fbca4bc 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -32,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
 					val & (1 << i));
 }
 
-static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct gpiomux *mux = data;
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 
 	i2c_mux_gpio_set(mux, chan);
 
 	return 0;
 }
 
-static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct gpiomux *mux = data;
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 
 	i2c_mux_gpio_set(mux, mux->data.idle);
 
@@ -138,7 +138,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	struct i2c_mux_core *muxc;
 	struct gpiomux *mux;
 	struct i2c_adapter *parent;
-	int (*deselect) (struct i2c_adapter *, void *, u32);
 	unsigned initial_state, gpio_base;
 	int i, ret;
 
@@ -180,6 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 		return -EPROBE_DEFER;
 
 	muxc->parent = parent;
+	muxc->select = i2c_mux_gpio_select;
 	mux->gpio_base = gpio_base;
 
 	mux->adap = devm_kzalloc(&pdev->dev,
@@ -193,10 +193,10 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 
 	if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
 		initial_state = mux->data.idle;
-		deselect = i2c_mux_gpio_deselect;
+		muxc->deselect = i2c_mux_gpio_deselect;
 	} else {
 		initial_state = mux->data.values[0];
-		deselect = NULL;
+		muxc->deselect = NULL;
 	}
 
 	for (i = 0; i < mux->data.n_gpios; i++) {
@@ -222,9 +222,8 @@ 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, mux, nr,
-						   mux->data.values[i], class,
-						   i2c_mux_gpio_select, deselect);
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
+						   mux->data.values[i], class);
 		if (!mux->adap[i]) {
 			ret = -ENODEV;
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 47ae2259d1ca..ae42039459d0 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -287,9 +287,10 @@ static int pca9541_arbitrate(struct i2c_client *client)
 	return 0;
 }
 
-static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
 	int ret;
 	unsigned long timeout = jiffies + ARB2_TIMEOUT;
 		/* give up after this time */
@@ -311,9 +312,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
 	return -ETIMEDOUT;
 }
 
-static int pca9541_release_chan(struct i2c_adapter *adap,
-				void *client, u32 chan)
+static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan)
 {
+	struct pca9541 *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+
 	pca9541_release_bus(client);
 	return 0;
 }
@@ -342,6 +345,8 @@ static int pca9541_probe(struct i2c_client *client,
 
 	data->client = client;
 	muxc->parent = adap;
+	muxc->select = pca9541_select_chan;
+	muxc->deselect = pca9541_release_chan;
 
 	/*
 	 * I2C accesses are unprotected here.
@@ -356,10 +361,7 @@ 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, client,
-					     force, 0, 0,
-					     pca9541_select_chan,
-					     pca9541_release_chan);
+	data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, force, 0, 0);
 
 	if (data->mux_adap == NULL) {
 		dev_err(&client->dev, "failed to register master selector\n");
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index a4df831fae9d..9e9d708fb2cb 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -63,6 +63,7 @@ struct pca954x {
 	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
 	u8 last_chan;		/* last register value */
+	u8 deselect;
 	struct i2c_client *client;
 };
 
@@ -147,10 +148,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
 	return ret;
 }
 
-static int pca954x_select_chan(struct i2c_adapter *adap,
-			       void *client, u32 chan)
+static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
 	const struct chip_desc *chip = &chips[data->type];
 	u8 regval;
 	int ret = 0;
@@ -163,21 +164,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap,
 
 	/* Only select the channel if its different from the last channel */
 	if (data->last_chan != regval) {
-		ret = pca954x_reg_write(adap, client, regval);
+		ret = pca954x_reg_write(muxc->parent, client, regval);
 		data->last_chan = regval;
 	}
 
 	return ret;
 }
 
-static int pca954x_deselect_mux(struct i2c_adapter *adap,
-				void *client, u32 chan)
+static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+
+	if (!(data->deselect & (1 << chan)))
+		return 0;
 
 	/* Deselect active channel */
 	data->last_chan = 0;
-	return pca954x_reg_write(adap, client, data->last_chan);
+	return pca954x_reg_write(muxc->parent, client, data->last_chan);
 }
 
 /*
@@ -222,6 +226,8 @@ static int pca954x_probe(struct i2c_client *client,
 	}
 
 	muxc->parent = adap;
+	muxc->select = pca954x_select_chan;
+	muxc->deselect = pca954x_deselect_mux;
 	data->type = id->driver_data;
 	data->last_chan = 0;		   /* force the first selection */
 
@@ -243,13 +249,13 @@ static int pca954x_probe(struct i2c_client *client,
 				/* discard unconfigured channels */
 				break;
 			idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
+			data->deselect |= (idle_disconnect_pd
+					   || idle_disconnect_dt) << num;
 		}
 
 		data->virt_adaps[num] =
-			i2c_add_mux_adapter(muxc, &client->dev, client,
-				force, num, class, pca954x_select_chan,
-				(idle_disconnect_pd || idle_disconnect_dt)
-					? pca954x_deselect_mux : NULL);
+			i2c_add_mux_adapter(muxc, &client->dev,
+					    force, num, class);
 
 		if (data->virt_adaps[num] == NULL) {
 			ret = -ENODEV;
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 810f75f114a7..e87c8f77037a 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -34,18 +34,16 @@ struct i2c_mux_pinctrl {
 	struct i2c_adapter **busses;
 };
 
-static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
-				  u32 chan)
+static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_mux_pinctrl *mux = data;
+	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
 
 	return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
 }
 
-static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
-				    u32 chan)
+static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_mux_pinctrl *mux = data;
+	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
 
 	return pinctrl_select_state(mux->pinctrl, mux->state_idle);
 }
@@ -132,7 +130,6 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 {
 	struct i2c_mux_core *muxc;
 	struct i2c_mux_pinctrl *mux;
-	int (*deselect)(struct i2c_adapter *, void *, u32);
 	int i, ret;
 
 	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
@@ -203,10 +200,11 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 			goto err;
 		}
 
-		deselect = i2c_mux_pinctrl_deselect;
+		muxc->deselect = i2c_mux_pinctrl_deselect;
 	} else {
-		deselect = NULL;
+		muxc->deselect = NULL;
 	}
+	muxc->select = i2c_mux_pinctrl_select;
 
 	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
 	if (!muxc->parent) {
@@ -221,9 +219,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 				(mux->pdata->base_bus_num + i) : 0;
 
 		mux->busses[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
-						     mux, bus, i, 0,
-						     i2c_mux_pinctrl_select,
-						     deselect);
+						     bus, i, 0);
 		if (!mux->busses[i]) {
 			ret = -ENODEV;
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 8bde4cfac512..3b01e7809a66 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -63,18 +63,16 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id)
 	return 0;
 }
 
-static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data,
-			      unsigned int chan)
+static int i2c_mux_reg_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct regmux *mux = data;
+	struct regmux *mux = i2c_mux_priv(muxc);
 
 	return i2c_mux_reg_set(mux, chan);
 }
 
-static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
-				unsigned int chan)
+static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct regmux *mux = data;
+	struct regmux *mux = i2c_mux_priv(muxc);
 
 	if (mux->data.idle_in_use)
 		return i2c_mux_reg_set(mux, mux->data.idle);
@@ -173,7 +171,6 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	struct regmux *mux;
 	struct i2c_adapter *parent;
 	struct resource *res;
-	int (*deselect)(struct i2c_adapter *, void *, u32);
 	unsigned int class;
 	int i, ret, nr;
 
@@ -225,19 +222,19 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	muxc->select = i2c_mux_reg_select;
 	if (mux->data.idle_in_use)
-		deselect = i2c_mux_reg_deselect;
+		muxc->deselect = i2c_mux_reg_deselect;
 	else
-		deselect = NULL;
+		muxc->deselect = NULL;
 
 	for (i = 0; i < mux->data.n_values; i++) {
 		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, mux,
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
 						   nr, mux->data.values[i],
-						   class, i2c_mux_reg_select,
-						   deselect);
+						   class);
 		if (!mux->adap[i]) {
 			ret = -ENODEV;
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 3aab0d7a1bdc..0a47396bc5be 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -109,10 +109,9 @@ static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st,
 	return 0;
 }
 
-static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
-				     u32 chan_id)
+static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct iio_dev *indio_dev = mux_priv;
+	struct iio_dev *indio_dev = i2c_mux_priv(muxc);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 	int ret = 0;
 
@@ -138,10 +137,9 @@ write_error:
 	return ret;
 }
 
-static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
-				       void *mux_priv, u32 chan_id)
+static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct iio_dev *indio_dev = mux_priv;
+	struct iio_dev *indio_dev = i2c_mux_priv(muxc);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&indio_dev->mlock);
@@ -849,13 +847,12 @@ static int inv_mpu_probe(struct i2c_client *client,
 	}
 	st->muxc->priv = indio_dev;
 	st->muxc->parent = client->adapter;
+	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,
-					      indio_dev,
-					      0, 0, 0,
-					      inv_mpu6050_select_bypass,
-					      inv_mpu6050_deselect_bypass);
+					      0, 0, 0);
 	if (!st->mux_adapter) {
 		result = -ENODEV;
 		goto out_unreg_device;
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index a0006aec6937..c9f8296ea421 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1251,9 +1251,9 @@ static void m88ds3103_release(struct dvb_frontend *fe)
 	i2c_unregister_device(client);
 }
 
-static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct m88ds3103_dev *dev = mux_priv;
+	struct m88ds3103_dev *dev = i2c_mux_priv(muxc);
 	struct i2c_client *client = dev->client;
 	int ret;
 	struct i2c_msg msg = {
@@ -1473,11 +1473,11 @@ static int m88ds3103_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = dev;
 	dev->muxc->parent = client->adapter;
+	dev->muxc->select = m88ds3103_select;
 
 	/* create mux i2c adapter for tuner */
 	dev->i2c_adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-					       dev, 0, 0, 0, m88ds3103_select,
-					       NULL);
+					       0, 0, 0);
 	if (dev->i2c_adapter == NULL) {
 		ret = -ENOMEM;
 		goto err_kfree;
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index ebf28b49cab2..d6330e8d5fa4 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -677,9 +677,9 @@ err:
  * adapter lock is already taken by tuner driver.
  * Gate is closed automatically after single I2C transfer.
  */
-static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2830_select(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct i2c_client *client = mux_priv;
+	struct i2c_client *client = i2c_mux_priv(muxc);
 	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 
@@ -871,10 +871,10 @@ static int rtl2830_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = client;
 	dev->muxc->parent = client->adapter;
+	dev->muxc->select = rtl2830_select;
 
 	/* create muxed i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-			client, 0, 0, 0, rtl2830_select, NULL);
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
 		goto err_regmap_exit;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 38402ad3ecdd..c8fd990fdae8 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -866,9 +866,9 @@ err:
 	dev_dbg(&client->dev, "failed=%d\n", ret);
 }
 
-static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2832_select(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct rtl2832_dev *dev = mux_priv;
+	struct rtl2832_dev *dev = i2c_mux_priv(muxc);
 	struct i2c_client *client = dev->client;
 	int ret;
 
@@ -889,10 +889,9 @@ err:
 	return ret;
 }
 
-static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
-			    u32 chan_id)
+static int rtl2832_deselect(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct rtl2832_dev *dev = mux_priv;
+	struct rtl2832_dev *dev = i2c_mux_priv(muxc);
 
 	schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100));
 	return 0;
@@ -1268,10 +1267,12 @@ static int rtl2832_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = dev;
 	dev->muxc->parent = i2c;
+	dev->muxc->select = rtl2832_select;
+	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, dev,
-			0, 0, 0, rtl2832_select, rtl2832_deselect);
+	dev->i2c_adapter_tuner = i2c_add_mux_adapter(dev->muxc, &i2c->dev,
+						     0, 0, 0);
 	if (dev->i2c_adapter_tuner == NULL) {
 		ret = -ENODEV;
 		goto err_regmap_exit;
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index a52756bf9834..5b1872b1bbf4 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -615,9 +615,9 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
  * We must use unlocked I2C I/O because I2C adapter lock is already taken
  * by the caller (usually tuner driver).
  */
-static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_client *client = mux_priv;
+	struct i2c_client *client = i2c_mux_priv(muxc);
 	int ret;
 	struct si2168_cmd cmd;
 
@@ -635,9 +635,9 @@ err:
 	return ret;
 }
 
-static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_client *client = mux_priv;
+	struct i2c_client *client = i2c_mux_priv(muxc);
 	int ret;
 	struct si2168_cmd cmd;
 
@@ -715,10 +715,11 @@ static int si2168_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = client;
 	dev->muxc->parent = client->adapter;
+	dev->muxc->select = si2168_select;
+	dev->muxc->deselect = si2168_deselect;
 
 	/* create mux i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-			client, 0, 0, 0, si2168_select, si2168_deselect);
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
 		goto err_kfree;
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 09c30e753ca5..51760bfc7cbc 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -557,10 +557,9 @@ int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
  * cx231xx_i2c_mux_select()
  * switch i2c master number 1 between port1 and port3
  */
-static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
-			void *mux_priv, u32 chan_id)
+static int cx231xx_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct cx231xx *dev = mux_priv;
+	struct cx231xx *dev = i2c_mux_priv(muxc);
 
 	return cx231xx_enable_i2c_port_3(dev, chan_id);
 }
@@ -572,6 +571,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
 		return -ENOMEM;
 	dev->muxc->priv = dev;
 	dev->muxc->parent = &dev->i2c_bus[1].i2c_adap;
+	dev->muxc->select = cx231xx_i2c_mux_select;
 	return 0;
 }
 
@@ -582,13 +582,9 @@ int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
 
 	dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(dev->muxc,
 				mux_dev,
-				dev /* mux_priv */,
 				0,
 				mux_no /* chan_id */,
-				0 /* class */,
-				&cx231xx_i2c_mux_select,
-				NULL);
-
+				0 /* class */);
 	if (!dev->i2c_mux_adap[mux_no])
 		dev_warn(dev->dev,
 			 "i2c mux %d register FAILED\n", mux_no);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 6bfc2f9a5a24..a4abd9b588b9 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1682,8 +1682,7 @@ struct unittest_i2c_mux_data {
 	struct i2c_adapter *adap[];
 };
 
-static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
-			       void *client, u32 chan)
+static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
 	return 0;
 }
@@ -1725,11 +1724,11 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	if (!muxc)
 		return -ENOMEM;
 	muxc->parent = adap;
+	muxc->select = unittest_i2c_mux_select_chan;
 	stm = i2c_mux_priv(muxc);
 	stm->nchans = nchans;
 	for (i = 0; i < nchans; i++) {
-		stm->adap[i] = i2c_add_mux_adapter(muxc, dev, client,
-				0, i, 0, unittest_i2c_mux_select_chan, NULL);
+		stm->adap[i] = i2c_add_mux_adapter(muxc, dev, 0, i, 0);
 		if (!stm->adap[i]) {
 			dev_err(dev, "Failed to register mux #%d\n", i);
 			for (i--; i >= 0; i--)
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 3ca1783b86ac..5cd6e1e664e0 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -29,7 +29,12 @@
 
 struct i2c_mux_core {
 	struct i2c_adapter *parent;
+	struct device *dev;
+
 	void *priv;
+
+	int (*select)(struct i2c_mux_core *, u32 chan_id);
+	int (*deselect)(struct i2c_mux_core *, u32 chan_id);
 };
 
 struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv);
@@ -46,13 +51,9 @@ static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
  * mux control.
  */
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-				struct device *mux_dev,
-				void *mux_priv, u32 force_nr, u32 chan_id,
-				unsigned int class,
-				int (*select) (struct i2c_adapter *,
-					       void *mux_dev, u32 chan_id),
-				int (*deselect) (struct i2c_adapter *,
-						 void *mux_dev, u32 chan_id));
+					struct device *mux_dev,
+					u32 force_nr, u32 chan_id,
+					unsigned int class);
 
 void i2c_del_mux_adapter(struct i2c_adapter *adap);
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 2/8] i2c-mux: move select and deselect ops to i2c_mux_core
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda@axentia.se>

The mux select and deselect ops are common to the mux most of the time,
so store the ops in the mux core.

Change the select and deselect op to work in terms of the mux core instead
of the child adapter. No driver uses the child adapter anyway, and if it
is needed in a future mux driver it can be worked out from the channel id.

i2c-arb-gpio-challenge is special in that it needs the mux device pointer
in the select op, so store that device pointer in the mux core as well.
This pointer is going to get further use in later commits.

i2c-mux-pca954x is special since it does not add its deselect op to all
its child adapters, handle this by adding a mask that makes the deselect
op a no-operation for child adapters not wishing to deselect the mux.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-mux.c                      | 31 ++++++++++--------------------
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 18 ++++++++---------
 drivers/i2c/muxes/i2c-mux-gpio.c           | 19 +++++++++---------
 drivers/i2c/muxes/i2c-mux-pca9541.c        | 18 +++++++++--------
 drivers/i2c/muxes/i2c-mux-pca954x.c        | 30 +++++++++++++++++------------
 drivers/i2c/muxes/i2c-mux-pinctrl.c        | 20 ++++++++-----------
 drivers/i2c/muxes/i2c-mux-reg.c            | 21 +++++++++-----------
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 17 +++++++---------
 drivers/media/dvb-frontends/m88ds3103.c    |  8 ++++----
 drivers/media/dvb-frontends/rtl2830.c      |  8 ++++----
 drivers/media/dvb-frontends/rtl2832.c      | 15 ++++++++-------
 drivers/media/dvb-frontends/si2168.c       | 13 +++++++------
 drivers/media/usb/cx231xx/cx231xx-i2c.c    | 12 ++++--------
 drivers/of/unittest.c                      |  7 +++----
 include/linux/i2c-mux.h                    | 15 ++++++++-------
 15 files changed, 118 insertions(+), 134 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index c2163f6b51d5..6c5cb9f7649b 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -32,13 +32,8 @@ struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
 	struct i2c_mux_core *muxc;
-
 	struct device *mux_dev;
-	void *mux_priv;
 	u32 chan_id;
-
-	int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
-	int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
 };
 
 static int i2c_mux_master_xfer(struct i2c_adapter *adap,
@@ -51,11 +46,11 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = priv->select(parent, priv->mux_priv, priv->chan_id);
+	ret = muxc->select(muxc, priv->chan_id);
 	if (ret >= 0)
 		ret = __i2c_transfer(parent, msgs, num);
-	if (priv->deselect)
-		priv->deselect(parent, priv->mux_priv, priv->chan_id);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
 
 	return ret;
 }
@@ -72,12 +67,12 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = priv->select(parent, priv->mux_priv, priv->chan_id);
+	ret = muxc->select(muxc, priv->chan_id);
 	if (ret >= 0)
 		ret = parent->algo->smbus_xfer(parent, addr, flags,
 					read_write, command, size, data);
-	if (priv->deselect)
-		priv->deselect(parent, priv->mux_priv, priv->chan_id);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
 
 	return ret;
 }
@@ -113,18 +108,15 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 		return NULL;
 	if (sizeof_priv)
 		muxc->priv = muxc + 1;
+	muxc->dev = dev;
 	return muxc;
 }
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
 
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-				struct device *mux_dev,
-				void *mux_priv, u32 force_nr, u32 chan_id,
-				unsigned int class,
-				int (*select) (struct i2c_adapter *,
-					       void *, u32),
-				int (*deselect) (struct i2c_adapter *,
-						 void *, u32))
+					struct device *mux_dev,
+					u32 force_nr, u32 chan_id,
+					unsigned int class)
 {
 	struct i2c_adapter *parent = muxc->parent;
 	struct i2c_mux_priv *priv;
@@ -138,10 +130,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	/* Set up private adapter data */
 	priv->muxc = muxc;
 	priv->mux_dev = mux_dev;
-	priv->mux_priv = mux_priv;
 	priv->chan_id = chan_id;
-	priv->select = select;
-	priv->deselect = deselect;
 
 	/* Need to do algo dynamically because we don't know ahead
 	 * of time what sort of physical adapter we'll be dealing with.
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 6e27ea4fb25a..1e1a479d5b61 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -58,9 +58,9 @@ struct i2c_arbitrator_data {
  *
  * Use the GPIO-based signalling protocol; return -EBUSY if we fail.
  */
-static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	const struct i2c_arbitrator_data *arb = data;
+	const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 	unsigned long stop_retry, stop_time;
 
 	/* Start a round of trying to claim the bus */
@@ -92,7 +92,7 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
 	/* Give up, release our claim */
 	gpio_set_value(arb->our_gpio, arb->our_gpio_release);
 	udelay(arb->slew_delay_us);
-	dev_err(&adap->dev, "Could not claim bus, timeout\n");
+	dev_err(muxc->dev, "Could not claim bus, timeout\n");
 	return -EBUSY;
 }
 
@@ -101,10 +101,9 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
  *
  * Release the I2C bus using the GPIO-based signalling protocol.
  */
-static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data,
-				   u32 chan)
+static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	const struct i2c_arbitrator_data *arb = data;
+	const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 
 	/* Release the bus and wait for the other master to notice */
 	gpio_set_value(arb->our_gpio, arb->our_gpio_release);
@@ -140,6 +139,9 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	arb = i2c_mux_priv(muxc);
 
 	platform_set_drvdata(pdev, muxc);
+
+	muxc->select = i2c_arbitrator_select,
+	muxc->deselect = i2c_arbitrator_deselect;
 	/* Request GPIOs */
 	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
 	if (!gpio_is_valid(ret)) {
@@ -203,9 +205,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	}
 
 	/* Actually add the mux adapter */
-	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
-					 i2c_arbitrator_select,
-					 i2c_arbitrator_deselect);
+	arb->child = i2c_add_mux_adapter(muxc, dev, 0, 0, 0);
 	if (!arb->child) {
 		dev_err(dev, "Failed to add adapter\n");
 		ret = -ENODEV;
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index ee43dd76a4d7..d89a0fbca4bc 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -32,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
 					val & (1 << i));
 }
 
-static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct gpiomux *mux = data;
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 
 	i2c_mux_gpio_set(mux, chan);
 
 	return 0;
 }
 
-static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct gpiomux *mux = data;
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 
 	i2c_mux_gpio_set(mux, mux->data.idle);
 
@@ -138,7 +138,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	struct i2c_mux_core *muxc;
 	struct gpiomux *mux;
 	struct i2c_adapter *parent;
-	int (*deselect) (struct i2c_adapter *, void *, u32);
 	unsigned initial_state, gpio_base;
 	int i, ret;
 
@@ -180,6 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 		return -EPROBE_DEFER;
 
 	muxc->parent = parent;
+	muxc->select = i2c_mux_gpio_select;
 	mux->gpio_base = gpio_base;
 
 	mux->adap = devm_kzalloc(&pdev->dev,
@@ -193,10 +193,10 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 
 	if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
 		initial_state = mux->data.idle;
-		deselect = i2c_mux_gpio_deselect;
+		muxc->deselect = i2c_mux_gpio_deselect;
 	} else {
 		initial_state = mux->data.values[0];
-		deselect = NULL;
+		muxc->deselect = NULL;
 	}
 
 	for (i = 0; i < mux->data.n_gpios; i++) {
@@ -222,9 +222,8 @@ 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, mux, nr,
-						   mux->data.values[i], class,
-						   i2c_mux_gpio_select, deselect);
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
+						   mux->data.values[i], class);
 		if (!mux->adap[i]) {
 			ret = -ENODEV;
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 47ae2259d1ca..ae42039459d0 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -287,9 +287,10 @@ static int pca9541_arbitrate(struct i2c_client *client)
 	return 0;
 }
 
-static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
 	int ret;
 	unsigned long timeout = jiffies + ARB2_TIMEOUT;
 		/* give up after this time */
@@ -311,9 +312,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
 	return -ETIMEDOUT;
 }
 
-static int pca9541_release_chan(struct i2c_adapter *adap,
-				void *client, u32 chan)
+static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan)
 {
+	struct pca9541 *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+
 	pca9541_release_bus(client);
 	return 0;
 }
@@ -342,6 +345,8 @@ static int pca9541_probe(struct i2c_client *client,
 
 	data->client = client;
 	muxc->parent = adap;
+	muxc->select = pca9541_select_chan;
+	muxc->deselect = pca9541_release_chan;
 
 	/*
 	 * I2C accesses are unprotected here.
@@ -356,10 +361,7 @@ 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, client,
-					     force, 0, 0,
-					     pca9541_select_chan,
-					     pca9541_release_chan);
+	data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, force, 0, 0);
 
 	if (data->mux_adap == NULL) {
 		dev_err(&client->dev, "failed to register master selector\n");
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index a4df831fae9d..9e9d708fb2cb 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -63,6 +63,7 @@ struct pca954x {
 	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
 	u8 last_chan;		/* last register value */
+	u8 deselect;
 	struct i2c_client *client;
 };
 
@@ -147,10 +148,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
 	return ret;
 }
 
-static int pca954x_select_chan(struct i2c_adapter *adap,
-			       void *client, u32 chan)
+static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
 	const struct chip_desc *chip = &chips[data->type];
 	u8 regval;
 	int ret = 0;
@@ -163,21 +164,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap,
 
 	/* Only select the channel if its different from the last channel */
 	if (data->last_chan != regval) {
-		ret = pca954x_reg_write(adap, client, regval);
+		ret = pca954x_reg_write(muxc->parent, client, regval);
 		data->last_chan = regval;
 	}
 
 	return ret;
 }
 
-static int pca954x_deselect_mux(struct i2c_adapter *adap,
-				void *client, u32 chan)
+static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+
+	if (!(data->deselect & (1 << chan)))
+		return 0;
 
 	/* Deselect active channel */
 	data->last_chan = 0;
-	return pca954x_reg_write(adap, client, data->last_chan);
+	return pca954x_reg_write(muxc->parent, client, data->last_chan);
 }
 
 /*
@@ -222,6 +226,8 @@ static int pca954x_probe(struct i2c_client *client,
 	}
 
 	muxc->parent = adap;
+	muxc->select = pca954x_select_chan;
+	muxc->deselect = pca954x_deselect_mux;
 	data->type = id->driver_data;
 	data->last_chan = 0;		   /* force the first selection */
 
@@ -243,13 +249,13 @@ static int pca954x_probe(struct i2c_client *client,
 				/* discard unconfigured channels */
 				break;
 			idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
+			data->deselect |= (idle_disconnect_pd
+					   || idle_disconnect_dt) << num;
 		}
 
 		data->virt_adaps[num] =
-			i2c_add_mux_adapter(muxc, &client->dev, client,
-				force, num, class, pca954x_select_chan,
-				(idle_disconnect_pd || idle_disconnect_dt)
-					? pca954x_deselect_mux : NULL);
+			i2c_add_mux_adapter(muxc, &client->dev,
+					    force, num, class);
 
 		if (data->virt_adaps[num] == NULL) {
 			ret = -ENODEV;
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 810f75f114a7..e87c8f77037a 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -34,18 +34,16 @@ struct i2c_mux_pinctrl {
 	struct i2c_adapter **busses;
 };
 
-static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
-				  u32 chan)
+static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_mux_pinctrl *mux = data;
+	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
 
 	return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
 }
 
-static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
-				    u32 chan)
+static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_mux_pinctrl *mux = data;
+	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
 
 	return pinctrl_select_state(mux->pinctrl, mux->state_idle);
 }
@@ -132,7 +130,6 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 {
 	struct i2c_mux_core *muxc;
 	struct i2c_mux_pinctrl *mux;
-	int (*deselect)(struct i2c_adapter *, void *, u32);
 	int i, ret;
 
 	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
@@ -203,10 +200,11 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 			goto err;
 		}
 
-		deselect = i2c_mux_pinctrl_deselect;
+		muxc->deselect = i2c_mux_pinctrl_deselect;
 	} else {
-		deselect = NULL;
+		muxc->deselect = NULL;
 	}
+	muxc->select = i2c_mux_pinctrl_select;
 
 	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
 	if (!muxc->parent) {
@@ -221,9 +219,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 				(mux->pdata->base_bus_num + i) : 0;
 
 		mux->busses[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
-						     mux, bus, i, 0,
-						     i2c_mux_pinctrl_select,
-						     deselect);
+						     bus, i, 0);
 		if (!mux->busses[i]) {
 			ret = -ENODEV;
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 8bde4cfac512..3b01e7809a66 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -63,18 +63,16 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id)
 	return 0;
 }
 
-static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data,
-			      unsigned int chan)
+static int i2c_mux_reg_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct regmux *mux = data;
+	struct regmux *mux = i2c_mux_priv(muxc);
 
 	return i2c_mux_reg_set(mux, chan);
 }
 
-static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
-				unsigned int chan)
+static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct regmux *mux = data;
+	struct regmux *mux = i2c_mux_priv(muxc);
 
 	if (mux->data.idle_in_use)
 		return i2c_mux_reg_set(mux, mux->data.idle);
@@ -173,7 +171,6 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	struct regmux *mux;
 	struct i2c_adapter *parent;
 	struct resource *res;
-	int (*deselect)(struct i2c_adapter *, void *, u32);
 	unsigned int class;
 	int i, ret, nr;
 
@@ -225,19 +222,19 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	muxc->select = i2c_mux_reg_select;
 	if (mux->data.idle_in_use)
-		deselect = i2c_mux_reg_deselect;
+		muxc->deselect = i2c_mux_reg_deselect;
 	else
-		deselect = NULL;
+		muxc->deselect = NULL;
 
 	for (i = 0; i < mux->data.n_values; i++) {
 		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, mux,
+		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev,
 						   nr, mux->data.values[i],
-						   class, i2c_mux_reg_select,
-						   deselect);
+						   class);
 		if (!mux->adap[i]) {
 			ret = -ENODEV;
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 3aab0d7a1bdc..0a47396bc5be 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -109,10 +109,9 @@ static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st,
 	return 0;
 }
 
-static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
-				     u32 chan_id)
+static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct iio_dev *indio_dev = mux_priv;
+	struct iio_dev *indio_dev = i2c_mux_priv(muxc);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 	int ret = 0;
 
@@ -138,10 +137,9 @@ write_error:
 	return ret;
 }
 
-static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
-				       void *mux_priv, u32 chan_id)
+static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct iio_dev *indio_dev = mux_priv;
+	struct iio_dev *indio_dev = i2c_mux_priv(muxc);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&indio_dev->mlock);
@@ -849,13 +847,12 @@ static int inv_mpu_probe(struct i2c_client *client,
 	}
 	st->muxc->priv = indio_dev;
 	st->muxc->parent = client->adapter;
+	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,
-					      indio_dev,
-					      0, 0, 0,
-					      inv_mpu6050_select_bypass,
-					      inv_mpu6050_deselect_bypass);
+					      0, 0, 0);
 	if (!st->mux_adapter) {
 		result = -ENODEV;
 		goto out_unreg_device;
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index a0006aec6937..c9f8296ea421 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1251,9 +1251,9 @@ static void m88ds3103_release(struct dvb_frontend *fe)
 	i2c_unregister_device(client);
 }
 
-static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct m88ds3103_dev *dev = mux_priv;
+	struct m88ds3103_dev *dev = i2c_mux_priv(muxc);
 	struct i2c_client *client = dev->client;
 	int ret;
 	struct i2c_msg msg = {
@@ -1473,11 +1473,11 @@ static int m88ds3103_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = dev;
 	dev->muxc->parent = client->adapter;
+	dev->muxc->select = m88ds3103_select;
 
 	/* create mux i2c adapter for tuner */
 	dev->i2c_adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-					       dev, 0, 0, 0, m88ds3103_select,
-					       NULL);
+					       0, 0, 0);
 	if (dev->i2c_adapter == NULL) {
 		ret = -ENOMEM;
 		goto err_kfree;
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index ebf28b49cab2..d6330e8d5fa4 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -677,9 +677,9 @@ err:
  * adapter lock is already taken by tuner driver.
  * Gate is closed automatically after single I2C transfer.
  */
-static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2830_select(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct i2c_client *client = mux_priv;
+	struct i2c_client *client = i2c_mux_priv(muxc);
 	struct rtl2830_dev *dev = i2c_get_clientdata(client);
 	int ret;
 
@@ -871,10 +871,10 @@ static int rtl2830_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = client;
 	dev->muxc->parent = client->adapter;
+	dev->muxc->select = rtl2830_select;
 
 	/* create muxed i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-			client, 0, 0, 0, rtl2830_select, NULL);
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
 		goto err_regmap_exit;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 38402ad3ecdd..c8fd990fdae8 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -866,9 +866,9 @@ err:
 	dev_dbg(&client->dev, "failed=%d\n", ret);
 }
 
-static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2832_select(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct rtl2832_dev *dev = mux_priv;
+	struct rtl2832_dev *dev = i2c_mux_priv(muxc);
 	struct i2c_client *client = dev->client;
 	int ret;
 
@@ -889,10 +889,9 @@ err:
 	return ret;
 }
 
-static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
-			    u32 chan_id)
+static int rtl2832_deselect(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct rtl2832_dev *dev = mux_priv;
+	struct rtl2832_dev *dev = i2c_mux_priv(muxc);
 
 	schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100));
 	return 0;
@@ -1268,10 +1267,12 @@ static int rtl2832_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = dev;
 	dev->muxc->parent = i2c;
+	dev->muxc->select = rtl2832_select;
+	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, dev,
-			0, 0, 0, rtl2832_select, rtl2832_deselect);
+	dev->i2c_adapter_tuner = i2c_add_mux_adapter(dev->muxc, &i2c->dev,
+						     0, 0, 0);
 	if (dev->i2c_adapter_tuner == NULL) {
 		ret = -ENODEV;
 		goto err_regmap_exit;
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index a52756bf9834..5b1872b1bbf4 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -615,9 +615,9 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
  * We must use unlocked I2C I/O because I2C adapter lock is already taken
  * by the caller (usually tuner driver).
  */
-static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_client *client = mux_priv;
+	struct i2c_client *client = i2c_mux_priv(muxc);
 	int ret;
 	struct si2168_cmd cmd;
 
@@ -635,9 +635,9 @@ err:
 	return ret;
 }
 
-static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_client *client = mux_priv;
+	struct i2c_client *client = i2c_mux_priv(muxc);
 	int ret;
 	struct si2168_cmd cmd;
 
@@ -715,10 +715,11 @@ static int si2168_probe(struct i2c_client *client,
 	}
 	dev->muxc->priv = client;
 	dev->muxc->parent = client->adapter;
+	dev->muxc->select = si2168_select;
+	dev->muxc->deselect = si2168_deselect;
 
 	/* create mux i2c adapter for tuner */
-	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev,
-			client, 0, 0, 0, si2168_select, si2168_deselect);
+	dev->adapter = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
 	if (dev->adapter == NULL) {
 		ret = -ENODEV;
 		goto err_kfree;
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 09c30e753ca5..51760bfc7cbc 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -557,10 +557,9 @@ int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
  * cx231xx_i2c_mux_select()
  * switch i2c master number 1 between port1 and port3
  */
-static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
-			void *mux_priv, u32 chan_id)
+static int cx231xx_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct cx231xx *dev = mux_priv;
+	struct cx231xx *dev = i2c_mux_priv(muxc);
 
 	return cx231xx_enable_i2c_port_3(dev, chan_id);
 }
@@ -572,6 +571,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
 		return -ENOMEM;
 	dev->muxc->priv = dev;
 	dev->muxc->parent = &dev->i2c_bus[1].i2c_adap;
+	dev->muxc->select = cx231xx_i2c_mux_select;
 	return 0;
 }
 
@@ -582,13 +582,9 @@ int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
 
 	dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(dev->muxc,
 				mux_dev,
-				dev /* mux_priv */,
 				0,
 				mux_no /* chan_id */,
-				0 /* class */,
-				&cx231xx_i2c_mux_select,
-				NULL);
-
+				0 /* class */);
 	if (!dev->i2c_mux_adap[mux_no])
 		dev_warn(dev->dev,
 			 "i2c mux %d register FAILED\n", mux_no);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 6bfc2f9a5a24..a4abd9b588b9 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1682,8 +1682,7 @@ struct unittest_i2c_mux_data {
 	struct i2c_adapter *adap[];
 };
 
-static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
-			       void *client, u32 chan)
+static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
 	return 0;
 }
@@ -1725,11 +1724,11 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	if (!muxc)
 		return -ENOMEM;
 	muxc->parent = adap;
+	muxc->select = unittest_i2c_mux_select_chan;
 	stm = i2c_mux_priv(muxc);
 	stm->nchans = nchans;
 	for (i = 0; i < nchans; i++) {
-		stm->adap[i] = i2c_add_mux_adapter(muxc, dev, client,
-				0, i, 0, unittest_i2c_mux_select_chan, NULL);
+		stm->adap[i] = i2c_add_mux_adapter(muxc, dev, 0, i, 0);
 		if (!stm->adap[i]) {
 			dev_err(dev, "Failed to register mux #%d\n", i);
 			for (i--; i >= 0; i--)
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 3ca1783b86ac..5cd6e1e664e0 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -29,7 +29,12 @@
 
 struct i2c_mux_core {
 	struct i2c_adapter *parent;
+	struct device *dev;
+
 	void *priv;
+
+	int (*select)(struct i2c_mux_core *, u32 chan_id);
+	int (*deselect)(struct i2c_mux_core *, u32 chan_id);
 };
 
 struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv);
@@ -46,13 +51,9 @@ static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
  * mux control.
  */
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-				struct device *mux_dev,
-				void *mux_priv, u32 force_nr, u32 chan_id,
-				unsigned int class,
-				int (*select) (struct i2c_adapter *,
-					       void *mux_dev, u32 chan_id),
-				int (*deselect) (struct i2c_adapter *,
-						 void *mux_dev, u32 chan_id));
+					struct device *mux_dev,
+					u32 force_nr, u32 chan_id,
+					unsigned int class);
 
 void i2c_del_mux_adapter(struct i2c_adapter *adap);
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
  2016-01-05 15:57 ` Peter Rosin
@ 2016-01-05 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

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


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 4/8] i2c-mux: remove the mux dev pointer from the mux per channel data
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

The dev pointer is readily available in the mux core struct, no point in
keeping multiple copies around.

The patch also fixes a bug in rtl2832, which attached its mux slave
adapter to the device owning the mux parent adapter instead of
attaching it to its own device.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-mux.c                      | 24 ++++++++++++------------
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c |  2 +-
 drivers/i2c/muxes/i2c-mux-gpio.c           |  3 +--
 drivers/i2c/muxes/i2c-mux-pca9541.c        |  2 +-
 drivers/i2c/muxes/i2c-mux-pca954x.c        |  3 +--
 drivers/i2c/muxes/i2c-mux-pinctrl.c        |  3 +--
 drivers/i2c/muxes/i2c-mux-reg.c            |  3 +--
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c |  2 +-
 drivers/media/dvb-frontends/m88ds3103.c    |  2 +-
 drivers/media/dvb-frontends/rtl2830.c      |  2 +-
 drivers/media/dvb-frontends/rtl2832.c      |  2 +-
 drivers/media/dvb-frontends/si2168.c       |  2 +-
 drivers/media/usb/cx231xx/cx231xx-i2c.c    |  3 ---
 drivers/of/unittest.c                      |  2 +-
 include/linux/i2c-mux.h                    |  1 -
 15 files changed, 24 insertions(+), 32 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 7ba0308537a8..5c1088079231 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -32,7 +32,6 @@ struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
 	struct i2c_mux_core *muxc;
-	struct device *mux_dev;
 	u32 chan_id;
 };
 
@@ -137,7 +136,6 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
 
 int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-			struct device *mux_dev,
 			u32 force_nr, u32 chan_id,
 			unsigned int class)
 {
@@ -162,7 +160,6 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 
 	/* Set up private adapter data */
 	priv->muxc = muxc;
-	priv->mux_dev = mux_dev;
 	priv->chan_id = chan_id;
 
 	/* Need to do algo dynamically because we don't know ahead
@@ -197,11 +194,11 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	 * Try to populate the mux adapter's of_node, expands to
 	 * nothing if !CONFIG_OF.
 	 */
-	if (mux_dev->of_node) {
+	if (muxc->dev->of_node) {
 		struct device_node *child;
 		u32 reg;
 
-		for_each_child_of_node(mux_dev->of_node, child) {
+		for_each_child_of_node(muxc->dev->of_node, child) {
 			ret = of_property_read_u32(child, "reg", &reg);
 			if (ret)
 				continue;
@@ -215,8 +212,9 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	/*
 	 * Associate the mux channel with an ACPI node.
 	 */
-	if (has_acpi_companion(mux_dev))
-		acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
+	if (has_acpi_companion(muxc->dev))
+		acpi_preset_companion(&priv->adap.dev,
+				      ACPI_COMPANION(muxc->dev),
 				      chan_id);
 
 	if (force_nr) {
@@ -233,12 +231,14 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 		return ret;
 	}
 
-	WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
-			       "can't create symlink to mux device\n");
+	WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj,
+			       "mux_device"),
+	     "can't create symlink to mux device\n");
 
 	snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
-	WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
-			       "can't create symlink for channel %u\n", chan_id);
+	WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
+			       symlink_name),
+	     "can't create symlink for channel %u\n", chan_id);
 	dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
 		 i2c_adapter_id(&priv->adap));
 
@@ -259,7 +259,7 @@ void i2c_del_mux_adapters(struct i2c_mux_core *muxc)
 
 		snprintf(symlink_name, sizeof(symlink_name),
 			 "channel-%u", priv->chan_id);
-		sysfs_remove_link(&priv->mux_dev->kobj, symlink_name);
+		sysfs_remove_link(&muxc->dev->kobj, symlink_name);
 
 		sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
 		i2c_del_adapter(adap);
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index e0558e8a0e74..c2bc18c7921f 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -204,7 +204,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	}
 
 	/* Actually add the mux adapter */
-	ret = i2c_add_mux_adapter(muxc, dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(muxc, 0, 0, 0);
 	if (ret) {
 		dev_err(dev, "Failed to add adapter\n");
 		i2c_put_adapter(muxc->parent);
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 6bd41ace81d4..e800c4597fa4 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -216,8 +216,7 @@ 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;
 
-		ret = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
-					  mux->data.values[i], class);
+		ret = i2c_add_mux_adapter(muxc, nr, mux->data.values[i], class);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto add_adapter_failed;
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 80de0a0977a5..0e18d25334b5 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -361,7 +361,7 @@ static int pca9541_probe(struct i2c_client *client,
 	force = 0;
 	if (pdata)
 		force = pdata->modes[0].adap_id;
-	ret = i2c_add_mux_adapter(muxc, &client->dev, force, 0, 0);
+	ret = i2c_add_mux_adapter(muxc, force, 0, 0);
 	if (ret) {
 		dev_err(&client->dev, "failed to register master selector\n");
 		return ret;
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 640670b604f5..2d15325b6282 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -256,8 +256,7 @@ static int pca954x_probe(struct i2c_client *client,
 					   || idle_disconnect_dt) << num;
 		}
 
-		ret = i2c_add_mux_adapter(muxc, &client->dev,
-					  force, num, class);
+		ret = i2c_add_mux_adapter(muxc, force, num, class);
 
 		if (ret) {
 			dev_err(&client->dev,
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 3bbb3fb1d693..0dc912898813 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -212,8 +212,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 		u32 bus = mux->pdata->base_bus_num ?
 				(mux->pdata->base_bus_num + i) : 0;
 
-		ret = i2c_add_mux_adapter(muxc, &pdev->dev,
-					  bus, i, 0);
+		ret = i2c_add_mux_adapter(muxc, bus, i, 0);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto err_del_adapter;
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 5c004ff5b6ad..3c919e49260c 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -227,8 +227,7 @@ 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;
 
-		ret = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
-					  mux->data.values[i], class);
+		ret = i2c_add_mux_adapter(muxc, nr, mux->data.values[i], class);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto add_adapter_failed;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index a9a163c1c22c..5cd3c48682e6 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -850,7 +850,7 @@ static int inv_mpu_probe(struct i2c_client *client,
 	st->muxc->select = inv_mpu6050_select_bypass;
 	st->muxc->deselect = inv_mpu6050_deselect_bypass;
 
-	result = i2c_add_mux_adapter(st->muxc, &client->dev, 0, 0, 0);
+	result = i2c_add_mux_adapter(st->muxc, 0, 0, 0);
 	if (result)
 		goto out_unreg_device;
 
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index deab5cdba01f..45ad3ef82b4f 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1476,7 +1476,7 @@ static int m88ds3103_probe(struct i2c_client *client,
 	dev->muxc->select = m88ds3103_select;
 
 	/* create mux i2c adapter for tuner */
-	ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_kfree;
 
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index 9864740722dd..1da8d2e22983 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -874,7 +874,7 @@ static int rtl2830_probe(struct i2c_client *client,
 	dev->muxc->select = rtl2830_select;
 
 	/* create muxed i2c adapter for tuner */
-	ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_regmap_exit;
 
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 99d8dbf66fd7..c586150623f7 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1271,7 +1271,7 @@ static int rtl2832_probe(struct i2c_client *client,
 	dev->muxc->deselect = rtl2832_deselect;
 
 	/* create muxed i2c adapter for demod tuner bus */
-	ret = i2c_add_mux_adapter(dev->muxc, &i2c->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_regmap_exit;
 
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 06aa496cc42c..ae217b5e6618 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -719,7 +719,7 @@ static int si2168_probe(struct i2c_client *client,
 	dev->muxc->deselect = si2168_deselect;
 
 	/* create mux i2c adapter for tuner */
-	ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_kfree;
 
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 2b5adb056827..bfa63cf69235 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -577,12 +577,9 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
 
 int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
 {
-	/* what is the correct mux_dev? */
-	struct device *mux_dev = dev->dev;
 	int rc;
 
 	rc = i2c_add_mux_adapter(dev->muxc,
-				 mux_dev,
 				 0,
 				 mux_no /* chan_id */,
 				 0 /* class */);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 77ccc54cfdc9..46897ed4e396 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1722,7 +1722,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	if (ret)
 		return ret;
 	for (i = 0; i < nchans; i++) {
-		ret = i2c_add_mux_adapter(muxc, dev, 0, i, 0);
+		ret = i2c_add_mux_adapter(muxc, 0, i, 0);
 		if (ret) {
 			dev_err(dev, "Failed to register mux #%d\n", i);
 			i2c_del_mux_adapters(muxc);
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index bfcdcc46f2a6..d88e0a3b6768 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -56,7 +56,6 @@ int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters);
  * mux control.
  */
 int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-			struct device *mux_dev,
 			u32 force_nr, u32 chan_id,
 			unsigned int class);
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 4/8] i2c-mux: remove the mux dev pointer from the mux per channel data
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

The dev pointer is readily available in the mux core struct, no point in
keeping multiple copies around.

The patch also fixes a bug in rtl2832, which attached its mux slave
adapter to the device owning the mux parent adapter instead of
attaching it to its own device.

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 drivers/i2c/i2c-mux.c                      | 24 ++++++++++++------------
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c |  2 +-
 drivers/i2c/muxes/i2c-mux-gpio.c           |  3 +--
 drivers/i2c/muxes/i2c-mux-pca9541.c        |  2 +-
 drivers/i2c/muxes/i2c-mux-pca954x.c        |  3 +--
 drivers/i2c/muxes/i2c-mux-pinctrl.c        |  3 +--
 drivers/i2c/muxes/i2c-mux-reg.c            |  3 +--
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c |  2 +-
 drivers/media/dvb-frontends/m88ds3103.c    |  2 +-
 drivers/media/dvb-frontends/rtl2830.c      |  2 +-
 drivers/media/dvb-frontends/rtl2832.c      |  2 +-
 drivers/media/dvb-frontends/si2168.c       |  2 +-
 drivers/media/usb/cx231xx/cx231xx-i2c.c    |  3 ---
 drivers/of/unittest.c                      |  2 +-
 include/linux/i2c-mux.h                    |  1 -
 15 files changed, 24 insertions(+), 32 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 7ba0308537a8..5c1088079231 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -32,7 +32,6 @@ struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
 	struct i2c_mux_core *muxc;
-	struct device *mux_dev;
 	u32 chan_id;
 };
 
@@ -137,7 +136,6 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
 
 int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-			struct device *mux_dev,
 			u32 force_nr, u32 chan_id,
 			unsigned int class)
 {
@@ -162,7 +160,6 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 
 	/* Set up private adapter data */
 	priv->muxc = muxc;
-	priv->mux_dev = mux_dev;
 	priv->chan_id = chan_id;
 
 	/* Need to do algo dynamically because we don't know ahead
@@ -197,11 +194,11 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	 * Try to populate the mux adapter's of_node, expands to
 	 * nothing if !CONFIG_OF.
 	 */
-	if (mux_dev->of_node) {
+	if (muxc->dev->of_node) {
 		struct device_node *child;
 		u32 reg;
 
-		for_each_child_of_node(mux_dev->of_node, child) {
+		for_each_child_of_node(muxc->dev->of_node, child) {
 			ret = of_property_read_u32(child, "reg", &reg);
 			if (ret)
 				continue;
@@ -215,8 +212,9 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	/*
 	 * Associate the mux channel with an ACPI node.
 	 */
-	if (has_acpi_companion(mux_dev))
-		acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
+	if (has_acpi_companion(muxc->dev))
+		acpi_preset_companion(&priv->adap.dev,
+				      ACPI_COMPANION(muxc->dev),
 				      chan_id);
 
 	if (force_nr) {
@@ -233,12 +231,14 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 		return ret;
 	}
 
-	WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
-			       "can't create symlink to mux device\n");
+	WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj,
+			       "mux_device"),
+	     "can't create symlink to mux device\n");
 
 	snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
-	WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
-			       "can't create symlink for channel %u\n", chan_id);
+	WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
+			       symlink_name),
+	     "can't create symlink for channel %u\n", chan_id);
 	dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
 		 i2c_adapter_id(&priv->adap));
 
@@ -259,7 +259,7 @@ void i2c_del_mux_adapters(struct i2c_mux_core *muxc)
 
 		snprintf(symlink_name, sizeof(symlink_name),
 			 "channel-%u", priv->chan_id);
-		sysfs_remove_link(&priv->mux_dev->kobj, symlink_name);
+		sysfs_remove_link(&muxc->dev->kobj, symlink_name);
 
 		sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
 		i2c_del_adapter(adap);
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index e0558e8a0e74..c2bc18c7921f 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -204,7 +204,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	}
 
 	/* Actually add the mux adapter */
-	ret = i2c_add_mux_adapter(muxc, dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(muxc, 0, 0, 0);
 	if (ret) {
 		dev_err(dev, "Failed to add adapter\n");
 		i2c_put_adapter(muxc->parent);
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 6bd41ace81d4..e800c4597fa4 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -216,8 +216,7 @@ 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;
 
-		ret = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
-					  mux->data.values[i], class);
+		ret = i2c_add_mux_adapter(muxc, nr, mux->data.values[i], class);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto add_adapter_failed;
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 80de0a0977a5..0e18d25334b5 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -361,7 +361,7 @@ static int pca9541_probe(struct i2c_client *client,
 	force = 0;
 	if (pdata)
 		force = pdata->modes[0].adap_id;
-	ret = i2c_add_mux_adapter(muxc, &client->dev, force, 0, 0);
+	ret = i2c_add_mux_adapter(muxc, force, 0, 0);
 	if (ret) {
 		dev_err(&client->dev, "failed to register master selector\n");
 		return ret;
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 640670b604f5..2d15325b6282 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -256,8 +256,7 @@ static int pca954x_probe(struct i2c_client *client,
 					   || idle_disconnect_dt) << num;
 		}
 
-		ret = i2c_add_mux_adapter(muxc, &client->dev,
-					  force, num, class);
+		ret = i2c_add_mux_adapter(muxc, force, num, class);
 
 		if (ret) {
 			dev_err(&client->dev,
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 3bbb3fb1d693..0dc912898813 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -212,8 +212,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 		u32 bus = mux->pdata->base_bus_num ?
 				(mux->pdata->base_bus_num + i) : 0;
 
-		ret = i2c_add_mux_adapter(muxc, &pdev->dev,
-					  bus, i, 0);
+		ret = i2c_add_mux_adapter(muxc, bus, i, 0);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto err_del_adapter;
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 5c004ff5b6ad..3c919e49260c 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -227,8 +227,7 @@ 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;
 
-		ret = i2c_add_mux_adapter(muxc, &pdev->dev, nr,
-					  mux->data.values[i], class);
+		ret = i2c_add_mux_adapter(muxc, nr, mux->data.values[i], class);
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto add_adapter_failed;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index a9a163c1c22c..5cd3c48682e6 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -850,7 +850,7 @@ static int inv_mpu_probe(struct i2c_client *client,
 	st->muxc->select = inv_mpu6050_select_bypass;
 	st->muxc->deselect = inv_mpu6050_deselect_bypass;
 
-	result = i2c_add_mux_adapter(st->muxc, &client->dev, 0, 0, 0);
+	result = i2c_add_mux_adapter(st->muxc, 0, 0, 0);
 	if (result)
 		goto out_unreg_device;
 
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index deab5cdba01f..45ad3ef82b4f 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1476,7 +1476,7 @@ static int m88ds3103_probe(struct i2c_client *client,
 	dev->muxc->select = m88ds3103_select;
 
 	/* create mux i2c adapter for tuner */
-	ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_kfree;
 
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index 9864740722dd..1da8d2e22983 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -874,7 +874,7 @@ static int rtl2830_probe(struct i2c_client *client,
 	dev->muxc->select = rtl2830_select;
 
 	/* create muxed i2c adapter for tuner */
-	ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_regmap_exit;
 
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 99d8dbf66fd7..c586150623f7 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -1271,7 +1271,7 @@ static int rtl2832_probe(struct i2c_client *client,
 	dev->muxc->deselect = rtl2832_deselect;
 
 	/* create muxed i2c adapter for demod tuner bus */
-	ret = i2c_add_mux_adapter(dev->muxc, &i2c->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_regmap_exit;
 
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 06aa496cc42c..ae217b5e6618 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -719,7 +719,7 @@ static int si2168_probe(struct i2c_client *client,
 	dev->muxc->deselect = si2168_deselect;
 
 	/* create mux i2c adapter for tuner */
-	ret = i2c_add_mux_adapter(dev->muxc, &client->dev, 0, 0, 0);
+	ret = i2c_add_mux_adapter(dev->muxc, 0, 0, 0);
 	if (ret)
 		goto err_kfree;
 
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 2b5adb056827..bfa63cf69235 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -577,12 +577,9 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
 
 int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
 {
-	/* what is the correct mux_dev? */
-	struct device *mux_dev = dev->dev;
 	int rc;
 
 	rc = i2c_add_mux_adapter(dev->muxc,
-				 mux_dev,
 				 0,
 				 mux_no /* chan_id */,
 				 0 /* class */);
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 77ccc54cfdc9..46897ed4e396 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1722,7 +1722,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
 	if (ret)
 		return ret;
 	for (i = 0; i < nchans; i++) {
-		ret = i2c_add_mux_adapter(muxc, dev, 0, i, 0);
+		ret = i2c_add_mux_adapter(muxc, 0, i, 0);
 		if (ret) {
 			dev_err(dev, "Failed to register mux #%d\n", i);
 			i2c_del_mux_adapters(muxc);
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index bfcdcc46f2a6..d88e0a3b6768 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -56,7 +56,6 @@ int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters);
  * mux control.
  */
 int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-			struct device *mux_dev,
 			u32 force_nr, u32 chan_id,
 			unsigned int class);
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 5/8] i2c-mux: pinctrl: get rid of the driver private struct device pointer
  2016-01-05 15:57 ` Peter Rosin
@ 2016-01-05 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

There is a copy of the device pointer in the mux core.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/muxes/i2c-mux-pinctrl.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 0dc912898813..38129850cbe4 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -26,7 +26,6 @@
 #include <linux/of.h>
 
 struct i2c_mux_pinctrl {
-	struct device *dev;
 	struct i2c_mux_pinctrl_platform_data *pdata;
 	struct pinctrl *pinctrl;
 	struct pinctrl_state **states;
@@ -51,6 +50,7 @@ static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
 static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 				struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 	struct device_node *np = pdev->dev.of_node;
 	int num_names, i, ret;
 	struct device_node *adapter_np;
@@ -60,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		return 0;
 
 	mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
-	if (!mux->pdata) {
-		dev_err(mux->dev,
-			"Cannot allocate i2c_mux_pinctrl_platform_data\n");
+	if (!mux->pdata)
 		return -ENOMEM;
-	}
 
 	num_names = of_property_count_strings(np, "pinctrl-names");
 	if (num_names < 0) {
-		dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+		dev_err(muxc->dev, "Cannot parse pinctrl-names: %d\n",
 			num_names);
 		return num_names;
 	}
@@ -76,23 +73,21 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 	mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
 		sizeof(*mux->pdata->pinctrl_states) * num_names,
 		GFP_KERNEL);
-	if (!mux->pdata->pinctrl_states) {
-		dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
+	if (!mux->pdata->pinctrl_states)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < num_names; i++) {
 		ret = of_property_read_string_index(np, "pinctrl-names", i,
 			&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
 		if (ret < 0) {
-			dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+			dev_err(muxc->dev, "Cannot parse pinctrl-names: %d\n",
 				ret);
 			return ret;
 		}
 		if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
 			    "idle")) {
 			if (i != num_names - 1) {
-				dev_err(mux->dev, "idle state must be last\n");
+				dev_err(muxc->dev, "idle state must be last\n");
 				return -EINVAL;
 			}
 			mux->pdata->pinctrl_state_idle = "idle";
@@ -103,13 +98,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
-		dev_err(mux->dev, "Cannot parse i2c-parent\n");
+		dev_err(muxc->dev, "Cannot parse i2c-parent\n");
 		return -ENODEV;
 	}
 	adapter = of_find_i2c_adapter_by_node(adapter_np);
 	of_node_put(adapter_np);
 	if (!adapter) {
-		dev_err(mux->dev, "Cannot find parent bus\n");
+		dev_err(muxc->dev, "Cannot find parent bus\n");
 		return -EPROBE_DEFER;
 	}
 	mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
@@ -139,8 +134,6 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 	mux = i2c_mux_priv(muxc);
 	platform_set_drvdata(pdev, muxc);
 
-	mux->dev = &pdev->dev;
-
 	mux->pdata = dev_get_platdata(&pdev->dev);
 	if (!mux->pdata) {
 		ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 5/8] i2c-mux: pinctrl: get rid of the driver private struct device pointer
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda@axentia.se>

There is a copy of the device pointer in the mux core.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/muxes/i2c-mux-pinctrl.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 0dc912898813..38129850cbe4 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -26,7 +26,6 @@
 #include <linux/of.h>
 
 struct i2c_mux_pinctrl {
-	struct device *dev;
 	struct i2c_mux_pinctrl_platform_data *pdata;
 	struct pinctrl *pinctrl;
 	struct pinctrl_state **states;
@@ -51,6 +50,7 @@ static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
 static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 				struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 	struct device_node *np = pdev->dev.of_node;
 	int num_names, i, ret;
 	struct device_node *adapter_np;
@@ -60,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		return 0;
 
 	mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
-	if (!mux->pdata) {
-		dev_err(mux->dev,
-			"Cannot allocate i2c_mux_pinctrl_platform_data\n");
+	if (!mux->pdata)
 		return -ENOMEM;
-	}
 
 	num_names = of_property_count_strings(np, "pinctrl-names");
 	if (num_names < 0) {
-		dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+		dev_err(muxc->dev, "Cannot parse pinctrl-names: %d\n",
 			num_names);
 		return num_names;
 	}
@@ -76,23 +73,21 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 	mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
 		sizeof(*mux->pdata->pinctrl_states) * num_names,
 		GFP_KERNEL);
-	if (!mux->pdata->pinctrl_states) {
-		dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
+	if (!mux->pdata->pinctrl_states)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < num_names; i++) {
 		ret = of_property_read_string_index(np, "pinctrl-names", i,
 			&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
 		if (ret < 0) {
-			dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+			dev_err(muxc->dev, "Cannot parse pinctrl-names: %d\n",
 				ret);
 			return ret;
 		}
 		if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
 			    "idle")) {
 			if (i != num_names - 1) {
-				dev_err(mux->dev, "idle state must be last\n");
+				dev_err(muxc->dev, "idle state must be last\n");
 				return -EINVAL;
 			}
 			mux->pdata->pinctrl_state_idle = "idle";
@@ -103,13 +98,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
-		dev_err(mux->dev, "Cannot parse i2c-parent\n");
+		dev_err(muxc->dev, "Cannot parse i2c-parent\n");
 		return -ENODEV;
 	}
 	adapter = of_find_i2c_adapter_by_node(adapter_np);
 	of_node_put(adapter_np);
 	if (!adapter) {
-		dev_err(mux->dev, "Cannot find parent bus\n");
+		dev_err(muxc->dev, "Cannot find parent bus\n");
 		return -EPROBE_DEFER;
 	}
 	mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
@@ -139,8 +134,6 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 	mux = i2c_mux_priv(muxc);
 	platform_set_drvdata(pdev, muxc);
 
-	mux->dev = &pdev->dev;
-
 	mux->pdata = dev_get_platdata(&pdev->dev);
 	if (!mux->pdata) {
 		ret = i2c_mux_pinctrl_parse_dt(mux, pdev);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 6/8] i2c: allow adapter drivers to override the adapter locking
  2016-01-05 15:57 ` Peter Rosin
@ 2016-01-05 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

Add i2c_lock_bus() and i2c_unlock_bus(), which call the new lock_bus and
unlock_bus ops in the adapter. These funcs/ops take an additional flags
argument that indicates for what purpose the adapter is locked.

There are two flags, I2C_LOCK_ADAPTER and I2C_LOCK_SEGMENT, but they are
both implemented the same. For now. Locking the adapter means that the
whole bus is locked, locking the segment means that only the current bus
segment is locked (i.e. i2c traffic on the parent side of mux is still
allowed even if the child side of the mux is locked.

Also support a trylock_bus op (but no function to call it, as it is not
expected to be needed outside of the i2c core).

Implement i2c_lock_adapter/i2c_unlock_adapter in terms of the new locking
scheme (i.e. lock with the I2C_LOCK_ADAPTER flag).

Annotate some of the locking with explicit I2C_LOCK_SEGMENT flags.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-core.c | 40 ++++++++++++++++++++++------------------
 include/linux/i2c.h    | 28 ++++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index ba8eb087f224..34a7748b4652 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -958,10 +958,10 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
 }
 
 /**
- * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
  */
-void i2c_lock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 
@@ -970,27 +970,26 @@ void i2c_lock_adapter(struct i2c_adapter *adapter)
 	else
 		rt_mutex_lock(&adapter->bus_lock);
 }
-EXPORT_SYMBOL_GPL(i2c_lock_adapter);
 
 /**
- * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
  */
-static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 
 	if (parent)
-		return i2c_trylock_adapter(parent);
+		return parent->trylock_bus(parent, flags);
 	else
 		return rt_mutex_trylock(&adapter->bus_lock);
 }
 
 /**
- * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
  */
-void i2c_unlock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 
@@ -999,7 +998,6 @@ void i2c_unlock_adapter(struct i2c_adapter *adapter)
 	else
 		rt_mutex_unlock(&adapter->bus_lock);
 }
-EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
 
 static void i2c_dev_set_name(struct i2c_adapter *adap,
 			     struct i2c_client *client)
@@ -1545,6 +1543,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 		return -EINVAL;
 	}
 
+	if (!adap->lock_bus) {
+		adap->lock_bus = i2c_adapter_lock_bus;
+		adap->trylock_bus = i2c_adapter_trylock_bus;
+		adap->unlock_bus = i2c_adapter_unlock_bus;
+	}
+
 	rt_mutex_init(&adap->bus_lock);
 	mutex_init(&adap->userspace_clients_lock);
 	INIT_LIST_HEAD(&adap->userspace_clients);
@@ -2254,16 +2258,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 #endif
 
 		if (in_atomic() || irqs_disabled()) {
-			ret = i2c_trylock_adapter(adap);
+			ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
 			if (!ret)
 				/* I2C activity is ongoing. */
 				return -EAGAIN;
 		} else {
-			i2c_lock_adapter(adap);
+			i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
 		}
 
 		ret = __i2c_transfer(adap, msgs, num);
-		i2c_unlock_adapter(adap);
+		i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
 
 		return ret;
 	} else {
@@ -3038,7 +3042,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
 	flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
 
 	if (adapter->algo->smbus_xfer) {
-		i2c_lock_adapter(adapter);
+		i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
 
 		/* Retry automatically on arbitration loss */
 		orig_jiffies = jiffies;
@@ -3052,7 +3056,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
 				       orig_jiffies + adapter->timeout))
 				break;
 		}
-		i2c_unlock_adapter(adapter);
+		i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
 
 		if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
 			goto trace;
@@ -3163,9 +3167,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
 
 	client->slave_cb = slave_cb;
 
-	i2c_lock_adapter(client->adapter);
+	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
 	ret = client->adapter->algo->reg_slave(client);
-	i2c_unlock_adapter(client->adapter);
+	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
 
 	if (ret) {
 		client->slave_cb = NULL;
@@ -3185,9 +3189,9 @@ int i2c_slave_unregister(struct i2c_client *client)
 		return -EOPNOTSUPP;
 	}
 
-	i2c_lock_adapter(client->adapter);
+	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
 	ret = client->adapter->algo->unreg_slave(client);
-	i2c_unlock_adapter(client->adapter);
+	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
 
 	if (ret == 0)
 		client->slave_cb = NULL;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 768063baafbf..8040b48aef75 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -520,6 +520,10 @@ struct i2c_adapter {
 
 	struct i2c_bus_recovery_info *bus_recovery_info;
 	const struct i2c_adapter_quirks *quirks;
+
+	void (*lock_bus)(struct i2c_adapter *, int flags);
+	int (*trylock_bus)(struct i2c_adapter *, int flags);
+	void (*unlock_bus)(struct i2c_adapter *, int flags);
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
@@ -549,8 +553,28 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
 int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
 
 /* Adapter locking functions, exported for shared pin cases */
-void i2c_lock_adapter(struct i2c_adapter *);
-void i2c_unlock_adapter(struct i2c_adapter *);
+#define I2C_LOCK_ADAPTER 0x01
+#define I2C_LOCK_SEGMENT 0x02
+static inline void
+i2c_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+	adapter->lock_bus(adapter, flags);
+}
+static inline void
+i2c_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+	adapter->unlock_bus(adapter, flags);
+}
+static inline void
+i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+	i2c_lock_bus(adapter, I2C_LOCK_ADAPTER);
+}
+static inline void
+i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+	i2c_unlock_bus(adapter, I2C_LOCK_ADAPTER);
+}
 
 /*flags for the client struct: */
 #define I2C_CLIENT_PEC		0x04	/* Use Packet Error Checking */
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 6/8] i2c: allow adapter drivers to override the adapter locking
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda@axentia.se>

Add i2c_lock_bus() and i2c_unlock_bus(), which call the new lock_bus and
unlock_bus ops in the adapter. These funcs/ops take an additional flags
argument that indicates for what purpose the adapter is locked.

There are two flags, I2C_LOCK_ADAPTER and I2C_LOCK_SEGMENT, but they are
both implemented the same. For now. Locking the adapter means that the
whole bus is locked, locking the segment means that only the current bus
segment is locked (i.e. i2c traffic on the parent side of mux is still
allowed even if the child side of the mux is locked.

Also support a trylock_bus op (but no function to call it, as it is not
expected to be needed outside of the i2c core).

Implement i2c_lock_adapter/i2c_unlock_adapter in terms of the new locking
scheme (i.e. lock with the I2C_LOCK_ADAPTER flag).

Annotate some of the locking with explicit I2C_LOCK_SEGMENT flags.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-core.c | 40 ++++++++++++++++++++++------------------
 include/linux/i2c.h    | 28 ++++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index ba8eb087f224..34a7748b4652 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -958,10 +958,10 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
 }
 
 /**
- * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
  */
-void i2c_lock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 
@@ -970,27 +970,26 @@ void i2c_lock_adapter(struct i2c_adapter *adapter)
 	else
 		rt_mutex_lock(&adapter->bus_lock);
 }
-EXPORT_SYMBOL_GPL(i2c_lock_adapter);
 
 /**
- * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
  */
-static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 
 	if (parent)
-		return i2c_trylock_adapter(parent);
+		return parent->trylock_bus(parent, flags);
 	else
 		return rt_mutex_trylock(&adapter->bus_lock);
 }
 
 /**
- * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
  */
-void i2c_unlock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 
@@ -999,7 +998,6 @@ void i2c_unlock_adapter(struct i2c_adapter *adapter)
 	else
 		rt_mutex_unlock(&adapter->bus_lock);
 }
-EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
 
 static void i2c_dev_set_name(struct i2c_adapter *adap,
 			     struct i2c_client *client)
@@ -1545,6 +1543,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 		return -EINVAL;
 	}
 
+	if (!adap->lock_bus) {
+		adap->lock_bus = i2c_adapter_lock_bus;
+		adap->trylock_bus = i2c_adapter_trylock_bus;
+		adap->unlock_bus = i2c_adapter_unlock_bus;
+	}
+
 	rt_mutex_init(&adap->bus_lock);
 	mutex_init(&adap->userspace_clients_lock);
 	INIT_LIST_HEAD(&adap->userspace_clients);
@@ -2254,16 +2258,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 #endif
 
 		if (in_atomic() || irqs_disabled()) {
-			ret = i2c_trylock_adapter(adap);
+			ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
 			if (!ret)
 				/* I2C activity is ongoing. */
 				return -EAGAIN;
 		} else {
-			i2c_lock_adapter(adap);
+			i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
 		}
 
 		ret = __i2c_transfer(adap, msgs, num);
-		i2c_unlock_adapter(adap);
+		i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
 
 		return ret;
 	} else {
@@ -3038,7 +3042,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
 	flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
 
 	if (adapter->algo->smbus_xfer) {
-		i2c_lock_adapter(adapter);
+		i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
 
 		/* Retry automatically on arbitration loss */
 		orig_jiffies = jiffies;
@@ -3052,7 +3056,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
 				       orig_jiffies + adapter->timeout))
 				break;
 		}
-		i2c_unlock_adapter(adapter);
+		i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
 
 		if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
 			goto trace;
@@ -3163,9 +3167,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
 
 	client->slave_cb = slave_cb;
 
-	i2c_lock_adapter(client->adapter);
+	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
 	ret = client->adapter->algo->reg_slave(client);
-	i2c_unlock_adapter(client->adapter);
+	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
 
 	if (ret) {
 		client->slave_cb = NULL;
@@ -3185,9 +3189,9 @@ int i2c_slave_unregister(struct i2c_client *client)
 		return -EOPNOTSUPP;
 	}
 
-	i2c_lock_adapter(client->adapter);
+	i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
 	ret = client->adapter->algo->unreg_slave(client);
-	i2c_unlock_adapter(client->adapter);
+	i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);
 
 	if (ret == 0)
 		client->slave_cb = NULL;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 768063baafbf..8040b48aef75 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -520,6 +520,10 @@ struct i2c_adapter {
 
 	struct i2c_bus_recovery_info *bus_recovery_info;
 	const struct i2c_adapter_quirks *quirks;
+
+	void (*lock_bus)(struct i2c_adapter *, int flags);
+	int (*trylock_bus)(struct i2c_adapter *, int flags);
+	void (*unlock_bus)(struct i2c_adapter *, int flags);
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
@@ -549,8 +553,28 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
 int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
 
 /* Adapter locking functions, exported for shared pin cases */
-void i2c_lock_adapter(struct i2c_adapter *);
-void i2c_unlock_adapter(struct i2c_adapter *);
+#define I2C_LOCK_ADAPTER 0x01
+#define I2C_LOCK_SEGMENT 0x02
+static inline void
+i2c_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+	adapter->lock_bus(adapter, flags);
+}
+static inline void
+i2c_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+	adapter->unlock_bus(adapter, flags);
+}
+static inline void
+i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+	i2c_lock_bus(adapter, I2C_LOCK_ADAPTER);
+}
+static inline void
+i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+	i2c_unlock_bus(adapter, I2C_LOCK_ADAPTER);
+}
 
 /*flags for the client struct: */
 #define I2C_CLIENT_PEC		0x04	/* Use Packet Error Checking */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 7/8] i2c: muxes always lock the parent adapter
  2016-01-05 15:57 ` Peter Rosin
@ 2016-01-05 15:57   ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

Instead of checking for i2c parent adapters for every lock/unlock, simply
override the locking for muxes to always lock/unlock the parent adapter
directly.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-core.c | 21 +++------------------
 drivers/i2c/i2c-mux.c  | 27 +++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 34a7748b4652..4683777f81ca 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -963,12 +963,7 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
  */
 static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		i2c_lock_adapter(parent);
-	else
-		rt_mutex_lock(&adapter->bus_lock);
+	rt_mutex_lock(&adapter->bus_lock);
 }
 
 /**
@@ -977,12 +972,7 @@ static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
  */
 static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		return parent->trylock_bus(parent, flags);
-	else
-		return rt_mutex_trylock(&adapter->bus_lock);
+	return rt_mutex_trylock(&adapter->bus_lock);
 }
 
 /**
@@ -991,12 +981,7 @@ static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
  */
 static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		i2c_unlock_adapter(parent);
-	else
-		rt_mutex_unlock(&adapter->bus_lock);
+	rt_mutex_unlock(&adapter->bus_lock);
 }
 
 static void i2c_dev_set_name(struct i2c_adapter *adap,
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 5c1088079231..dd8a790cb4cc 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -98,6 +98,30 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
+static void i2c_parent_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	parent->lock_bus(parent, flags);
+}
+
+static int i2c_parent_trylock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	return parent->trylock_bus(parent, flags);
+}
+
+static void i2c_parent_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	parent->unlock_bus(parent, flags);
+}
+
 int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
 {
 	struct i2c_adapter **adapter;
@@ -181,6 +205,9 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	priv->adap.retries = parent->retries;
 	priv->adap.timeout = parent->timeout;
 	priv->adap.quirks = parent->quirks;
+	priv->adap.lock_bus = i2c_parent_lock_bus;
+	priv->adap.trylock_bus = i2c_parent_trylock_bus;
+	priv->adap.unlock_bus = i2c_parent_unlock_bus;
 
 	/* Sanity check on class */
 	if (i2c_mux_parent_classes(parent) & class)
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 7/8] i2c: muxes always lock the parent adapter
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda@axentia.se>

Instead of checking for i2c parent adapters for every lock/unlock, simply
override the locking for muxes to always lock/unlock the parent adapter
directly.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/i2c-core.c | 21 +++------------------
 drivers/i2c/i2c-mux.c  | 27 +++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 34a7748b4652..4683777f81ca 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -963,12 +963,7 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
  */
 static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		i2c_lock_adapter(parent);
-	else
-		rt_mutex_lock(&adapter->bus_lock);
+	rt_mutex_lock(&adapter->bus_lock);
 }
 
 /**
@@ -977,12 +972,7 @@ static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
  */
 static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		return parent->trylock_bus(parent, flags);
-	else
-		return rt_mutex_trylock(&adapter->bus_lock);
+	return rt_mutex_trylock(&adapter->bus_lock);
 }
 
 /**
@@ -991,12 +981,7 @@ static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
  */
 static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		i2c_unlock_adapter(parent);
-	else
-		rt_mutex_unlock(&adapter->bus_lock);
+	rt_mutex_unlock(&adapter->bus_lock);
 }
 
 static void i2c_dev_set_name(struct i2c_adapter *adap,
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 5c1088079231..dd8a790cb4cc 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -98,6 +98,30 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
+static void i2c_parent_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	parent->lock_bus(parent, flags);
+}
+
+static int i2c_parent_trylock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	return parent->trylock_bus(parent, flags);
+}
+
+static void i2c_parent_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	parent->unlock_bus(parent, flags);
+}
+
 int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
 {
 	struct i2c_adapter **adapter;
@@ -181,6 +205,9 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	priv->adap.retries = parent->retries;
 	priv->adap.timeout = parent->timeout;
 	priv->adap.quirks = parent->quirks;
+	priv->adap.lock_bus = i2c_parent_lock_bus;
+	priv->adap.trylock_bus = i2c_parent_trylock_bus;
+	priv->adap.unlock_bus = i2c_parent_unlock_bus;
 
 	/* Sanity check on class */
 	if (i2c_mux_parent_classes(parent) & class)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, Peter Rosin, linux-i2c, devicetree, linux-kernel,
	linux-iio, linux-media

From: Peter Rosin <peda@axentia.se>

With a i2c topology like the following

                       GPIO ---|  ------ BAT1
                        |      v /
   I2C  -----+----------+---- MUX
             |                   \
           EEPROM                 ------ BAT2

there is a locking problem with the GPIO controller since it is a client
on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
will lock the whole i2c bus prior to attempting to switch the mux to the
correct i2c segment. In the above case, the GPIO device is an I/O expander
with an i2c interface, and since the GPIO subsystem knows nothing (and
rightfully so) about the lockless needs of the i2c mux code, this results
in a deadlock when the GPIO driver issues i2c transfers to modify the
mux.

So, observing that while it is needed to have the i2c bus locked during the
actual MUX update in order to avoid random garbage on the slave side, it
is not strictly a must to have it locked over the whole sequence of a full
select-transfer-deselect mux client operation. The mux itself needs to be
locked, so transfers to clients behind the mux are serialized, and the mux
needs to be stable during all i2c traffic (otherwise individual mux slave
segments might see garbage, or worse).

Add devive tree properties (bool named i2c-controlled) to i2c-mux-gpio and
i2c-mux-pinctrl that asserts that the the gpio/pinctrl is controlled via
the same i2c bus that it muxes.

Modify the i2c mux locking so that muxes that are "i2c-controlled" locks
the mux instead of the whole i2c bus when there is a transfer to the slave
side of the mux. This lock serializes transfers to the slave side of the
mux.

Modify the select-transfer-deselect code for "i2c-controlled" muxes so
that each of the select-transfer-deselect ops locks the mux parent
adapter individually.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
 .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
 drivers/i2c/i2c-mux.c                              | 109 +++++++++++++++++++--
 drivers/i2c/muxes/i2c-mux-gpio.c                   |   3 +
 drivers/i2c/muxes/i2c-mux-pinctrl.c                |   3 +
 include/linux/i2c-mux-gpio.h                       |   2 +
 include/linux/i2c-mux-pinctrl.h                    |   2 +
 include/linux/i2c-mux.h                            |   2 +
 8 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
index 66709a825541..17670b997d81 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
@@ -28,6 +28,8 @@ Required properties:
 Optional properties:
 - idle-state: value to set the muxer to when idle. When no value is
   given, it defaults to the last value used.
+- i2c-controlled: The muxed I2C bus is also used to control all the gpios
+  used for muxing.
 
 For each i2c child node, an I2C child bus will be created. They will
 be numbered based on their order in the device tree.
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
index ae8af1694e95..8374a1f7a709 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
@@ -23,6 +23,10 @@ Required properties:
 - i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
   port is connected to.
 
+Optional properties:
+- i2c-controlled: The muxed I2C bus is also used to control all the pinctrl
+  pins used for muxing.
+
 Also required are:
 
 * Standard pinctrl properties that specify the pin mux state for each child
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index dd8a790cb4cc..c4d4b14a5399 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -54,6 +54,25 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 	return ret;
 }
 
+static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
+				 struct i2c_msg msgs[], int num)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	/* Switch to the right mux port and perform the transfer. */
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret >= 0)
+		ret = i2c_transfer(parent, msgs, num);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
 static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 			      u16 addr, unsigned short flags,
 			      char read_write, u8 command,
@@ -76,6 +95,28 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 	return ret;
 }
 
+static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+				u16 addr, unsigned short flags,
+				char read_write, u8 command,
+				int size, union i2c_smbus_data *data)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	/* Select the right mux port and perform the transfer. */
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret >= 0)
+		ret = i2c_smbus_xfer(parent, addr, flags,
+				     read_write, command, size, data);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
 /* Return the parent's functionality */
 static u32 i2c_mux_functionality(struct i2c_adapter *adap)
 {
@@ -98,6 +139,45 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
+static void i2c_mux_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+
+	rt_mutex_lock(&muxc->bus_lock);
+	if (!(flags & I2C_LOCK_ADAPTER))
+		return;
+	i2c_lock_bus(parent, flags);
+}
+
+static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+
+	if (!rt_mutex_trylock(&muxc->bus_lock))
+		return 0;
+	if (!(flags & I2C_LOCK_ADAPTER))
+		return 1;
+	if (parent->trylock_bus(parent, flags))
+		return 1;
+	rt_mutex_unlock(&muxc->bus_lock);
+	return 0;
+}
+
+static void i2c_mux_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+
+	if (flags & I2C_LOCK_ADAPTER)
+		i2c_unlock_bus(parent, flags);
+	rt_mutex_unlock(&muxc->bus_lock);
+}
+
 static void i2c_parent_lock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_mux_priv *priv = adapter->algo_data;
@@ -155,6 +235,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 	if (sizeof_priv)
 		muxc->priv = muxc + 1;
 	muxc->dev = dev;
+	rt_mutex_init(&muxc->bus_lock);
 	return muxc;
 }
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
@@ -189,10 +270,18 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	/* Need to do algo dynamically because we don't know ahead
 	 * of time what sort of physical adapter we'll be dealing with.
 	 */
-	if (parent->algo->master_xfer)
-		priv->algo.master_xfer = i2c_mux_master_xfer;
-	if (parent->algo->smbus_xfer)
-		priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	if (parent->algo->master_xfer) {
+		if (muxc->i2c_controlled)
+			priv->algo.master_xfer = __i2c_mux_master_xfer;
+		else
+			priv->algo.master_xfer = i2c_mux_master_xfer;
+	}
+	if (parent->algo->smbus_xfer) {
+		if (muxc->i2c_controlled)
+			priv->algo.smbus_xfer = __i2c_mux_smbus_xfer;
+		else
+			priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	}
 	priv->algo.functionality = i2c_mux_functionality;
 
 	/* Now fill out new adapter structure */
@@ -205,9 +294,15 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	priv->adap.retries = parent->retries;
 	priv->adap.timeout = parent->timeout;
 	priv->adap.quirks = parent->quirks;
-	priv->adap.lock_bus = i2c_parent_lock_bus;
-	priv->adap.trylock_bus = i2c_parent_trylock_bus;
-	priv->adap.unlock_bus = i2c_parent_unlock_bus;
+	if (muxc->i2c_controlled) {
+		priv->adap.lock_bus = i2c_mux_lock_bus;
+		priv->adap.trylock_bus = i2c_mux_trylock_bus;
+		priv->adap.unlock_bus = i2c_mux_unlock_bus;
+	} else {
+		priv->adap.lock_bus = i2c_parent_lock_bus;
+		priv->adap.trylock_bus = i2c_parent_trylock_bus;
+		priv->adap.unlock_bus = i2c_parent_unlock_bus;
+	}
 
 	/* Sanity check on class */
 	if (i2c_mux_parent_classes(parent) & class)
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index e800c4597fa4..115321b689f9 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -68,6 +68,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 	if (!np)
 		return -ENODEV;
 
+	mux->data.i2c_controlled = of_property_read_bool(np,
+							 "i2c-controlled");
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
 		dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
@@ -177,6 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	if (!parent)
 		return -EPROBE_DEFER;
 
+	muxc->i2c_controlled = mux->data.i2c_controlled;
 	muxc->parent = parent;
 	muxc->select = i2c_mux_gpio_select;
 	mux->gpio_base = gpio_base;
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 38129850cbe4..753355798ea8 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -96,6 +96,8 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		}
 	}
 
+	mux->pdata->i2c_controlled = of_property_read_bool(np,
+							   "i2c-controlled");
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
 		dev_err(muxc->dev, "Cannot parse i2c-parent\n");
@@ -193,6 +195,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 	}
 	muxc->select = i2c_mux_pinctrl_select;
 
+	muxc->i2c_controlled = mux->pdata->i2c_controlled;
 	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
 	if (!muxc->parent) {
 		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
diff --git a/include/linux/i2c-mux-gpio.h b/include/linux/i2c-mux-gpio.h
index 4406108201fe..8fb19380bb03 100644
--- a/include/linux/i2c-mux-gpio.h
+++ b/include/linux/i2c-mux-gpio.h
@@ -27,6 +27,7 @@
  * @gpios: Array of GPIO numbers used to control MUX
  * @n_gpios: Number of GPIOs used to control MUX
  * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
+ * @i2c_controlled: Set if the parent i2c bus is used to control the gpio.
  */
 struct i2c_mux_gpio_platform_data {
 	int parent;
@@ -38,6 +39,7 @@ struct i2c_mux_gpio_platform_data {
 	const unsigned *gpios;
 	int n_gpios;
 	unsigned idle;
+	bool i2c_controlled;
 };
 
 #endif /* _LINUX_I2C_MUX_GPIO_H */
diff --git a/include/linux/i2c-mux-pinctrl.h b/include/linux/i2c-mux-pinctrl.h
index a65c86429e84..fb95cb7c45c5 100644
--- a/include/linux/i2c-mux-pinctrl.h
+++ b/include/linux/i2c-mux-pinctrl.h
@@ -29,6 +29,7 @@
  * @pinctrl_state_idle: The pinctrl state to select when no child bus is being
  *	accessed. If NULL, the most recently used pinctrl state will be left
  *	selected.
+ * @i2c_controlled: Set if the parent i2c bus is used to control the pinctrl.
  */
 struct i2c_mux_pinctrl_platform_data {
 	int parent_bus_num;
@@ -36,6 +37,7 @@ struct i2c_mux_pinctrl_platform_data {
 	int bus_count;
 	const char **pinctrl_states;
 	const char *pinctrl_state_idle;
+	bool i2c_controlled;
 };
 
 #endif
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index d88e0a3b6768..b73d14c45121 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -33,6 +33,8 @@ struct i2c_mux_core {
 	int adapters;
 	int max_adapters;
 	struct device *dev;
+	struct rt_mutex bus_lock;
+	bool i2c_controlled;
 
 	void *priv;
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
@ 2016-01-05 15:57   ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 15:57 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen

From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>

With a i2c topology like the following

                       GPIO ---|  ------ BAT1
                        |      v /
   I2C  -----+----------+---- MUX
             |                   \
           EEPROM                 ------ BAT2

there is a locking problem with the GPIO controller since it is a client
on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
will lock the whole i2c bus prior to attempting to switch the mux to the
correct i2c segment. In the above case, the GPIO device is an I/O expander
with an i2c interface, and since the GPIO subsystem knows nothing (and
rightfully so) about the lockless needs of the i2c mux code, this results
in a deadlock when the GPIO driver issues i2c transfers to modify the
mux.

So, observing that while it is needed to have the i2c bus locked during the
actual MUX update in order to avoid random garbage on the slave side, it
is not strictly a must to have it locked over the whole sequence of a full
select-transfer-deselect mux client operation. The mux itself needs to be
locked, so transfers to clients behind the mux are serialized, and the mux
needs to be stable during all i2c traffic (otherwise individual mux slave
segments might see garbage, or worse).

Add devive tree properties (bool named i2c-controlled) to i2c-mux-gpio and
i2c-mux-pinctrl that asserts that the the gpio/pinctrl is controlled via
the same i2c bus that it muxes.

Modify the i2c mux locking so that muxes that are "i2c-controlled" locks
the mux instead of the whole i2c bus when there is a transfer to the slave
side of the mux. This lock serializes transfers to the slave side of the
mux.

Modify the select-transfer-deselect code for "i2c-controlled" muxes so
that each of the select-transfer-deselect ops locks the mux parent
adapter individually.

Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
---
 .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
 .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
 drivers/i2c/i2c-mux.c                              | 109 +++++++++++++++++++--
 drivers/i2c/muxes/i2c-mux-gpio.c                   |   3 +
 drivers/i2c/muxes/i2c-mux-pinctrl.c                |   3 +
 include/linux/i2c-mux-gpio.h                       |   2 +
 include/linux/i2c-mux-pinctrl.h                    |   2 +
 include/linux/i2c-mux.h                            |   2 +
 8 files changed, 120 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
index 66709a825541..17670b997d81 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
@@ -28,6 +28,8 @@ Required properties:
 Optional properties:
 - idle-state: value to set the muxer to when idle. When no value is
   given, it defaults to the last value used.
+- i2c-controlled: The muxed I2C bus is also used to control all the gpios
+  used for muxing.
 
 For each i2c child node, an I2C child bus will be created. They will
 be numbered based on their order in the device tree.
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
index ae8af1694e95..8374a1f7a709 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
@@ -23,6 +23,10 @@ Required properties:
 - i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
   port is connected to.
 
+Optional properties:
+- i2c-controlled: The muxed I2C bus is also used to control all the pinctrl
+  pins used for muxing.
+
 Also required are:
 
 * Standard pinctrl properties that specify the pin mux state for each child
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index dd8a790cb4cc..c4d4b14a5399 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -54,6 +54,25 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 	return ret;
 }
 
+static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
+				 struct i2c_msg msgs[], int num)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	/* Switch to the right mux port and perform the transfer. */
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret >= 0)
+		ret = i2c_transfer(parent, msgs, num);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
 static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 			      u16 addr, unsigned short flags,
 			      char read_write, u8 command,
@@ -76,6 +95,28 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 	return ret;
 }
 
+static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+				u16 addr, unsigned short flags,
+				char read_write, u8 command,
+				int size, union i2c_smbus_data *data)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	/* Select the right mux port and perform the transfer. */
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret >= 0)
+		ret = i2c_smbus_xfer(parent, addr, flags,
+				     read_write, command, size, data);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
 /* Return the parent's functionality */
 static u32 i2c_mux_functionality(struct i2c_adapter *adap)
 {
@@ -98,6 +139,45 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
+static void i2c_mux_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+
+	rt_mutex_lock(&muxc->bus_lock);
+	if (!(flags & I2C_LOCK_ADAPTER))
+		return;
+	i2c_lock_bus(parent, flags);
+}
+
+static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+
+	if (!rt_mutex_trylock(&muxc->bus_lock))
+		return 0;
+	if (!(flags & I2C_LOCK_ADAPTER))
+		return 1;
+	if (parent->trylock_bus(parent, flags))
+		return 1;
+	rt_mutex_unlock(&muxc->bus_lock);
+	return 0;
+}
+
+static void i2c_mux_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+
+	if (flags & I2C_LOCK_ADAPTER)
+		i2c_unlock_bus(parent, flags);
+	rt_mutex_unlock(&muxc->bus_lock);
+}
+
 static void i2c_parent_lock_bus(struct i2c_adapter *adapter, int flags)
 {
 	struct i2c_mux_priv *priv = adapter->algo_data;
@@ -155,6 +235,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 	if (sizeof_priv)
 		muxc->priv = muxc + 1;
 	muxc->dev = dev;
+	rt_mutex_init(&muxc->bus_lock);
 	return muxc;
 }
 EXPORT_SYMBOL_GPL(i2c_mux_alloc);
@@ -189,10 +270,18 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	/* Need to do algo dynamically because we don't know ahead
 	 * of time what sort of physical adapter we'll be dealing with.
 	 */
-	if (parent->algo->master_xfer)
-		priv->algo.master_xfer = i2c_mux_master_xfer;
-	if (parent->algo->smbus_xfer)
-		priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	if (parent->algo->master_xfer) {
+		if (muxc->i2c_controlled)
+			priv->algo.master_xfer = __i2c_mux_master_xfer;
+		else
+			priv->algo.master_xfer = i2c_mux_master_xfer;
+	}
+	if (parent->algo->smbus_xfer) {
+		if (muxc->i2c_controlled)
+			priv->algo.smbus_xfer = __i2c_mux_smbus_xfer;
+		else
+			priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	}
 	priv->algo.functionality = i2c_mux_functionality;
 
 	/* Now fill out new adapter structure */
@@ -205,9 +294,15 @@ int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
 	priv->adap.retries = parent->retries;
 	priv->adap.timeout = parent->timeout;
 	priv->adap.quirks = parent->quirks;
-	priv->adap.lock_bus = i2c_parent_lock_bus;
-	priv->adap.trylock_bus = i2c_parent_trylock_bus;
-	priv->adap.unlock_bus = i2c_parent_unlock_bus;
+	if (muxc->i2c_controlled) {
+		priv->adap.lock_bus = i2c_mux_lock_bus;
+		priv->adap.trylock_bus = i2c_mux_trylock_bus;
+		priv->adap.unlock_bus = i2c_mux_unlock_bus;
+	} else {
+		priv->adap.lock_bus = i2c_parent_lock_bus;
+		priv->adap.trylock_bus = i2c_parent_trylock_bus;
+		priv->adap.unlock_bus = i2c_parent_unlock_bus;
+	}
 
 	/* Sanity check on class */
 	if (i2c_mux_parent_classes(parent) & class)
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index e800c4597fa4..115321b689f9 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -68,6 +68,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 	if (!np)
 		return -ENODEV;
 
+	mux->data.i2c_controlled = of_property_read_bool(np,
+							 "i2c-controlled");
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
 		dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
@@ -177,6 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	if (!parent)
 		return -EPROBE_DEFER;
 
+	muxc->i2c_controlled = mux->data.i2c_controlled;
 	muxc->parent = parent;
 	muxc->select = i2c_mux_gpio_select;
 	mux->gpio_base = gpio_base;
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 38129850cbe4..753355798ea8 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -96,6 +96,8 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		}
 	}
 
+	mux->pdata->i2c_controlled = of_property_read_bool(np,
+							   "i2c-controlled");
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
 		dev_err(muxc->dev, "Cannot parse i2c-parent\n");
@@ -193,6 +195,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 	}
 	muxc->select = i2c_mux_pinctrl_select;
 
+	muxc->i2c_controlled = mux->pdata->i2c_controlled;
 	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
 	if (!muxc->parent) {
 		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
diff --git a/include/linux/i2c-mux-gpio.h b/include/linux/i2c-mux-gpio.h
index 4406108201fe..8fb19380bb03 100644
--- a/include/linux/i2c-mux-gpio.h
+++ b/include/linux/i2c-mux-gpio.h
@@ -27,6 +27,7 @@
  * @gpios: Array of GPIO numbers used to control MUX
  * @n_gpios: Number of GPIOs used to control MUX
  * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
+ * @i2c_controlled: Set if the parent i2c bus is used to control the gpio.
  */
 struct i2c_mux_gpio_platform_data {
 	int parent;
@@ -38,6 +39,7 @@ struct i2c_mux_gpio_platform_data {
 	const unsigned *gpios;
 	int n_gpios;
 	unsigned idle;
+	bool i2c_controlled;
 };
 
 #endif /* _LINUX_I2C_MUX_GPIO_H */
diff --git a/include/linux/i2c-mux-pinctrl.h b/include/linux/i2c-mux-pinctrl.h
index a65c86429e84..fb95cb7c45c5 100644
--- a/include/linux/i2c-mux-pinctrl.h
+++ b/include/linux/i2c-mux-pinctrl.h
@@ -29,6 +29,7 @@
  * @pinctrl_state_idle: The pinctrl state to select when no child bus is being
  *	accessed. If NULL, the most recently used pinctrl state will be left
  *	selected.
+ * @i2c_controlled: Set if the parent i2c bus is used to control the pinctrl.
  */
 struct i2c_mux_pinctrl_platform_data {
 	int parent_bus_num;
@@ -36,6 +37,7 @@ struct i2c_mux_pinctrl_platform_data {
 	int bus_count;
 	const char **pinctrl_states;
 	const char *pinctrl_state_idle;
+	bool i2c_controlled;
 };
 
 #endif
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index d88e0a3b6768..b73d14c45121 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -33,6 +33,8 @@ struct i2c_mux_core {
 	int adapters;
 	int max_adapters;
 	struct device *dev;
+	struct rt_mutex bus_lock;
+	bool i2c_controlled;
 
 	void *priv;
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-01-05 16:42     ` Guenter Roeck
  0 siblings, 0 replies; 52+ messages in thread
From: Guenter Roeck @ 2016-01-05 16:42 UTC (permalink / raw)
  To: Peter Rosin, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree,
	linux-kernel, linux-iio, linux-media

On 01/05/2016 07:57 AM, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
>
> The initial core mux structure starts off small with only the parent
> adapter pointer, which all muxes have, and a priv pointer for mux
> driver private data.
>
> Add i2c_mux_alloc function to unify the creation of a mux.
>
> Where appropriate, pass around the mux core structure instead of the
> parent adapter or the driver private data.
>
> Remove the parent adapter pointer from the driver private data for all
> mux drivers.
>
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>   drivers/i2c/i2c-mux.c                        | 28 +++++++++++++++++-----
>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 24 +++++++++----------
>   drivers/i2c/muxes/i2c-mux-gpio.c             | 20 ++++++++--------
>   drivers/i2c/muxes/i2c-mux-pca9541.c          | 35 ++++++++++++++--------------
>   drivers/i2c/muxes/i2c-mux-pca954x.c          | 19 ++++++++++-----
>   drivers/i2c/muxes/i2c-mux-pinctrl.c          | 23 +++++++++---------
>   drivers/i2c/muxes/i2c-mux-reg.c              | 23 ++++++++++--------
>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 10 +++++++-
>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 +
>   drivers/media/dvb-frontends/m88ds3103.c      | 10 +++++++-
>   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        | 10 +++++++-
>   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      | 13 +++++++++--
>   drivers/media/usb/cx231xx/cx231xx.h          |  2 ++
>   drivers/of/unittest.c                        | 16 +++++++------
>   include/linux/i2c-mux.h                      | 14 ++++++++++-
>   22 files changed, 187 insertions(+), 88 deletions(-)
>
> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
> index 00fc5b1c7b66..c2163f6b51d5 100644
> --- a/drivers/i2c/i2c-mux.c
> +++ b/drivers/i2c/i2c-mux.c
> @@ -31,8 +31,8 @@
>   struct i2c_mux_priv {
>   	struct i2c_adapter adap;
>   	struct i2c_algorithm algo;
> +	struct i2c_mux_core *muxc;
>
> -	struct i2c_adapter *parent;
>   	struct device *mux_dev;
>   	void *mux_priv;
>   	u32 chan_id;
> @@ -45,7 +45,8 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
>   			       struct i2c_msg msgs[], int num)
>   {
>   	struct i2c_mux_priv *priv = adap->algo_data;
> -	struct i2c_adapter *parent = priv->parent;
> +	struct i2c_mux_core *muxc = priv->muxc;
> +	struct i2c_adapter *parent = muxc->parent;
>   	int ret;
>
>   	/* Switch to the right mux port and perform the transfer. */
> @@ -65,7 +66,8 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>   			      int size, union i2c_smbus_data *data)
>   {
>   	struct i2c_mux_priv *priv = adap->algo_data;
> -	struct i2c_adapter *parent = priv->parent;
> +	struct i2c_mux_core *muxc = priv->muxc;
> +	struct i2c_adapter *parent = muxc->parent;
>   	int ret;
>
>   	/* Select the right mux port and perform the transfer. */
> @@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>   static u32 i2c_mux_functionality(struct i2c_adapter *adap)
>   {
>   	struct i2c_mux_priv *priv = adap->algo_data;
> -	struct i2c_adapter *parent = priv->parent;
> +	struct i2c_adapter *parent = priv->muxc->parent;
>
>   	return parent->algo->functionality(parent);
>   }
> @@ -102,7 +104,20 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
>   	return class;
>   }
>
> -struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
> +struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
> +{
> +	struct i2c_mux_core *muxc;
> +
> +	muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
> +	if (!muxc)
> +		return NULL;
> +	if (sizeof_priv)
> +		muxc->priv = muxc + 1;
> +	return muxc;
> +}
> +EXPORT_SYMBOL_GPL(i2c_mux_alloc);
> +
> +struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
>   				struct device *mux_dev,
>   				void *mux_priv, u32 force_nr, u32 chan_id,
>   				unsigned int class,
> @@ -111,6 +126,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>   				int (*deselect) (struct i2c_adapter *,
>   						 void *, u32))
>   {
> +	struct i2c_adapter *parent = muxc->parent;
>   	struct i2c_mux_priv *priv;
>   	char symlink_name[20];
>   	int ret;
> @@ -120,7 +136,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>   		return NULL;
>
>   	/* Set up private adapter data */
> -	priv->parent = parent;
> +	priv->muxc = muxc;
>   	priv->mux_dev = mux_dev;
>   	priv->mux_priv = mux_priv;
>   	priv->chan_id = chan_id;
> diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
> index 402e3a6c671a..6e27ea4fb25a 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 *parent;
>   	struct i2c_adapter *child;
>   	int our_gpio;
>   	int our_gpio_release;
> @@ -119,6 +118,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>   	struct device *dev = &pdev->dev;
>   	struct device_node *np = dev->of_node;
>   	struct device_node *parent_np;
> +	struct i2c_mux_core *muxc;
>   	struct i2c_arbitrator_data *arb;
>   	enum of_gpio_flags gpio_flags;
>   	unsigned long out_init;
> @@ -134,13 +134,12 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>   		return -EINVAL;
>   	}
>
> -	arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
> -	if (!arb) {
> -		dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
> +	muxc = i2c_mux_alloc(dev, sizeof(*arb));
> +	if (!muxc)
>   		return -ENOMEM;
> -	}
> -	platform_set_drvdata(pdev, arb);
> +	arb = i2c_mux_priv(muxc);
>
> +	platform_set_drvdata(pdev, muxc);
>   	/* Request GPIOs */
>   	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
>   	if (!gpio_is_valid(ret)) {
> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>   		dev_err(dev, "Cannot parse i2c-parent\n");
>   		return -EINVAL;
>   	}
> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>   	of_node_put(parent_np);
> -	if (!arb->parent) {
> +	if (!muxc->parent) {
>   		dev_err(dev, "Cannot find parent bus\n");
>   		return -EPROBE_DEFER;
>   	}
>
>   	/* Actually add the mux adapter */
> -	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
> +	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
>   					 i2c_arbitrator_select,
>   					 i2c_arbitrator_deselect);
>   	if (!arb->child) {
>   		dev_err(dev, "Failed to add adapter\n");
>   		ret = -ENODEV;
> -		i2c_put_adapter(arb->parent);
> +		i2c_put_adapter(muxc->parent);
>   	}
>
>   	return ret;
> @@ -218,10 +217,11 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>
>   static int i2c_arbitrator_remove(struct platform_device *pdev)
>   {
> -	struct i2c_arbitrator_data *arb = platform_get_drvdata(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_put_adapter(arb->parent);
> +	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 b8e11c16d98c..ee43dd76a4d7 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 *parent;
>   	struct i2c_adapter **adap; /* child busses */
>   	struct i2c_mux_gpio_platform_data data;
>   	unsigned gpio_base;
> @@ -136,19 +135,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
>
>   static int i2c_mux_gpio_probe(struct platform_device *pdev)
>   {
> +	struct i2c_mux_core *muxc;
>   	struct gpiomux *mux;
>   	struct i2c_adapter *parent;
>   	int (*deselect) (struct i2c_adapter *, void *, u32);
>   	unsigned initial_state, gpio_base;
>   	int i, ret;
>
> -	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
> -	if (!mux) {
> -		dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
> +	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
> +	if (!muxc)
>   		return -ENOMEM;
> -	}
> +	mux = i2c_mux_priv(muxc);
>
> -	platform_set_drvdata(pdev, mux);
> +	platform_set_drvdata(pdev, muxc);
>
>   	if (!dev_get_platdata(&pdev->dev)) {
>   		ret = i2c_mux_gpio_probe_dt(mux, pdev);
> @@ -180,7 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
>   	if (!parent)
>   		return -EPROBE_DEFER;
>
> -	mux->parent = parent;
> +	muxc->parent = parent;
>   	mux->gpio_base = gpio_base;
>
>   	mux->adap = devm_kzalloc(&pdev->dev,
> @@ -223,7 +222,7 @@ 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(parent, &pdev->dev, mux, nr,
> +		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux, nr,
>   						   mux->data.values[i], class,
>   						   i2c_mux_gpio_select, deselect);
>   		if (!mux->adap[i]) {
> @@ -253,7 +252,8 @@ alloc_failed:
>
>   static int i2c_mux_gpio_remove(struct platform_device *pdev)
>   {
> -	struct gpiomux *mux = platform_get_drvdata(pdev);
> +	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
> +	struct gpiomux *mux = i2c_mux_priv(muxc);
>   	int i;
>
>   	for (i = 0; i < mux->data.n_values; i++)
> @@ -262,7 +262,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
>   	for (i = 0; i < mux->data.n_gpios; i++)
>   		gpio_free(mux->gpio_base + mux->data.gpios[i]);
>
> -	i2c_put_adapter(mux->parent);
> +	i2c_put_adapter(muxc->parent);
>
>   	return 0;
>   }
> diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
> index d0ba424adebc..47ae2259d1ca 100644
> --- a/drivers/i2c/muxes/i2c-mux-pca9541.c
> +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
> @@ -73,6 +73,7 @@
>   #define SELECT_DELAY_LONG	1000
>
>   struct pca9541 {
> +	struct i2c_client *client;

I fail to see where this is being used.

>   	struct i2c_adapter *mux_adap;
>   	unsigned long select_timeout;
>   	unsigned long arb_timeout;
> @@ -217,7 +218,8 @@ static const u8 pca9541_control[16] = {
>    */
>   static int pca9541_arbitrate(struct i2c_client *client)
>   {
> -	struct pca9541 *data = i2c_get_clientdata(client);
> +	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
> +	struct pca9541 *data = i2c_mux_priv(muxc);
>   	int reg;
>
>   	reg = pca9541_reg_read(client, PCA9541_CONTROL);
> @@ -324,20 +326,22 @@ static int pca9541_probe(struct i2c_client *client,
>   {
>   	struct i2c_adapter *adap = client->adapter;
>   	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
> +	struct i2c_mux_core *muxc;
>   	struct pca9541 *data;
>   	int force;
> -	int ret = -ENODEV;
>
>   	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
> -		goto err;
> +		return -ENODEV;
>
> -	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
> -	if (!data) {
> -		ret = -ENOMEM;
> -		goto err;
> -	}
> +	muxc = i2c_mux_alloc(&client->dev, sizeof(*data));
> +	if (!muxc)
> +		return -ENOMEM;
> +	data = i2c_mux_priv(muxc);
> +
> +	i2c_set_clientdata(client, muxc);
>
> -	i2c_set_clientdata(client, data);
> +	data->client = client;
> +	muxc->parent = adap;
>
>   	/*
>   	 * I2C accesses are unprotected here.
> @@ -352,34 +356,29 @@ 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(adap, &client->dev, client,
> +	data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, client,
>   					     force, 0, 0,
>   					     pca9541_select_chan,
>   					     pca9541_release_chan);
>
>   	if (data->mux_adap == NULL) {
>   		dev_err(&client->dev, "failed to register master selector\n");
> -		goto exit_free;
> +		return -ENODEV;
>   	}
>
>   	dev_info(&client->dev, "registered master selector for I2C %s\n",
>   		 client->name);
>
>   	return 0;
> -
> -exit_free:
> -	kfree(data);
> -err:
> -	return ret;
>   }
>
>   static int pca9541_remove(struct i2c_client *client)
>   {
> -	struct pca9541 *data = i2c_get_clientdata(client);
> +	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
> +	struct pca9541 *data = i2c_mux_priv(muxc);
>
>   	i2c_del_mux_adapter(data->mux_adap);
>
> -	kfree(data);
>   	return 0;
>   }
>
> diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
> index acfcef3d4068..a4df831fae9d 100644
> --- a/drivers/i2c/muxes/i2c-mux-pca954x.c
> +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
> @@ -63,6 +63,7 @@ struct pca954x {
>   	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
>
>   	u8 last_chan;		/* last register value */
> +	struct i2c_client *client;

Same here.

Maybe it starts to be used in a later patch (I did not check), but then it should be defined
where it is used.

Thanks,
Guenter


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-01-05 16:42     ` Guenter Roeck
  0 siblings, 0 replies; 52+ messages in thread
From: Guenter Roeck @ 2016-01-05 16:42 UTC (permalink / raw)
  To: Peter Rosin, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TaqPxH82wqD4g

On 01/05/2016 07:57 AM, Peter Rosin wrote:
> From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>
> The initial core mux structure starts off small with only the parent
> adapter pointer, which all muxes have, and a priv pointer for mux
> driver private data.
>
> Add i2c_mux_alloc function to unify the creation of a mux.
>
> Where appropriate, pass around the mux core structure instead of the
> parent adapter or the driver private data.
>
> Remove the parent adapter pointer from the driver private data for all
> mux drivers.
>
> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> ---
>   drivers/i2c/i2c-mux.c                        | 28 +++++++++++++++++-----
>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 24 +++++++++----------
>   drivers/i2c/muxes/i2c-mux-gpio.c             | 20 ++++++++--------
>   drivers/i2c/muxes/i2c-mux-pca9541.c          | 35 ++++++++++++++--------------
>   drivers/i2c/muxes/i2c-mux-pca954x.c          | 19 ++++++++++-----
>   drivers/i2c/muxes/i2c-mux-pinctrl.c          | 23 +++++++++---------
>   drivers/i2c/muxes/i2c-mux-reg.c              | 23 ++++++++++--------
>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 10 +++++++-
>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 +
>   drivers/media/dvb-frontends/m88ds3103.c      | 10 +++++++-
>   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        | 10 +++++++-
>   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      | 13 +++++++++--
>   drivers/media/usb/cx231xx/cx231xx.h          |  2 ++
>   drivers/of/unittest.c                        | 16 +++++++------
>   include/linux/i2c-mux.h                      | 14 ++++++++++-
>   22 files changed, 187 insertions(+), 88 deletions(-)
>
> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
> index 00fc5b1c7b66..c2163f6b51d5 100644
> --- a/drivers/i2c/i2c-mux.c
> +++ b/drivers/i2c/i2c-mux.c
> @@ -31,8 +31,8 @@
>   struct i2c_mux_priv {
>   	struct i2c_adapter adap;
>   	struct i2c_algorithm algo;
> +	struct i2c_mux_core *muxc;
>
> -	struct i2c_adapter *parent;
>   	struct device *mux_dev;
>   	void *mux_priv;
>   	u32 chan_id;
> @@ -45,7 +45,8 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
>   			       struct i2c_msg msgs[], int num)
>   {
>   	struct i2c_mux_priv *priv = adap->algo_data;
> -	struct i2c_adapter *parent = priv->parent;
> +	struct i2c_mux_core *muxc = priv->muxc;
> +	struct i2c_adapter *parent = muxc->parent;
>   	int ret;
>
>   	/* Switch to the right mux port and perform the transfer. */
> @@ -65,7 +66,8 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>   			      int size, union i2c_smbus_data *data)
>   {
>   	struct i2c_mux_priv *priv = adap->algo_data;
> -	struct i2c_adapter *parent = priv->parent;
> +	struct i2c_mux_core *muxc = priv->muxc;
> +	struct i2c_adapter *parent = muxc->parent;
>   	int ret;
>
>   	/* Select the right mux port and perform the transfer. */
> @@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>   static u32 i2c_mux_functionality(struct i2c_adapter *adap)
>   {
>   	struct i2c_mux_priv *priv = adap->algo_data;
> -	struct i2c_adapter *parent = priv->parent;
> +	struct i2c_adapter *parent = priv->muxc->parent;
>
>   	return parent->algo->functionality(parent);
>   }
> @@ -102,7 +104,20 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
>   	return class;
>   }
>
> -struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
> +struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
> +{
> +	struct i2c_mux_core *muxc;
> +
> +	muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
> +	if (!muxc)
> +		return NULL;
> +	if (sizeof_priv)
> +		muxc->priv = muxc + 1;
> +	return muxc;
> +}
> +EXPORT_SYMBOL_GPL(i2c_mux_alloc);
> +
> +struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
>   				struct device *mux_dev,
>   				void *mux_priv, u32 force_nr, u32 chan_id,
>   				unsigned int class,
> @@ -111,6 +126,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>   				int (*deselect) (struct i2c_adapter *,
>   						 void *, u32))
>   {
> +	struct i2c_adapter *parent = muxc->parent;
>   	struct i2c_mux_priv *priv;
>   	char symlink_name[20];
>   	int ret;
> @@ -120,7 +136,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>   		return NULL;
>
>   	/* Set up private adapter data */
> -	priv->parent = parent;
> +	priv->muxc = muxc;
>   	priv->mux_dev = mux_dev;
>   	priv->mux_priv = mux_priv;
>   	priv->chan_id = chan_id;
> diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
> index 402e3a6c671a..6e27ea4fb25a 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 *parent;
>   	struct i2c_adapter *child;
>   	int our_gpio;
>   	int our_gpio_release;
> @@ -119,6 +118,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>   	struct device *dev = &pdev->dev;
>   	struct device_node *np = dev->of_node;
>   	struct device_node *parent_np;
> +	struct i2c_mux_core *muxc;
>   	struct i2c_arbitrator_data *arb;
>   	enum of_gpio_flags gpio_flags;
>   	unsigned long out_init;
> @@ -134,13 +134,12 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>   		return -EINVAL;
>   	}
>
> -	arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
> -	if (!arb) {
> -		dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
> +	muxc = i2c_mux_alloc(dev, sizeof(*arb));
> +	if (!muxc)
>   		return -ENOMEM;
> -	}
> -	platform_set_drvdata(pdev, arb);
> +	arb = i2c_mux_priv(muxc);
>
> +	platform_set_drvdata(pdev, muxc);
>   	/* Request GPIOs */
>   	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
>   	if (!gpio_is_valid(ret)) {
> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>   		dev_err(dev, "Cannot parse i2c-parent\n");
>   		return -EINVAL;
>   	}
> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>   	of_node_put(parent_np);
> -	if (!arb->parent) {
> +	if (!muxc->parent) {
>   		dev_err(dev, "Cannot find parent bus\n");
>   		return -EPROBE_DEFER;
>   	}
>
>   	/* Actually add the mux adapter */
> -	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
> +	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
>   					 i2c_arbitrator_select,
>   					 i2c_arbitrator_deselect);
>   	if (!arb->child) {
>   		dev_err(dev, "Failed to add adapter\n");
>   		ret = -ENODEV;
> -		i2c_put_adapter(arb->parent);
> +		i2c_put_adapter(muxc->parent);
>   	}
>
>   	return ret;
> @@ -218,10 +217,11 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>
>   static int i2c_arbitrator_remove(struct platform_device *pdev)
>   {
> -	struct i2c_arbitrator_data *arb = platform_get_drvdata(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_put_adapter(arb->parent);
> +	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 b8e11c16d98c..ee43dd76a4d7 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 *parent;
>   	struct i2c_adapter **adap; /* child busses */
>   	struct i2c_mux_gpio_platform_data data;
>   	unsigned gpio_base;
> @@ -136,19 +135,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
>
>   static int i2c_mux_gpio_probe(struct platform_device *pdev)
>   {
> +	struct i2c_mux_core *muxc;
>   	struct gpiomux *mux;
>   	struct i2c_adapter *parent;
>   	int (*deselect) (struct i2c_adapter *, void *, u32);
>   	unsigned initial_state, gpio_base;
>   	int i, ret;
>
> -	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
> -	if (!mux) {
> -		dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
> +	muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
> +	if (!muxc)
>   		return -ENOMEM;
> -	}
> +	mux = i2c_mux_priv(muxc);
>
> -	platform_set_drvdata(pdev, mux);
> +	platform_set_drvdata(pdev, muxc);
>
>   	if (!dev_get_platdata(&pdev->dev)) {
>   		ret = i2c_mux_gpio_probe_dt(mux, pdev);
> @@ -180,7 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
>   	if (!parent)
>   		return -EPROBE_DEFER;
>
> -	mux->parent = parent;
> +	muxc->parent = parent;
>   	mux->gpio_base = gpio_base;
>
>   	mux->adap = devm_kzalloc(&pdev->dev,
> @@ -223,7 +222,7 @@ 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(parent, &pdev->dev, mux, nr,
> +		mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux, nr,
>   						   mux->data.values[i], class,
>   						   i2c_mux_gpio_select, deselect);
>   		if (!mux->adap[i]) {
> @@ -253,7 +252,8 @@ alloc_failed:
>
>   static int i2c_mux_gpio_remove(struct platform_device *pdev)
>   {
> -	struct gpiomux *mux = platform_get_drvdata(pdev);
> +	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
> +	struct gpiomux *mux = i2c_mux_priv(muxc);
>   	int i;
>
>   	for (i = 0; i < mux->data.n_values; i++)
> @@ -262,7 +262,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
>   	for (i = 0; i < mux->data.n_gpios; i++)
>   		gpio_free(mux->gpio_base + mux->data.gpios[i]);
>
> -	i2c_put_adapter(mux->parent);
> +	i2c_put_adapter(muxc->parent);
>
>   	return 0;
>   }
> diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
> index d0ba424adebc..47ae2259d1ca 100644
> --- a/drivers/i2c/muxes/i2c-mux-pca9541.c
> +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
> @@ -73,6 +73,7 @@
>   #define SELECT_DELAY_LONG	1000
>
>   struct pca9541 {
> +	struct i2c_client *client;

I fail to see where this is being used.

>   	struct i2c_adapter *mux_adap;
>   	unsigned long select_timeout;
>   	unsigned long arb_timeout;
> @@ -217,7 +218,8 @@ static const u8 pca9541_control[16] = {
>    */
>   static int pca9541_arbitrate(struct i2c_client *client)
>   {
> -	struct pca9541 *data = i2c_get_clientdata(client);
> +	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
> +	struct pca9541 *data = i2c_mux_priv(muxc);
>   	int reg;
>
>   	reg = pca9541_reg_read(client, PCA9541_CONTROL);
> @@ -324,20 +326,22 @@ static int pca9541_probe(struct i2c_client *client,
>   {
>   	struct i2c_adapter *adap = client->adapter;
>   	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
> +	struct i2c_mux_core *muxc;
>   	struct pca9541 *data;
>   	int force;
> -	int ret = -ENODEV;
>
>   	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
> -		goto err;
> +		return -ENODEV;
>
> -	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
> -	if (!data) {
> -		ret = -ENOMEM;
> -		goto err;
> -	}
> +	muxc = i2c_mux_alloc(&client->dev, sizeof(*data));
> +	if (!muxc)
> +		return -ENOMEM;
> +	data = i2c_mux_priv(muxc);
> +
> +	i2c_set_clientdata(client, muxc);
>
> -	i2c_set_clientdata(client, data);
> +	data->client = client;
> +	muxc->parent = adap;
>
>   	/*
>   	 * I2C accesses are unprotected here.
> @@ -352,34 +356,29 @@ 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(adap, &client->dev, client,
> +	data->mux_adap = i2c_add_mux_adapter(muxc, &client->dev, client,
>   					     force, 0, 0,
>   					     pca9541_select_chan,
>   					     pca9541_release_chan);
>
>   	if (data->mux_adap == NULL) {
>   		dev_err(&client->dev, "failed to register master selector\n");
> -		goto exit_free;
> +		return -ENODEV;
>   	}
>
>   	dev_info(&client->dev, "registered master selector for I2C %s\n",
>   		 client->name);
>
>   	return 0;
> -
> -exit_free:
> -	kfree(data);
> -err:
> -	return ret;
>   }
>
>   static int pca9541_remove(struct i2c_client *client)
>   {
> -	struct pca9541 *data = i2c_get_clientdata(client);
> +	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
> +	struct pca9541 *data = i2c_mux_priv(muxc);
>
>   	i2c_del_mux_adapter(data->mux_adap);
>
> -	kfree(data);
>   	return 0;
>   }
>
> diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
> index acfcef3d4068..a4df831fae9d 100644
> --- a/drivers/i2c/muxes/i2c-mux-pca954x.c
> +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
> @@ -63,6 +63,7 @@ struct pca954x {
>   	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
>
>   	u8 last_chan;		/* last register value */
> +	struct i2c_client *client;

Same here.

Maybe it starts to be used in a later patch (I did not check), but then it should be defined
where it is used.

Thanks,
Guenter

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
  2016-01-05 15:57   ` Peter Rosin
@ 2016-01-05 16:49     ` kbuild test robot
  -1 siblings, 0 replies; 52+ messages in thread
From: kbuild test robot @ 2016-01-05 16:49 UTC (permalink / raw)
  To: Peter Rosin
  Cc: kbuild-all, Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Peter Korsgaard,
	Guenter Roeck, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, Peter Rosin, linux-i2c,
	devicetree, linux-kernel, linux-iio, linux-media

[-- Attachment #1: Type: text/plain, Size: 2101 bytes --]

Hi Peter,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.4-rc8 next-20160105]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/i2c-mux-cleanup-and-locking-update/20160106-000205
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: i386-randconfig-s1-201601 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c: In function 'inv_mpu_acpi_create_mux_client':
>> drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c:185:37: error: 'struct inv_mpu6050_state' has no member named 'mux_adapter'
      st->mux_client = i2c_new_device(st->mux_adapter, &info);
                                        ^

vim +185 drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c

a35c5d1a Srinivas Pandruvada 2015-01-30  179  					*name = '\0';
a35c5d1a Srinivas Pandruvada 2015-01-30  180  				strlcat(info.type, "-client",
a35c5d1a Srinivas Pandruvada 2015-01-30  181  					sizeof(info.type));
a35c5d1a Srinivas Pandruvada 2015-01-30  182  			} else
a35c5d1a Srinivas Pandruvada 2015-01-30  183  				return 0; /* no secondary addr, which is OK */
a35c5d1a Srinivas Pandruvada 2015-01-30  184  		}
a35c5d1a Srinivas Pandruvada 2015-01-30 @185  		st->mux_client = i2c_new_device(st->mux_adapter, &info);
a35c5d1a Srinivas Pandruvada 2015-01-30  186  		if (!st->mux_client)
a35c5d1a Srinivas Pandruvada 2015-01-30  187  			return -ENODEV;
a35c5d1a Srinivas Pandruvada 2015-01-30  188  

:::::: The code at line 185 was first introduced by commit
:::::: a35c5d1aa96aa6cc70e91786cbe9be4db23f8f4a iio: imu: inv_mpu6050: Create mux clients for ACPI

:::::: TO: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
:::::: CC: Jonathan Cameron <jic23@kernel.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 22266 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
@ 2016-01-05 16:49     ` kbuild test robot
  0 siblings, 0 replies; 52+ messages in thread
From: kbuild test robot @ 2016-01-05 16:49 UTC (permalink / raw)
  To: Peter Rosin
  Cc: kbuild-all, Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Peter Korsgaard,
	Guenter Roeck, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire

[-- Attachment #1: Type: text/plain, Size: 2101 bytes --]

Hi Peter,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.4-rc8 next-20160105]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/i2c-mux-cleanup-and-locking-update/20160106-000205
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: i386-randconfig-s1-201601 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c: In function 'inv_mpu_acpi_create_mux_client':
>> drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c:185:37: error: 'struct inv_mpu6050_state' has no member named 'mux_adapter'
      st->mux_client = i2c_new_device(st->mux_adapter, &info);
                                        ^

vim +185 drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c

a35c5d1a Srinivas Pandruvada 2015-01-30  179  					*name = '\0';
a35c5d1a Srinivas Pandruvada 2015-01-30  180  				strlcat(info.type, "-client",
a35c5d1a Srinivas Pandruvada 2015-01-30  181  					sizeof(info.type));
a35c5d1a Srinivas Pandruvada 2015-01-30  182  			} else
a35c5d1a Srinivas Pandruvada 2015-01-30  183  				return 0; /* no secondary addr, which is OK */
a35c5d1a Srinivas Pandruvada 2015-01-30  184  		}
a35c5d1a Srinivas Pandruvada 2015-01-30 @185  		st->mux_client = i2c_new_device(st->mux_adapter, &info);
a35c5d1a Srinivas Pandruvada 2015-01-30  186  		if (!st->mux_client)
a35c5d1a Srinivas Pandruvada 2015-01-30  187  			return -ENODEV;
a35c5d1a Srinivas Pandruvada 2015-01-30  188  

:::::: The code at line 185 was first introduced by commit
:::::: a35c5d1aa96aa6cc70e91786cbe9be4db23f8f4a iio: imu: inv_mpu6050: Create mux clients for ACPI

:::::: TO: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
:::::: CC: Jonathan Cameron <jic23@kernel.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 22266 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-05 18:48   ` Wolfram Sang
  0 siblings, 0 replies; 52+ messages in thread
From: Wolfram Sang @ 2016-01-05 18:48 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

[-- Attachment #1: Type: text/plain, Size: 738 bytes --]

Peter,

> PS. needs a bunch of testing, I do not have access to all the involved hw

First of all, thanks for diving into this topic and the huge effort you
apparently have put into it.

It is obviously a quite intrusive series, so it needs careful review.
TBH, I can't really tell when I have the bandwidth to do that, so I hope
other people will step up. And yes, it needs serious testing.

To all: Although I appreciate any review support, I'd think the first
thing to be done should be a very high level review - is this series
worth the huge update? Is the path chosen proper? Stuff like this. I'd
appreciate Acks or Revs for that. Stuff like fixing checkpatch warnings
and other minor stuff should come later.

Thanks,

   Wolfram


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-05 18:48   ` Wolfram Sang
  0 siblings, 0 replies; 52+ messages in thread
From: Wolfram Sang @ 2016-01-05 18:48 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c

[-- Attachment #1: Type: text/plain, Size: 738 bytes --]

Peter,

> PS. needs a bunch of testing, I do not have access to all the involved hw

First of all, thanks for diving into this topic and the huge effort you
apparently have put into it.

It is obviously a quite intrusive series, so it needs careful review.
TBH, I can't really tell when I have the bandwidth to do that, so I hope
other people will step up. And yes, it needs serious testing.

To all: Although I appreciate any review support, I'd think the first
thing to be done should be a very high level review - is this series
worth the huge update? Is the path chosen proper? Stuff like this. I'd
appreciate Acks or Revs for that. Stuff like fixing checkpatch warnings
and other minor stuff should come later.

Thanks,

   Wolfram


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
  2016-01-05 16:42     ` Guenter Roeck
@ 2016-01-05 18:55       ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 18:55 UTC (permalink / raw)
  To: Guenter Roeck, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree,
	linux-kernel, linux-iio, linux-media

Hi Guenter,

[BTW, if anyone feels spammed by this series, please drop me a note]

On 2016-01-05 17:42, Guenter Roeck wrote:
> On 01/05/2016 07:57 AM, Peter Rosin wrote:
>> From: Peter Rosin <peda@axentia.se>
>>
>> The initial core mux structure starts off small with only the parent
>> adapter pointer, which all muxes have, and a priv pointer for mux
>> driver private data.
>>
>> Add i2c_mux_alloc function to unify the creation of a mux.
>>
>> Where appropriate, pass around the mux core structure instead of the
>> parent adapter or the driver private data.
>>
>> Remove the parent adapter pointer from the driver private data for all
>> mux drivers.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>   drivers/i2c/i2c-mux.c                        | 28 +++++++++++++++++-----
>>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 24 +++++++++----------
>>   drivers/i2c/muxes/i2c-mux-gpio.c             | 20 ++++++++--------
>>   drivers/i2c/muxes/i2c-mux-pca9541.c          | 35 ++++++++++++++--------------
>>   drivers/i2c/muxes/i2c-mux-pca954x.c          | 19 ++++++++++-----
>>   drivers/i2c/muxes/i2c-mux-pinctrl.c          | 23 +++++++++---------
>>   drivers/i2c/muxes/i2c-mux-reg.c              | 23 ++++++++++--------
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 10 +++++++-
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 +
>>   drivers/media/dvb-frontends/m88ds3103.c      | 10 +++++++-
>>   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        | 10 +++++++-
>>   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      | 13 +++++++++--
>>   drivers/media/usb/cx231xx/cx231xx.h          |  2 ++
>>   drivers/of/unittest.c                        | 16 +++++++------
>>   include/linux/i2c-mux.h                      | 14 ++++++++++-
>>   22 files changed, 187 insertions(+), 88 deletions(-)
>>
>> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
>> index 00fc5b1c7b66..c2163f6b51d5 100644
>> --- a/drivers/i2c/i2c-mux.c
>> +++ b/drivers/i2c/i2c-mux.c
>> @@ -31,8 +31,8 @@
>>   struct i2c_mux_priv {
>>       struct i2c_adapter adap;
>>       struct i2c_algorithm algo;
>> +    struct i2c_mux_core *muxc;
>>
>> -    struct i2c_adapter *parent;
>>       struct device *mux_dev;
>>       void *mux_priv;
>>       u32 chan_id;
>> @@ -45,7 +45,8 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
>>                      struct i2c_msg msgs[], int num)
>>   {
>>       struct i2c_mux_priv *priv = adap->algo_data;
>> -    struct i2c_adapter *parent = priv->parent;
>> +    struct i2c_mux_core *muxc = priv->muxc;
>> +    struct i2c_adapter *parent = muxc->parent;
>>       int ret;
>>
>>       /* Switch to the right mux port and perform the transfer. */
>> @@ -65,7 +66,8 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>>                     int size, union i2c_smbus_data *data)
>>   {
>>       struct i2c_mux_priv *priv = adap->algo_data;
>> -    struct i2c_adapter *parent = priv->parent;
>> +    struct i2c_mux_core *muxc = priv->muxc;
>> +    struct i2c_adapter *parent = muxc->parent;
>>       int ret;
>>
>>       /* Select the right mux port and perform the transfer. */
>> @@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>>   static u32 i2c_mux_functionality(struct i2c_adapter *adap)
>>   {
>>       struct i2c_mux_priv *priv = adap->algo_data;
>> -    struct i2c_adapter *parent = priv->parent;
>> +    struct i2c_adapter *parent = priv->muxc->parent;
>>
>>       return parent->algo->functionality(parent);
>>   }
>> @@ -102,7 +104,20 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
>>       return class;
>>   }
>>
>> -struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>> +struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
>> +{
>> +    struct i2c_mux_core *muxc;
>> +
>> +    muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
>> +    if (!muxc)
>> +        return NULL;
>> +    if (sizeof_priv)
>> +        muxc->priv = muxc + 1;
>> +    return muxc;
>> +}
>> +EXPORT_SYMBOL_GPL(i2c_mux_alloc);
>> +
>> +struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
>>                   struct device *mux_dev,
>>                   void *mux_priv, u32 force_nr, u32 chan_id,
>>                   unsigned int class,
>> @@ -111,6 +126,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>>                   int (*deselect) (struct i2c_adapter *,
>>                            void *, u32))
>>   {
>> +    struct i2c_adapter *parent = muxc->parent;
>>       struct i2c_mux_priv *priv;
>>       char symlink_name[20];
>>       int ret;
>> @@ -120,7 +136,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>>           return NULL;
>>
>>       /* Set up private adapter data */
>> -    priv->parent = parent;
>> +    priv->muxc = muxc;
>>       priv->mux_dev = mux_dev;
>>       priv->mux_priv = mux_priv;
>>       priv->chan_id = chan_id;
>> diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
>> index 402e3a6c671a..6e27ea4fb25a 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 *parent;
>>       struct i2c_adapter *child;
>>       int our_gpio;
>>       int our_gpio_release;
>> @@ -119,6 +118,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>       struct device *dev = &pdev->dev;
>>       struct device_node *np = dev->of_node;
>>       struct device_node *parent_np;
>> +    struct i2c_mux_core *muxc;
>>       struct i2c_arbitrator_data *arb;
>>       enum of_gpio_flags gpio_flags;
>>       unsigned long out_init;
>> @@ -134,13 +134,12 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>           return -EINVAL;
>>       }
>>
>> -    arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
>> -    if (!arb) {
>> -        dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
>> +    muxc = i2c_mux_alloc(dev, sizeof(*arb));
>> +    if (!muxc)
>>           return -ENOMEM;
>> -    }
>> -    platform_set_drvdata(pdev, arb);
>> +    arb = i2c_mux_priv(muxc);
>>
>> +    platform_set_drvdata(pdev, muxc);
>>       /* Request GPIOs */
>>       ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
>>       if (!gpio_is_valid(ret)) {
>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>           dev_err(dev, "Cannot parse i2c-parent\n");
>>           return -EINVAL;
>>       }
>> -    arb->parent = of_get_i2c_adapter_by_node(parent_np);
>> +    muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>>       of_node_put(parent_np);
>> -    if (!arb->parent) {
>> +    if (!muxc->parent) {
>>           dev_err(dev, "Cannot find parent bus\n");
>>           return -EPROBE_DEFER;
>>       }
>>
>>       /* Actually add the mux adapter */
>> -    arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
>> +    arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
>>                        i2c_arbitrator_select,
>>                        i2c_arbitrator_deselect);
>>       if (!arb->child) {
>>           dev_err(dev, "Failed to add adapter\n");
>>           ret = -ENODEV;
>> -        i2c_put_adapter(arb->parent);
>> +        i2c_put_adapter(muxc->parent);
>>       }
>>
>>       return ret;
>> @@ -218,10 +217,11 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>
>>   static int i2c_arbitrator_remove(struct platform_device *pdev)
>>   {
>> -    struct i2c_arbitrator_data *arb = platform_get_drvdata(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_put_adapter(arb->parent);
>> +    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 b8e11c16d98c..ee43dd76a4d7 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 *parent;
>>       struct i2c_adapter **adap; /* child busses */
>>       struct i2c_mux_gpio_platform_data data;
>>       unsigned gpio_base;
>> @@ -136,19 +135,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
>>
>>   static int i2c_mux_gpio_probe(struct platform_device *pdev)
>>   {
>> +    struct i2c_mux_core *muxc;
>>       struct gpiomux *mux;
>>       struct i2c_adapter *parent;
>>       int (*deselect) (struct i2c_adapter *, void *, u32);
>>       unsigned initial_state, gpio_base;
>>       int i, ret;
>>
>> -    mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
>> -    if (!mux) {
>> -        dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
>> +    muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
>> +    if (!muxc)
>>           return -ENOMEM;
>> -    }
>> +    mux = i2c_mux_priv(muxc);
>>
>> -    platform_set_drvdata(pdev, mux);
>> +    platform_set_drvdata(pdev, muxc);
>>
>>       if (!dev_get_platdata(&pdev->dev)) {
>>           ret = i2c_mux_gpio_probe_dt(mux, pdev);
>> @@ -180,7 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
>>       if (!parent)
>>           return -EPROBE_DEFER;
>>
>> -    mux->parent = parent;
>> +    muxc->parent = parent;
>>       mux->gpio_base = gpio_base;
>>
>>       mux->adap = devm_kzalloc(&pdev->dev,
>> @@ -223,7 +222,7 @@ 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(parent, &pdev->dev, mux, nr,
>> +        mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux, nr,
>>                              mux->data.values[i], class,
>>                              i2c_mux_gpio_select, deselect);
>>           if (!mux->adap[i]) {
>> @@ -253,7 +252,8 @@ alloc_failed:
>>
>>   static int i2c_mux_gpio_remove(struct platform_device *pdev)
>>   {
>> -    struct gpiomux *mux = platform_get_drvdata(pdev);
>> +    struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
>> +    struct gpiomux *mux = i2c_mux_priv(muxc);
>>       int i;
>>
>>       for (i = 0; i < mux->data.n_values; i++)
>> @@ -262,7 +262,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
>>       for (i = 0; i < mux->data.n_gpios; i++)
>>           gpio_free(mux->gpio_base + mux->data.gpios[i]);
>>
>> -    i2c_put_adapter(mux->parent);
>> +    i2c_put_adapter(muxc->parent);
>>
>>       return 0;
>>   }
>> diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
>> index d0ba424adebc..47ae2259d1ca 100644
>> --- a/drivers/i2c/muxes/i2c-mux-pca9541.c
>> +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
>> @@ -73,6 +73,7 @@
>>   #define SELECT_DELAY_LONG    1000
>>
>>   struct pca9541 {
>> +    struct i2c_client *client;
> 
> I fail to see where this is being used.
> 

Right, that was a bad split. It's not used until 2/8, I'll move this
and the one in pca954x for v3. I will also fix the compile problem with
inv_mpu_acpi.c for v3. But I'll wait a bit for more feedback first...

*snip*

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-01-05 18:55       ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 18:55 UTC (permalink / raw)
  To: Guenter Roeck, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree

Hi Guenter,

[BTW, if anyone feels spammed by this series, please drop me a note]

On 2016-01-05 17:42, Guenter Roeck wrote:
> On 01/05/2016 07:57 AM, Peter Rosin wrote:
>> From: Peter Rosin <peda@axentia.se>
>>
>> The initial core mux structure starts off small with only the parent
>> adapter pointer, which all muxes have, and a priv pointer for mux
>> driver private data.
>>
>> Add i2c_mux_alloc function to unify the creation of a mux.
>>
>> Where appropriate, pass around the mux core structure instead of the
>> parent adapter or the driver private data.
>>
>> Remove the parent adapter pointer from the driver private data for all
>> mux drivers.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>   drivers/i2c/i2c-mux.c                        | 28 +++++++++++++++++-----
>>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c   | 24 +++++++++----------
>>   drivers/i2c/muxes/i2c-mux-gpio.c             | 20 ++++++++--------
>>   drivers/i2c/muxes/i2c-mux-pca9541.c          | 35 ++++++++++++++--------------
>>   drivers/i2c/muxes/i2c-mux-pca954x.c          | 19 ++++++++++-----
>>   drivers/i2c/muxes/i2c-mux-pinctrl.c          | 23 +++++++++---------
>>   drivers/i2c/muxes/i2c-mux-reg.c              | 23 ++++++++++--------
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c   | 10 +++++++-
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h    |  1 +
>>   drivers/media/dvb-frontends/m88ds3103.c      | 10 +++++++-
>>   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        | 10 +++++++-
>>   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      | 13 +++++++++--
>>   drivers/media/usb/cx231xx/cx231xx.h          |  2 ++
>>   drivers/of/unittest.c                        | 16 +++++++------
>>   include/linux/i2c-mux.h                      | 14 ++++++++++-
>>   22 files changed, 187 insertions(+), 88 deletions(-)
>>
>> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
>> index 00fc5b1c7b66..c2163f6b51d5 100644
>> --- a/drivers/i2c/i2c-mux.c
>> +++ b/drivers/i2c/i2c-mux.c
>> @@ -31,8 +31,8 @@
>>   struct i2c_mux_priv {
>>       struct i2c_adapter adap;
>>       struct i2c_algorithm algo;
>> +    struct i2c_mux_core *muxc;
>>
>> -    struct i2c_adapter *parent;
>>       struct device *mux_dev;
>>       void *mux_priv;
>>       u32 chan_id;
>> @@ -45,7 +45,8 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
>>                      struct i2c_msg msgs[], int num)
>>   {
>>       struct i2c_mux_priv *priv = adap->algo_data;
>> -    struct i2c_adapter *parent = priv->parent;
>> +    struct i2c_mux_core *muxc = priv->muxc;
>> +    struct i2c_adapter *parent = muxc->parent;
>>       int ret;
>>
>>       /* Switch to the right mux port and perform the transfer. */
>> @@ -65,7 +66,8 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>>                     int size, union i2c_smbus_data *data)
>>   {
>>       struct i2c_mux_priv *priv = adap->algo_data;
>> -    struct i2c_adapter *parent = priv->parent;
>> +    struct i2c_mux_core *muxc = priv->muxc;
>> +    struct i2c_adapter *parent = muxc->parent;
>>       int ret;
>>
>>       /* Select the right mux port and perform the transfer. */
>> @@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
>>   static u32 i2c_mux_functionality(struct i2c_adapter *adap)
>>   {
>>       struct i2c_mux_priv *priv = adap->algo_data;
>> -    struct i2c_adapter *parent = priv->parent;
>> +    struct i2c_adapter *parent = priv->muxc->parent;
>>
>>       return parent->algo->functionality(parent);
>>   }
>> @@ -102,7 +104,20 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
>>       return class;
>>   }
>>
>> -struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>> +struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
>> +{
>> +    struct i2c_mux_core *muxc;
>> +
>> +    muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
>> +    if (!muxc)
>> +        return NULL;
>> +    if (sizeof_priv)
>> +        muxc->priv = muxc + 1;
>> +    return muxc;
>> +}
>> +EXPORT_SYMBOL_GPL(i2c_mux_alloc);
>> +
>> +struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
>>                   struct device *mux_dev,
>>                   void *mux_priv, u32 force_nr, u32 chan_id,
>>                   unsigned int class,
>> @@ -111,6 +126,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>>                   int (*deselect) (struct i2c_adapter *,
>>                            void *, u32))
>>   {
>> +    struct i2c_adapter *parent = muxc->parent;
>>       struct i2c_mux_priv *priv;
>>       char symlink_name[20];
>>       int ret;
>> @@ -120,7 +136,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
>>           return NULL;
>>
>>       /* Set up private adapter data */
>> -    priv->parent = parent;
>> +    priv->muxc = muxc;
>>       priv->mux_dev = mux_dev;
>>       priv->mux_priv = mux_priv;
>>       priv->chan_id = chan_id;
>> diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
>> index 402e3a6c671a..6e27ea4fb25a 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 *parent;
>>       struct i2c_adapter *child;
>>       int our_gpio;
>>       int our_gpio_release;
>> @@ -119,6 +118,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>       struct device *dev = &pdev->dev;
>>       struct device_node *np = dev->of_node;
>>       struct device_node *parent_np;
>> +    struct i2c_mux_core *muxc;
>>       struct i2c_arbitrator_data *arb;
>>       enum of_gpio_flags gpio_flags;
>>       unsigned long out_init;
>> @@ -134,13 +134,12 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>           return -EINVAL;
>>       }
>>
>> -    arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
>> -    if (!arb) {
>> -        dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
>> +    muxc = i2c_mux_alloc(dev, sizeof(*arb));
>> +    if (!muxc)
>>           return -ENOMEM;
>> -    }
>> -    platform_set_drvdata(pdev, arb);
>> +    arb = i2c_mux_priv(muxc);
>>
>> +    platform_set_drvdata(pdev, muxc);
>>       /* Request GPIOs */
>>       ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
>>       if (!gpio_is_valid(ret)) {
>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>           dev_err(dev, "Cannot parse i2c-parent\n");
>>           return -EINVAL;
>>       }
>> -    arb->parent = of_get_i2c_adapter_by_node(parent_np);
>> +    muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>>       of_node_put(parent_np);
>> -    if (!arb->parent) {
>> +    if (!muxc->parent) {
>>           dev_err(dev, "Cannot find parent bus\n");
>>           return -EPROBE_DEFER;
>>       }
>>
>>       /* Actually add the mux adapter */
>> -    arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
>> +    arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
>>                        i2c_arbitrator_select,
>>                        i2c_arbitrator_deselect);
>>       if (!arb->child) {
>>           dev_err(dev, "Failed to add adapter\n");
>>           ret = -ENODEV;
>> -        i2c_put_adapter(arb->parent);
>> +        i2c_put_adapter(muxc->parent);
>>       }
>>
>>       return ret;
>> @@ -218,10 +217,11 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>
>>   static int i2c_arbitrator_remove(struct platform_device *pdev)
>>   {
>> -    struct i2c_arbitrator_data *arb = platform_get_drvdata(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_put_adapter(arb->parent);
>> +    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 b8e11c16d98c..ee43dd76a4d7 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 *parent;
>>       struct i2c_adapter **adap; /* child busses */
>>       struct i2c_mux_gpio_platform_data data;
>>       unsigned gpio_base;
>> @@ -136,19 +135,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
>>
>>   static int i2c_mux_gpio_probe(struct platform_device *pdev)
>>   {
>> +    struct i2c_mux_core *muxc;
>>       struct gpiomux *mux;
>>       struct i2c_adapter *parent;
>>       int (*deselect) (struct i2c_adapter *, void *, u32);
>>       unsigned initial_state, gpio_base;
>>       int i, ret;
>>
>> -    mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
>> -    if (!mux) {
>> -        dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
>> +    muxc = i2c_mux_alloc(&pdev->dev, sizeof(*mux));
>> +    if (!muxc)
>>           return -ENOMEM;
>> -    }
>> +    mux = i2c_mux_priv(muxc);
>>
>> -    platform_set_drvdata(pdev, mux);
>> +    platform_set_drvdata(pdev, muxc);
>>
>>       if (!dev_get_platdata(&pdev->dev)) {
>>           ret = i2c_mux_gpio_probe_dt(mux, pdev);
>> @@ -180,7 +179,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
>>       if (!parent)
>>           return -EPROBE_DEFER;
>>
>> -    mux->parent = parent;
>> +    muxc->parent = parent;
>>       mux->gpio_base = gpio_base;
>>
>>       mux->adap = devm_kzalloc(&pdev->dev,
>> @@ -223,7 +222,7 @@ 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(parent, &pdev->dev, mux, nr,
>> +        mux->adap[i] = i2c_add_mux_adapter(muxc, &pdev->dev, mux, nr,
>>                              mux->data.values[i], class,
>>                              i2c_mux_gpio_select, deselect);
>>           if (!mux->adap[i]) {
>> @@ -253,7 +252,8 @@ alloc_failed:
>>
>>   static int i2c_mux_gpio_remove(struct platform_device *pdev)
>>   {
>> -    struct gpiomux *mux = platform_get_drvdata(pdev);
>> +    struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
>> +    struct gpiomux *mux = i2c_mux_priv(muxc);
>>       int i;
>>
>>       for (i = 0; i < mux->data.n_values; i++)
>> @@ -262,7 +262,7 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev)
>>       for (i = 0; i < mux->data.n_gpios; i++)
>>           gpio_free(mux->gpio_base + mux->data.gpios[i]);
>>
>> -    i2c_put_adapter(mux->parent);
>> +    i2c_put_adapter(muxc->parent);
>>
>>       return 0;
>>   }
>> diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
>> index d0ba424adebc..47ae2259d1ca 100644
>> --- a/drivers/i2c/muxes/i2c-mux-pca9541.c
>> +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
>> @@ -73,6 +73,7 @@
>>   #define SELECT_DELAY_LONG    1000
>>
>>   struct pca9541 {
>> +    struct i2c_client *client;
> 
> I fail to see where this is being used.
> 

Right, that was a bad split. It's not used until 2/8, I'll move this
and the one in pca954x for v3. I will also fix the compile problem with
inv_mpu_acpi.c for v3. But I'll wait a bit for more feedback first...

*snip*

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
  2016-01-05 18:48   ` Wolfram Sang
@ 2016-01-05 19:01     ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 19:01 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Wolfram,

On 2016-01-05 19:48, Wolfram Sang wrote:
> Peter,
> 
>> PS. needs a bunch of testing, I do not have access to all the involved hw
> 
> First of all, thanks for diving into this topic and the huge effort you
> apparently have put into it.

Yeah, I started with dipping just the toes, but now it rather feels like
I'm fully submerged at the deep end...

> It is obviously a quite intrusive series, so it needs careful review.
> TBH, I can't really tell when I have the bandwidth to do that, so I hope
> other people will step up. And yes, it needs serious testing.
> 
> To all: Although I appreciate any review support, I'd think the first
> thing to be done should be a very high level review - is this series
> worth the huge update? Is the path chosen proper? Stuff like this. I'd
> appreciate Acks or Revs for that. Stuff like fixing checkpatch warnings
> and other minor stuff should come later.

Right, I'll hold back on sending updates for trivial stuff until the
big picture stuff has been cleared.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-05 19:01     ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 19:01 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c

Hi Wolfram,

On 2016-01-05 19:48, Wolfram Sang wrote:
> Peter,
> 
>> PS. needs a bunch of testing, I do not have access to all the involved hw
> 
> First of all, thanks for diving into this topic and the huge effort you
> apparently have put into it.

Yeah, I started with dipping just the toes, but now it rather feels like
I'm fully submerged at the deep end...

> It is obviously a quite intrusive series, so it needs careful review.
> TBH, I can't really tell when I have the bandwidth to do that, so I hope
> other people will step up. And yes, it needs serious testing.
> 
> To all: Although I appreciate any review support, I'd think the first
> thing to be done should be a very high level review - is this series
> worth the huge update? Is the path chosen proper? Stuff like this. I'd
> appreciate Acks or Revs for that. Stuff like fixing checkpatch warnings
> and other minor stuff should come later.

Right, I'll hold back on sending updates for trivial stuff until the
big picture stuff has been cleared.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
  2016-01-05 16:49     ` kbuild test robot
@ 2016-01-05 19:16       ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 19:16 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Peter Korsgaard,
	Guenter Roeck, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree,
	linux-kernel, linux-iio, linux-media

Hi,

This should fix it (I'm not sending a v3 right away).

Cheers,
Peter

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
index 1c982a56acd5..5de993deca7e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
@@ -16,6 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
+#include <linux/i2c-mux.h>
 #include <linux/dmi.h>
 #include <linux/acpi.h>
 #include "inv_mpu_iio.h"
@@ -182,7 +183,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;
 
-- 


On 2016-01-05 17:49, kbuild test robot wrote:
> Hi Peter,
> 
> [auto build test ERROR on wsa/i2c/for-next]
> [also build test ERROR on v4.4-rc8 next-20160105]
> [if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/i2c-mux-cleanup-and-locking-update/20160106-000205
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
> config: i386-randconfig-s1-201601 (attached as .config)
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 
> All errors (new ones prefixed by >>):
> 
>    drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c: In function 'inv_mpu_acpi_create_mux_client':
>>> drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c:185:37: error: 'struct inv_mpu6050_state' has no member named 'mux_adapter'
>       st->mux_client = i2c_new_device(st->mux_adapter, &info);
>                                         ^
> 
> vim +185 drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
> 
> a35c5d1a Srinivas Pandruvada 2015-01-30  179  					*name = '\0';
> a35c5d1a Srinivas Pandruvada 2015-01-30  180  				strlcat(info.type, "-client",
> a35c5d1a Srinivas Pandruvada 2015-01-30  181  					sizeof(info.type));
> a35c5d1a Srinivas Pandruvada 2015-01-30  182  			} else
> a35c5d1a Srinivas Pandruvada 2015-01-30  183  				return 0; /* no secondary addr, which is OK */
> a35c5d1a Srinivas Pandruvada 2015-01-30  184  		}
> a35c5d1a Srinivas Pandruvada 2015-01-30 @185  		st->mux_client = i2c_new_device(st->mux_adapter, &info);
> a35c5d1a Srinivas Pandruvada 2015-01-30  186  		if (!st->mux_client)
> a35c5d1a Srinivas Pandruvada 2015-01-30  187  			return -ENODEV;
> a35c5d1a Srinivas Pandruvada 2015-01-30  188  
> 
> :::::: The code at line 185 was first introduced by commit
> :::::: a35c5d1aa96aa6cc70e91786cbe9be4db23f8f4a iio: imu: inv_mpu6050: Create mux clients for ACPI
> 
> :::::: TO: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> :::::: CC: Jonathan Cameron <jic23@kernel.org>
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
> 

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
@ 2016-01-05 19:16       ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 19:16 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Peter Korsgaard,
	Guenter Roeck, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire

Hi,

This should fix it (I'm not sending a v3 right away).

Cheers,
Peter

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
index 1c982a56acd5..5de993deca7e 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
@@ -16,6 +16,7 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
+#include <linux/i2c-mux.h>
 #include <linux/dmi.h>
 #include <linux/acpi.h>
 #include "inv_mpu_iio.h"
@@ -182,7 +183,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;
 
-- 


On 2016-01-05 17:49, kbuild test robot wrote:
> Hi Peter,
> 
> [auto build test ERROR on wsa/i2c/for-next]
> [also build test ERROR on v4.4-rc8 next-20160105]
> [if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Peter-Rosin/i2c-mux-cleanup-and-locking-update/20160106-000205
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
> config: i386-randconfig-s1-201601 (attached as .config)
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386 
> 
> All errors (new ones prefixed by >>):
> 
>    drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c: In function 'inv_mpu_acpi_create_mux_client':
>>> drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c:185:37: error: 'struct inv_mpu6050_state' has no member named 'mux_adapter'
>       st->mux_client = i2c_new_device(st->mux_adapter, &info);
>                                         ^
> 
> vim +185 drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
> 
> a35c5d1a Srinivas Pandruvada 2015-01-30  179  					*name = '\0';
> a35c5d1a Srinivas Pandruvada 2015-01-30  180  				strlcat(info.type, "-client",
> a35c5d1a Srinivas Pandruvada 2015-01-30  181  					sizeof(info.type));
> a35c5d1a Srinivas Pandruvada 2015-01-30  182  			} else
> a35c5d1a Srinivas Pandruvada 2015-01-30  183  				return 0; /* no secondary addr, which is OK */
> a35c5d1a Srinivas Pandruvada 2015-01-30  184  		}
> a35c5d1a Srinivas Pandruvada 2015-01-30 @185  		st->mux_client = i2c_new_device(st->mux_adapter, &info);
> a35c5d1a Srinivas Pandruvada 2015-01-30  186  		if (!st->mux_client)
> a35c5d1a Srinivas Pandruvada 2015-01-30  187  			return -ENODEV;
> a35c5d1a Srinivas Pandruvada 2015-01-30  188  
> 
> :::::: The code at line 185 was first introduced by commit
> :::::: a35c5d1aa96aa6cc70e91786cbe9be4db23f8f4a iio: imu: inv_mpu6050: Create mux clients for ACPI
> 
> :::::: TO: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> :::::: CC: Jonathan Cameron <jic23@kernel.org>
> 
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
> 

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
  2016-01-05 15:57   ` Peter Rosin
@ 2016-01-05 22:17     ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 22:17 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 3/8] i2c-mux: move the slave side adapter management to i2c_mux_core
@ 2016-01-05 22:17     ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-05 22:17 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Antti Palosaari, Mauro Carvalho Chehab, Frank Rowand,
	Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c

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

^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
  2016-01-05 18:48   ` Wolfram Sang
@ 2016-01-06 13:23     ` Crt Mori
  -1 siblings, 0 replies; 52+ messages in thread
From: Crt Mori @ 2016-01-06 13:23 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Wolfram and Peter,
I will give my opinion about the path chosen although it should be
taken lightly.

I can see that hardware guys missed the software guys again on the
development path, but since this happens more often than not, I would
say it seems OK to have support for this as long as it does not make
more complex (longer) standard i2c transfers. I would support to have
additional mutex before mux as that will make less chance that someone
forgets to lock mutex before mux and proposed solution seems valid.

Regards,
Crt

On 5 January 2016 at 19:48, Wolfram Sang <wsa@the-dreams.de> wrote:
> Peter,
>
>> PS. needs a bunch of testing, I do not have access to all the involved hw
>
> First of all, thanks for diving into this topic and the huge effort you
> apparently have put into it.
>
> It is obviously a quite intrusive series, so it needs careful review.
> TBH, I can't really tell when I have the bandwidth to do that, so I hope
> other people will step up. And yes, it needs serious testing.
>
> To all: Although I appreciate any review support, I'd think the first
> thing to be done should be a very high level review - is this series
> worth the huge update? Is the path chosen proper? Stuff like this. I'd
> appreciate Acks or Revs for that. Stuff like fixing checkpatch warnings
> and other minor stuff should come later.
>
> Thanks,
>
>    Wolfram
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-06 13:23     ` Crt Mori
  0 siblings, 0 replies; 52+ messages in thread
From: Crt Mori @ 2016-01-06 13:23 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Peter Rosin, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire

Hi Wolfram and Peter,
I will give my opinion about the path chosen although it should be
taken lightly.

I can see that hardware guys missed the software guys again on the
development path, but since this happens more often than not, I would
say it seems OK to have support for this as long as it does not make
more complex (longer) standard i2c transfers. I would support to have
additional mutex before mux as that will make less chance that someone
forgets to lock mutex before mux and proposed solution seems valid.

Regards,
Crt

On 5 January 2016 at 19:48, Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org> wrote:
> Peter,
>
>> PS. needs a bunch of testing, I do not have access to all the involved hw
>
> First of all, thanks for diving into this topic and the huge effort you
> apparently have put into it.
>
> It is obviously a quite intrusive series, so it needs careful review.
> TBH, I can't really tell when I have the bandwidth to do that, so I hope
> other people will step up. And yes, it needs serious testing.
>
> To all: Although I appreciate any review support, I'd think the first
> thing to be done should be a very high level review - is this series
> worth the huge update? Is the path chosen proper? Stuff like this. I'd
> appreciate Acks or Revs for that. Stuff like fixing checkpatch warnings
> and other minor stuff should come later.
>
> Thanks,
>
>    Wolfram
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
  2016-01-05 15:57   ` Peter Rosin
@ 2016-01-06 14:49     ` Rob Herring
  -1 siblings, 0 replies; 52+ messages in thread
From: Rob Herring @ 2016-01-06 14:49 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Wolfram Sang, Peter Rosin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

On Tue, Jan 05, 2016 at 04:57:18PM +0100, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
> 
> With a i2c topology like the following
> 
>                        GPIO ---|  ------ BAT1
>                         |      v /
>    I2C  -----+----------+---- MUX
>              |                   \
>            EEPROM                 ------ BAT2

Yuck. One would think you would just use an I2C controlled mux in this 
case...
 
> there is a locking problem with the GPIO controller since it is a client
> on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
> will lock the whole i2c bus prior to attempting to switch the mux to the
> correct i2c segment. In the above case, the GPIO device is an I/O expander
> with an i2c interface, and since the GPIO subsystem knows nothing (and
> rightfully so) about the lockless needs of the i2c mux code, this results
> in a deadlock when the GPIO driver issues i2c transfers to modify the
> mux.
> 
> So, observing that while it is needed to have the i2c bus locked during the
> actual MUX update in order to avoid random garbage on the slave side, it
> is not strictly a must to have it locked over the whole sequence of a full
> select-transfer-deselect mux client operation. The mux itself needs to be
> locked, so transfers to clients behind the mux are serialized, and the mux
> needs to be stable during all i2c traffic (otherwise individual mux slave
> segments might see garbage, or worse).
> 
> Add devive tree properties (bool named i2c-controlled) to i2c-mux-gpio and
> i2c-mux-pinctrl that asserts that the the gpio/pinctrl is controlled via
> the same i2c bus that it muxes.

Can't you determine this condition by checking the mux parent and gpio 
parent are the same i2c controller?

Alternatively, can't you just always do the locking like i2c-controlled 
is set when a mux is involved? What is the harm in doing that if the 
GPIO is controlled somewhere else?

I would prefer to see a solution not requiring DT updates to fix and 
this change seems like it is working around kernel issues.

Rob

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
@ 2016-01-06 14:49     ` Rob Herring
  0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring @ 2016-01-06 14:49 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Wolfram Sang, Peter Rosin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c

On Tue, Jan 05, 2016 at 04:57:18PM +0100, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
> 
> With a i2c topology like the following
> 
>                        GPIO ---|  ------ BAT1
>                         |      v /
>    I2C  -----+----------+---- MUX
>              |                   \
>            EEPROM                 ------ BAT2

Yuck. One would think you would just use an I2C controlled mux in this 
case...
 
> there is a locking problem with the GPIO controller since it is a client
> on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
> will lock the whole i2c bus prior to attempting to switch the mux to the
> correct i2c segment. In the above case, the GPIO device is an I/O expander
> with an i2c interface, and since the GPIO subsystem knows nothing (and
> rightfully so) about the lockless needs of the i2c mux code, this results
> in a deadlock when the GPIO driver issues i2c transfers to modify the
> mux.
> 
> So, observing that while it is needed to have the i2c bus locked during the
> actual MUX update in order to avoid random garbage on the slave side, it
> is not strictly a must to have it locked over the whole sequence of a full
> select-transfer-deselect mux client operation. The mux itself needs to be
> locked, so transfers to clients behind the mux are serialized, and the mux
> needs to be stable during all i2c traffic (otherwise individual mux slave
> segments might see garbage, or worse).
> 
> Add devive tree properties (bool named i2c-controlled) to i2c-mux-gpio and
> i2c-mux-pinctrl that asserts that the the gpio/pinctrl is controlled via
> the same i2c bus that it muxes.

Can't you determine this condition by checking the mux parent and gpio 
parent are the same i2c controller?

Alternatively, can't you just always do the locking like i2c-controlled 
is set when a mux is involved? What is the harm in doing that if the 
GPIO is controlled somewhere else?

I would prefer to see a solution not requiring DT updates to fix and 
this change seems like it is working around kernel issues.

Rob

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
  2016-01-05 15:57 ` Peter Rosin
@ 2016-01-06 17:17   ` Antti Palosaari
  -1 siblings, 0 replies; 52+ messages in thread
From: Antti Palosaari @ 2016-01-06 17:17 UTC (permalink / raw)
  To: Peter Rosin, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree,
	linux-kernel, linux-iio, linux-media

On 01/05/2016 05:57 PM, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
>
> Hi!
>
> I have a pair of boards with this i2c topology:
>
>                         GPIO ---|  ------ BAT1
>                          |      v /
>     I2C  -----+------B---+---- MUX
>               |                   \
>             EEPROM                 ------ BAT2
>
> 	(B denotes the boundary between the boards)

Handling of I2C muxes that close channel automatically, after the first 
I2C stop (P) is seen?

For example channel is selected to BAT1 => there is EEPROM write => mux 
closes channel BAT1 => access to BAT1 will fail. Is it possible to lock 
whole adapter, but allow only traffic to i2c mux client?

regards
Antti

>
> The problem with this is that the GPIO controller sits on the same i2c bus
> that it MUXes. For pca954x devices this is worked around by using unlocked
> transfers when updating the MUX. I have no such luck as the GPIO is a general
> purpose IO expander and the MUX is just a random bidirectional MUX, unaware
> of the fact that it is muxing an i2c bus, and extending unlocked transfers
> into the GPIO subsystem is too ugly to even think about. But the general hw
> approach is sane in my opinion, with the number of connections between the
> two boards minimized. To put is plainly, I need support for it.
>
> So, I observe that while it is needed to have the i2c bus locked during the
> actual MUX update in order to avoid random garbage on the slave side, it
> is not strictly a must to have it locked over the whole sequence of a full
> select-transfer-deselect operation. The MUX itself needs to be locked, so
> transfers to clients behind the mux are serialized, and the MUX needs to be
> stable during all i2c traffic (otherwise individual mux slave segments
> might see garbage).
>
> This series accomplishes this by adding a dt property to i2c-mux-gpio and
> i2c-mux-pinctrl that can be used to state that the mux is updated by means
> of the muxed master bus, and that the select-transfer-deselect operations
> should be locked individually. When this holds, the i2c bus *is* locked
> during muxing, since the muxing happens as part of i2c transfers. This
> is true even if the MUX is updated with several transfers to the GPIO (at
> least as long as *all* MUX changes are using the i2s master bus). A lock
> is added to the mux so that transfers through the mux are serialized.
>
> Concerns:
> - The locking is perhaps too complex?
> - I worry about the priority inheritance aspect of the adapter lock. When
>    the transfers behind the mux are divided into select-transfer-deselect all
>    locked individually, low priority transfers get more chances to interfere
>    with high priority transfers.
> - When doing an i2c_transfer() in_atomic() context of with irqs_disabled(),
>    there is a higher possibility that the mux is not returned to its idle
>    state after a failed (-EAGAIN) transfer due to trylock.
>
> To summarize the series, there's some i2c-mux infrastructure cleanup work
> first (I think that part stands by itself as desireable regardless), the
> locking changes are in the last three patches of the series, with the real
> meat in 8/8.
>
> PS. needs a bunch of testing, I do not have access to all the involved hw
>
> Changes since v1:
> - Allocate mux core and (optional) priv in a combined allocation.
> - Killed dev_err messages triggered by memory allocation failure.
> - Fix the device specific i2c muxes that I had overlooked.
> - Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously).
>
> Cheers,
> Peter
>
> Peter Rosin (8):
>    i2c-mux: add common core data for every mux instance
>    i2c-mux: move select and deselect ops to i2c_mux_core
>    i2c-mux: move the slave side adapter management to i2c_mux_core
>    i2c-mux: remove the mux dev pointer from the mux per channel data
>    i2c-mux: pinctrl: get rid of the driver private struct device pointer
>    i2c: allow adapter drivers to override the adapter locking
>    i2c: muxes always lock the parent adapter
>    i2c-mux: relax locking of the top i2c adapter during i2c controlled
>      muxing
>
>   .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
>   .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
>   drivers/i2c/i2c-core.c                             |  59 ++---
>   drivers/i2c/i2c-mux.c                              | 272 +++++++++++++++++----
>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
>   drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
>   drivers/i2c/muxes/i2c-mux-pca9541.c                |  58 +++--
>   drivers/i2c/muxes/i2c-mux-pca954x.c                |  66 ++---
>   drivers/i2c/muxes/i2c-mux-pinctrl.c                |  89 +++----
>   drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c         |  33 +--
>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |   2 +-
>   drivers/media/dvb-frontends/m88ds3103.c            |  23 +-
>   drivers/media/dvb-frontends/m88ds3103_priv.h       |   2 +-
>   drivers/media/dvb-frontends/rtl2830.c              |  24 +-
>   drivers/media/dvb-frontends/rtl2830_priv.h         |   2 +-
>   drivers/media/dvb-frontends/rtl2832.c              |  30 ++-
>   drivers/media/dvb-frontends/rtl2832_priv.h         |   2 +-
>   drivers/media/dvb-frontends/si2168.c               |  29 ++-
>   drivers/media/dvb-frontends/si2168_priv.h          |   2 +-
>   drivers/media/usb/cx231xx/cx231xx-core.c           |   6 +-
>   drivers/media/usb/cx231xx/cx231xx-i2c.c            |  48 ++--
>   drivers/media/usb/cx231xx/cx231xx.h                |   4 +-
>   drivers/of/unittest.c                              |  41 ++--
>   include/linux/i2c-mux-gpio.h                       |   2 +
>   include/linux/i2c-mux-pinctrl.h                    |   2 +
>   include/linux/i2c-mux.h                            |  39 ++-
>   include/linux/i2c.h                                |  28 ++-
>   28 files changed, 612 insertions(+), 424 deletions(-)
>

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-06 17:17   ` Antti Palosaari
  0 siblings, 0 replies; 52+ messages in thread
From: Antti Palosaari @ 2016-01-06 17:17 UTC (permalink / raw)
  To: Peter Rosin, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree

On 01/05/2016 05:57 PM, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
>
> Hi!
>
> I have a pair of boards with this i2c topology:
>
>                         GPIO ---|  ------ BAT1
>                          |      v /
>     I2C  -----+------B---+---- MUX
>               |                   \
>             EEPROM                 ------ BAT2
>
> 	(B denotes the boundary between the boards)

Handling of I2C muxes that close channel automatically, after the first 
I2C stop (P) is seen?

For example channel is selected to BAT1 => there is EEPROM write => mux 
closes channel BAT1 => access to BAT1 will fail. Is it possible to lock 
whole adapter, but allow only traffic to i2c mux client?

regards
Antti

>
> The problem with this is that the GPIO controller sits on the same i2c bus
> that it MUXes. For pca954x devices this is worked around by using unlocked
> transfers when updating the MUX. I have no such luck as the GPIO is a general
> purpose IO expander and the MUX is just a random bidirectional MUX, unaware
> of the fact that it is muxing an i2c bus, and extending unlocked transfers
> into the GPIO subsystem is too ugly to even think about. But the general hw
> approach is sane in my opinion, with the number of connections between the
> two boards minimized. To put is plainly, I need support for it.
>
> So, I observe that while it is needed to have the i2c bus locked during the
> actual MUX update in order to avoid random garbage on the slave side, it
> is not strictly a must to have it locked over the whole sequence of a full
> select-transfer-deselect operation. The MUX itself needs to be locked, so
> transfers to clients behind the mux are serialized, and the MUX needs to be
> stable during all i2c traffic (otherwise individual mux slave segments
> might see garbage).
>
> This series accomplishes this by adding a dt property to i2c-mux-gpio and
> i2c-mux-pinctrl that can be used to state that the mux is updated by means
> of the muxed master bus, and that the select-transfer-deselect operations
> should be locked individually. When this holds, the i2c bus *is* locked
> during muxing, since the muxing happens as part of i2c transfers. This
> is true even if the MUX is updated with several transfers to the GPIO (at
> least as long as *all* MUX changes are using the i2s master bus). A lock
> is added to the mux so that transfers through the mux are serialized.
>
> Concerns:
> - The locking is perhaps too complex?
> - I worry about the priority inheritance aspect of the adapter lock. When
>    the transfers behind the mux are divided into select-transfer-deselect all
>    locked individually, low priority transfers get more chances to interfere
>    with high priority transfers.
> - When doing an i2c_transfer() in_atomic() context of with irqs_disabled(),
>    there is a higher possibility that the mux is not returned to its idle
>    state after a failed (-EAGAIN) transfer due to trylock.
>
> To summarize the series, there's some i2c-mux infrastructure cleanup work
> first (I think that part stands by itself as desireable regardless), the
> locking changes are in the last three patches of the series, with the real
> meat in 8/8.
>
> PS. needs a bunch of testing, I do not have access to all the involved hw
>
> Changes since v1:
> - Allocate mux core and (optional) priv in a combined allocation.
> - Killed dev_err messages triggered by memory allocation failure.
> - Fix the device specific i2c muxes that I had overlooked.
> - Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously).
>
> Cheers,
> Peter
>
> Peter Rosin (8):
>    i2c-mux: add common core data for every mux instance
>    i2c-mux: move select and deselect ops to i2c_mux_core
>    i2c-mux: move the slave side adapter management to i2c_mux_core
>    i2c-mux: remove the mux dev pointer from the mux per channel data
>    i2c-mux: pinctrl: get rid of the driver private struct device pointer
>    i2c: allow adapter drivers to override the adapter locking
>    i2c: muxes always lock the parent adapter
>    i2c-mux: relax locking of the top i2c adapter during i2c controlled
>      muxing
>
>   .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
>   .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
>   drivers/i2c/i2c-core.c                             |  59 ++---
>   drivers/i2c/i2c-mux.c                              | 272 +++++++++++++++++----
>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
>   drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
>   drivers/i2c/muxes/i2c-mux-pca9541.c                |  58 +++--
>   drivers/i2c/muxes/i2c-mux-pca954x.c                |  66 ++---
>   drivers/i2c/muxes/i2c-mux-pinctrl.c                |  89 +++----
>   drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c         |  33 +--
>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |   2 +-
>   drivers/media/dvb-frontends/m88ds3103.c            |  23 +-
>   drivers/media/dvb-frontends/m88ds3103_priv.h       |   2 +-
>   drivers/media/dvb-frontends/rtl2830.c              |  24 +-
>   drivers/media/dvb-frontends/rtl2830_priv.h         |   2 +-
>   drivers/media/dvb-frontends/rtl2832.c              |  30 ++-
>   drivers/media/dvb-frontends/rtl2832_priv.h         |   2 +-
>   drivers/media/dvb-frontends/si2168.c               |  29 ++-
>   drivers/media/dvb-frontends/si2168_priv.h          |   2 +-
>   drivers/media/usb/cx231xx/cx231xx-core.c           |   6 +-
>   drivers/media/usb/cx231xx/cx231xx-i2c.c            |  48 ++--
>   drivers/media/usb/cx231xx/cx231xx.h                |   4 +-
>   drivers/of/unittest.c                              |  41 ++--
>   include/linux/i2c-mux-gpio.h                       |   2 +
>   include/linux/i2c-mux-pinctrl.h                    |   2 +
>   include/linux/i2c-mux.h                            |  39 ++-
>   include/linux/i2c.h                                |  28 ++-
>   28 files changed, 612 insertions(+), 424 deletions(-)
>

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-07  8:14     ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-07  8:14 UTC (permalink / raw)
  To: Antti Palosaari, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree,
	linux-kernel, linux-iio, linux-media

Hi Antti,

On 2016-01-06 18:17, Antti Palosaari wrote:
> On 01/05/2016 05:57 PM, Peter Rosin wrote:
>> From: Peter Rosin <peda@axentia.se>
>>
>> Hi!
>>
>> I have a pair of boards with this i2c topology:
>>
>>                         GPIO ---|  ------ BAT1
>>                          |      v /
>>     I2C  -----+------B---+---- MUX
>>               |                   \
>>             EEPROM                 ------ BAT2
>>
>>     (B denotes the boundary between the boards)
> 
> Handling of I2C muxes that close channel automatically, after the first I2C stop (P) is seen?
> 
> For example channel is selected to BAT1 => there is EEPROM write => mux closes channel BAT1 => access to BAT1 will fail.

The proposed locking changes affect gpio- and pinctrl-controlled muxes
only, and I can't see one of those actually know anything about the
i2c-signals that they mux. Such muxes certainly has to obey the pins
that control them, no?

That fact that other muxes might piggy-back and also use the new
i2c-controlled flag is a different question, and it may indeed not be
safe to declare a mux "i2c-controlled" just to avoid the locking, if
the locking is in fact required. Maybe the name "i2c-controlled" is
poor?

> Is it possible to lock whole adapter, but allow only traffic to i2c mux client?

This is basically what is there today, and which does not work for the
above i2c topology. So maybe you need to expand on what you meant?



There is no neat way for the i2c mux code to dip its fingers into all
relevant i2c-accesses to categorize them as "mux updates" or "mux slave
side accesses", when they come from generic subsystems such as gpio
och pinctrl.

The only thing I have been able to think of in that area is to add i2c
devices that are used to change the mux to a virtual slave adapter of
the mux, so that the mux can identify those accesses and bypass the
locking. But that isn't generic enough to cover the case where one
device is used to control more than one mux (since it needs to sit on
more than one adapter in that case), so I scrapped that idea pretty
early. But I also find that I have to scrap it again and again, since
everything else I cook up usually ends up being some variant of the
virtual slave adapter when I think some more about it. Maybe it *is*
possible to have the same device in different places in the adapter
tree (if all those places have a common ancestor)? But I don't think
so...

That does not address your concerns about extra accesses creeping
in between the mux select and the mux slave side access for auto-
closing muxes (or arbitrators), but I never pretended that there would
be protection from that. If there are such requirements you basically
have to lock the root adapter to prevent i2c "noise".

I can't see recursive locks helping either, because that would need
lock ownership to be propagated into gpio/pinctrl, and that is again
too ugly.

Cheers,
Peter

> regards
> Antti
> 
>>
>> The problem with this is that the GPIO controller sits on the same i2c bus
>> that it MUXes. For pca954x devices this is worked around by using unlocked
>> transfers when updating the MUX. I have no such luck as the GPIO is a general
>> purpose IO expander and the MUX is just a random bidirectional MUX, unaware
>> of the fact that it is muxing an i2c bus, and extending unlocked transfers
>> into the GPIO subsystem is too ugly to even think about. But the general hw
>> approach is sane in my opinion, with the number of connections between the
>> two boards minimized. To put is plainly, I need support for it.
>>
>> So, I observe that while it is needed to have the i2c bus locked during the
>> actual MUX update in order to avoid random garbage on the slave side, it
>> is not strictly a must to have it locked over the whole sequence of a full
>> select-transfer-deselect operation. The MUX itself needs to be locked, so
>> transfers to clients behind the mux are serialized, and the MUX needs to be
>> stable during all i2c traffic (otherwise individual mux slave segments
>> might see garbage).
>>
>> This series accomplishes this by adding a dt property to i2c-mux-gpio and
>> i2c-mux-pinctrl that can be used to state that the mux is updated by means
>> of the muxed master bus, and that the select-transfer-deselect operations
>> should be locked individually. When this holds, the i2c bus *is* locked
>> during muxing, since the muxing happens as part of i2c transfers. This
>> is true even if the MUX is updated with several transfers to the GPIO (at
>> least as long as *all* MUX changes are using the i2s master bus). A lock
>> is added to the mux so that transfers through the mux are serialized.
>>
>> Concerns:
>> - The locking is perhaps too complex?
>> - I worry about the priority inheritance aspect of the adapter lock. When
>>    the transfers behind the mux are divided into select-transfer-deselect all
>>    locked individually, low priority transfers get more chances to interfere
>>    with high priority transfers.
>> - When doing an i2c_transfer() in_atomic() context of with irqs_disabled(),
>>    there is a higher possibility that the mux is not returned to its idle
>>    state after a failed (-EAGAIN) transfer due to trylock.
>>
>> To summarize the series, there's some i2c-mux infrastructure cleanup work
>> first (I think that part stands by itself as desireable regardless), the
>> locking changes are in the last three patches of the series, with the real
>> meat in 8/8.
>>
>> PS. needs a bunch of testing, I do not have access to all the involved hw
>>
>> Changes since v1:
>> - Allocate mux core and (optional) priv in a combined allocation.
>> - Killed dev_err messages triggered by memory allocation failure.
>> - Fix the device specific i2c muxes that I had overlooked.
>> - Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously).
>>
>> Cheers,
>> Peter
>>
>> Peter Rosin (8):
>>    i2c-mux: add common core data for every mux instance
>>    i2c-mux: move select and deselect ops to i2c_mux_core
>>    i2c-mux: move the slave side adapter management to i2c_mux_core
>>    i2c-mux: remove the mux dev pointer from the mux per channel data
>>    i2c-mux: pinctrl: get rid of the driver private struct device pointer
>>    i2c: allow adapter drivers to override the adapter locking
>>    i2c: muxes always lock the parent adapter
>>    i2c-mux: relax locking of the top i2c adapter during i2c controlled
>>      muxing
>>
>>   .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
>>   .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
>>   drivers/i2c/i2c-core.c                             |  59 ++---
>>   drivers/i2c/i2c-mux.c                              | 272 +++++++++++++++++----
>>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
>>   drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
>>   drivers/i2c/muxes/i2c-mux-pca9541.c                |  58 +++--
>>   drivers/i2c/muxes/i2c-mux-pca954x.c                |  66 ++---
>>   drivers/i2c/muxes/i2c-mux-pinctrl.c                |  89 +++----
>>   drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c         |  33 +--
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |   2 +-
>>   drivers/media/dvb-frontends/m88ds3103.c            |  23 +-
>>   drivers/media/dvb-frontends/m88ds3103_priv.h       |   2 +-
>>   drivers/media/dvb-frontends/rtl2830.c              |  24 +-
>>   drivers/media/dvb-frontends/rtl2830_priv.h         |   2 +-
>>   drivers/media/dvb-frontends/rtl2832.c              |  30 ++-
>>   drivers/media/dvb-frontends/rtl2832_priv.h         |   2 +-
>>   drivers/media/dvb-frontends/si2168.c               |  29 ++-
>>   drivers/media/dvb-frontends/si2168_priv.h          |   2 +-
>>   drivers/media/usb/cx231xx/cx231xx-core.c           |   6 +-
>>   drivers/media/usb/cx231xx/cx231xx-i2c.c            |  48 ++--
>>   drivers/media/usb/cx231xx/cx231xx.h                |   4 +-
>>   drivers/of/unittest.c                              |  41 ++--
>>   include/linux/i2c-mux-gpio.h                       |   2 +
>>   include/linux/i2c-mux-pinctrl.h                    |   2 +
>>   include/linux/i2c-mux.h                            |  39 ++-
>>   include/linux/i2c.h                                |  28 ++-
>>   28 files changed, 612 insertions(+), 424 deletions(-)
>>
> 

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 0/8] i2c mux cleanup and locking update
@ 2016-01-07  8:14     ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-07  8:14 UTC (permalink / raw)
  To: Antti Palosaari, Wolfram Sang
  Cc: Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Peter Korsgaard, Guenter Roeck, Jonathan Cameron,
	Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TZNg+MwTxZMZA

Hi Antti,

On 2016-01-06 18:17, Antti Palosaari wrote:
> On 01/05/2016 05:57 PM, Peter Rosin wrote:
>> From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>
>> Hi!
>>
>> I have a pair of boards with this i2c topology:
>>
>>                         GPIO ---|  ------ BAT1
>>                          |      v /
>>     I2C  -----+------B---+---- MUX
>>               |                   \
>>             EEPROM                 ------ BAT2
>>
>>     (B denotes the boundary between the boards)
> 
> Handling of I2C muxes that close channel automatically, after the first I2C stop (P) is seen?
> 
> For example channel is selected to BAT1 => there is EEPROM write => mux closes channel BAT1 => access to BAT1 will fail.

The proposed locking changes affect gpio- and pinctrl-controlled muxes
only, and I can't see one of those actually know anything about the
i2c-signals that they mux. Such muxes certainly has to obey the pins
that control them, no?

That fact that other muxes might piggy-back and also use the new
i2c-controlled flag is a different question, and it may indeed not be
safe to declare a mux "i2c-controlled" just to avoid the locking, if
the locking is in fact required. Maybe the name "i2c-controlled" is
poor?

> Is it possible to lock whole adapter, but allow only traffic to i2c mux client?

This is basically what is there today, and which does not work for the
above i2c topology. So maybe you need to expand on what you meant?



There is no neat way for the i2c mux code to dip its fingers into all
relevant i2c-accesses to categorize them as "mux updates" or "mux slave
side accesses", when they come from generic subsystems such as gpio
och pinctrl.

The only thing I have been able to think of in that area is to add i2c
devices that are used to change the mux to a virtual slave adapter of
the mux, so that the mux can identify those accesses and bypass the
locking. But that isn't generic enough to cover the case where one
device is used to control more than one mux (since it needs to sit on
more than one adapter in that case), so I scrapped that idea pretty
early. But I also find that I have to scrap it again and again, since
everything else I cook up usually ends up being some variant of the
virtual slave adapter when I think some more about it. Maybe it *is*
possible to have the same device in different places in the adapter
tree (if all those places have a common ancestor)? But I don't think
so...

That does not address your concerns about extra accesses creeping
in between the mux select and the mux slave side access for auto-
closing muxes (or arbitrators), but I never pretended that there would
be protection from that. If there are such requirements you basically
have to lock the root adapter to prevent i2c "noise".

I can't see recursive locks helping either, because that would need
lock ownership to be propagated into gpio/pinctrl, and that is again
too ugly.

Cheers,
Peter

> regards
> Antti
> 
>>
>> The problem with this is that the GPIO controller sits on the same i2c bus
>> that it MUXes. For pca954x devices this is worked around by using unlocked
>> transfers when updating the MUX. I have no such luck as the GPIO is a general
>> purpose IO expander and the MUX is just a random bidirectional MUX, unaware
>> of the fact that it is muxing an i2c bus, and extending unlocked transfers
>> into the GPIO subsystem is too ugly to even think about. But the general hw
>> approach is sane in my opinion, with the number of connections between the
>> two boards minimized. To put is plainly, I need support for it.
>>
>> So, I observe that while it is needed to have the i2c bus locked during the
>> actual MUX update in order to avoid random garbage on the slave side, it
>> is not strictly a must to have it locked over the whole sequence of a full
>> select-transfer-deselect operation. The MUX itself needs to be locked, so
>> transfers to clients behind the mux are serialized, and the MUX needs to be
>> stable during all i2c traffic (otherwise individual mux slave segments
>> might see garbage).
>>
>> This series accomplishes this by adding a dt property to i2c-mux-gpio and
>> i2c-mux-pinctrl that can be used to state that the mux is updated by means
>> of the muxed master bus, and that the select-transfer-deselect operations
>> should be locked individually. When this holds, the i2c bus *is* locked
>> during muxing, since the muxing happens as part of i2c transfers. This
>> is true even if the MUX is updated with several transfers to the GPIO (at
>> least as long as *all* MUX changes are using the i2s master bus). A lock
>> is added to the mux so that transfers through the mux are serialized.
>>
>> Concerns:
>> - The locking is perhaps too complex?
>> - I worry about the priority inheritance aspect of the adapter lock. When
>>    the transfers behind the mux are divided into select-transfer-deselect all
>>    locked individually, low priority transfers get more chances to interfere
>>    with high priority transfers.
>> - When doing an i2c_transfer() in_atomic() context of with irqs_disabled(),
>>    there is a higher possibility that the mux is not returned to its idle
>>    state after a failed (-EAGAIN) transfer due to trylock.
>>
>> To summarize the series, there's some i2c-mux infrastructure cleanup work
>> first (I think that part stands by itself as desireable regardless), the
>> locking changes are in the last three patches of the series, with the real
>> meat in 8/8.
>>
>> PS. needs a bunch of testing, I do not have access to all the involved hw
>>
>> Changes since v1:
>> - Allocate mux core and (optional) priv in a combined allocation.
>> - Killed dev_err messages triggered by memory allocation failure.
>> - Fix the device specific i2c muxes that I had overlooked.
>> - Rebased on top of v4.4-rc8 (was based on v4.4-rc6 previously).
>>
>> Cheers,
>> Peter
>>
>> Peter Rosin (8):
>>    i2c-mux: add common core data for every mux instance
>>    i2c-mux: move select and deselect ops to i2c_mux_core
>>    i2c-mux: move the slave side adapter management to i2c_mux_core
>>    i2c-mux: remove the mux dev pointer from the mux per channel data
>>    i2c-mux: pinctrl: get rid of the driver private struct device pointer
>>    i2c: allow adapter drivers to override the adapter locking
>>    i2c: muxes always lock the parent adapter
>>    i2c-mux: relax locking of the top i2c adapter during i2c controlled
>>      muxing
>>
>>   .../devicetree/bindings/i2c/i2c-mux-gpio.txt       |   2 +
>>   .../devicetree/bindings/i2c/i2c-mux-pinctrl.txt    |   4 +
>>   drivers/i2c/i2c-core.c                             |  59 ++---
>>   drivers/i2c/i2c-mux.c                              | 272 +++++++++++++++++----
>>   drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
>>   drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
>>   drivers/i2c/muxes/i2c-mux-pca9541.c                |  58 +++--
>>   drivers/i2c/muxes/i2c-mux-pca954x.c                |  66 ++---
>>   drivers/i2c/muxes/i2c-mux-pinctrl.c                |  89 +++----
>>   drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c         |  33 +--
>>   drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h          |   2 +-
>>   drivers/media/dvb-frontends/m88ds3103.c            |  23 +-
>>   drivers/media/dvb-frontends/m88ds3103_priv.h       |   2 +-
>>   drivers/media/dvb-frontends/rtl2830.c              |  24 +-
>>   drivers/media/dvb-frontends/rtl2830_priv.h         |   2 +-
>>   drivers/media/dvb-frontends/rtl2832.c              |  30 ++-
>>   drivers/media/dvb-frontends/rtl2832_priv.h         |   2 +-
>>   drivers/media/dvb-frontends/si2168.c               |  29 ++-
>>   drivers/media/dvb-frontends/si2168_priv.h          |   2 +-
>>   drivers/media/usb/cx231xx/cx231xx-core.c           |   6 +-
>>   drivers/media/usb/cx231xx/cx231xx-i2c.c            |  48 ++--
>>   drivers/media/usb/cx231xx/cx231xx.h                |   4 +-
>>   drivers/of/unittest.c                              |  41 ++--
>>   include/linux/i2c-mux-gpio.h                       |   2 +
>>   include/linux/i2c-mux-pinctrl.h                    |   2 +
>>   include/linux/i2c-mux.h                            |  39 ++-
>>   include/linux/i2c.h                                |  28 ++-
>>   28 files changed, 612 insertions(+), 424 deletions(-)
>>
> 
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
  2016-01-06 14:49     ` Rob Herring
@ 2016-01-07  8:21       ` Peter Rosin
  -1 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-07  8:21 UTC (permalink / raw)
  To: Rob Herring
  Cc: Wolfram Sang, Peter Rosin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Rob,

On 2016-01-06 15:49, Rob Herring wrote:
> On Tue, Jan 05, 2016 at 04:57:18PM +0100, Peter Rosin wrote:
>> From: Peter Rosin <peda@axentia.se>
>>
>> With a i2c topology like the following
>>
>>                        GPIO ---|  ------ BAT1
>>                         |      v /
>>    I2C  -----+----------+---- MUX
>>              |                   \
>>            EEPROM                 ------ BAT2
> 
> Yuck. One would think you would just use an I2C controlled mux in this 
> case...
>  
>> there is a locking problem with the GPIO controller since it is a client
>> on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
>> will lock the whole i2c bus prior to attempting to switch the mux to the
>> correct i2c segment. In the above case, the GPIO device is an I/O expander
>> with an i2c interface, and since the GPIO subsystem knows nothing (and
>> rightfully so) about the lockless needs of the i2c mux code, this results
>> in a deadlock when the GPIO driver issues i2c transfers to modify the
>> mux.
>>
>> So, observing that while it is needed to have the i2c bus locked during the
>> actual MUX update in order to avoid random garbage on the slave side, it
>> is not strictly a must to have it locked over the whole sequence of a full
>> select-transfer-deselect mux client operation. The mux itself needs to be
>> locked, so transfers to clients behind the mux are serialized, and the mux
>> needs to be stable during all i2c traffic (otherwise individual mux slave
>> segments might see garbage, or worse).
>>
>> Add devive tree properties (bool named i2c-controlled) to i2c-mux-gpio and
>> i2c-mux-pinctrl that asserts that the the gpio/pinctrl is controlled via
>> the same i2c bus that it muxes.
> 
> Can't you determine this condition by checking the mux parent and gpio 
> parent are the same i2c controller?

Good suggestion, I wrote code that implements this, and will include it in
v3. Do not expect v3 to hit the dt crowd though, since no dt changes will
be needed then, but I'm sure that is not a problem...

> Alternatively, can't you just always do the locking like i2c-controlled 
> is set when a mux is involved? What is the harm in doing that if the 
> GPIO is controlled somewhere else?

No, that is not possible. If you change a non-i2c-controlled gpio in the
middle of some i2c-access, the slave side of the mux might see partial
i2c transfers, and that is a recipe for disaster.

> I would prefer to see a solution not requiring DT updates to fix and 
> this change seems like it is working around kernel issues.

Right, I'll make it so.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
@ 2016-01-07  8:21       ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-01-07  8:21 UTC (permalink / raw)
  To: Rob Herring
  Cc: Wolfram Sang, Peter Rosin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c

Hi Rob,

On 2016-01-06 15:49, Rob Herring wrote:
> On Tue, Jan 05, 2016 at 04:57:18PM +0100, Peter Rosin wrote:
>> From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>
>> With a i2c topology like the following
>>
>>                        GPIO ---|  ------ BAT1
>>                         |      v /
>>    I2C  -----+----------+---- MUX
>>              |                   \
>>            EEPROM                 ------ BAT2
> 
> Yuck. One would think you would just use an I2C controlled mux in this 
> case...
>  
>> there is a locking problem with the GPIO controller since it is a client
>> on the same i2c bus that it muxes. Transfers to the mux clients (e.g. BAT1)
>> will lock the whole i2c bus prior to attempting to switch the mux to the
>> correct i2c segment. In the above case, the GPIO device is an I/O expander
>> with an i2c interface, and since the GPIO subsystem knows nothing (and
>> rightfully so) about the lockless needs of the i2c mux code, this results
>> in a deadlock when the GPIO driver issues i2c transfers to modify the
>> mux.
>>
>> So, observing that while it is needed to have the i2c bus locked during the
>> actual MUX update in order to avoid random garbage on the slave side, it
>> is not strictly a must to have it locked over the whole sequence of a full
>> select-transfer-deselect mux client operation. The mux itself needs to be
>> locked, so transfers to clients behind the mux are serialized, and the mux
>> needs to be stable during all i2c traffic (otherwise individual mux slave
>> segments might see garbage, or worse).
>>
>> Add devive tree properties (bool named i2c-controlled) to i2c-mux-gpio and
>> i2c-mux-pinctrl that asserts that the the gpio/pinctrl is controlled via
>> the same i2c bus that it muxes.
> 
> Can't you determine this condition by checking the mux parent and gpio 
> parent are the same i2c controller?

Good suggestion, I wrote code that implements this, and will include it in
v3. Do not expect v3 to hit the dt crowd though, since no dt changes will
be needed then, but I'm sure that is not a problem...

> Alternatively, can't you just always do the locking like i2c-controlled 
> is set when a mux is involved? What is the harm in doing that if the 
> GPIO is controlled somewhere else?

No, that is not possible. If you change a non-i2c-controlled gpio in the
middle of some i2c-access, the slave side of the mux might see partial
i2c transfers, and that is a recipe for disaster.

> I would prefer to see a solution not requiring DT updates to fix and 
> this change seems like it is working around kernel issues.

Right, I'll make it so.

Cheers,
Peter
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
  2016-01-05 15:57   ` Peter Rosin
@ 2016-03-24  9:50     ` Vladimir Zapolskiy
  -1 siblings, 0 replies; 52+ messages in thread
From: Vladimir Zapolskiy @ 2016-03-24  9:50 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Peter,

On 05.01.2016 17:57, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
> 
> The initial core mux structure starts off small with only the parent
> adapter pointer, which all muxes have, and a priv pointer for mux
> driver private data.
> 
> Add i2c_mux_alloc function to unify the creation of a mux.
> 
> Where appropriate, pass around the mux core structure instead of the
> parent adapter or the driver private data.
> 
> Remove the parent adapter pointer from the driver private data for all
> mux drivers.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>

is it still under review? If yes, please find one question from me below :)

[snip]

> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>  		dev_err(dev, "Cannot parse i2c-parent\n");
>  		return -EINVAL;
>  	}
> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);

why do you prefer here to use "unlocked" version of API?

Foe example would it be safe/possible to unload an I2C bus device driver
module or unbind I2C device itself in runtime?

>  	of_node_put(parent_np);
> -	if (!arb->parent) {
> +	if (!muxc->parent) {
>  		dev_err(dev, "Cannot find parent bus\n");
>  		return -EPROBE_DEFER;
>  	}
>  
>  	/* Actually add the mux adapter */
> -	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
> +	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
>  					 i2c_arbitrator_select,
>  					 i2c_arbitrator_deselect);
>  	if (!arb->child) {
>  		dev_err(dev, "Failed to add adapter\n");
>  		ret = -ENODEV;
> -		i2c_put_adapter(arb->parent);
> +		i2c_put_adapter(muxc->parent);
>  	}
>  
>  	return ret;

--
With best wishes,
Vladimir

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24  9:50     ` Vladimir Zapolskiy
  0 siblings, 0 replies; 52+ messages in thread
From: Vladimir Zapolskiy @ 2016-03-24  9:50 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire

Hi Peter,

On 05.01.2016 17:57, Peter Rosin wrote:
> From: Peter Rosin <peda@axentia.se>
> 
> The initial core mux structure starts off small with only the parent
> adapter pointer, which all muxes have, and a priv pointer for mux
> driver private data.
> 
> Add i2c_mux_alloc function to unify the creation of a mux.
> 
> Where appropriate, pass around the mux core structure instead of the
> parent adapter or the driver private data.
> 
> Remove the parent adapter pointer from the driver private data for all
> mux drivers.
> 
> Signed-off-by: Peter Rosin <peda@axentia.se>

is it still under review? If yes, please find one question from me below :)

[snip]

> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>  		dev_err(dev, "Cannot parse i2c-parent\n");
>  		return -EINVAL;
>  	}
> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);

why do you prefer here to use "unlocked" version of API?

Foe example would it be safe/possible to unload an I2C bus device driver
module or unbind I2C device itself in runtime?

>  	of_node_put(parent_np);
> -	if (!arb->parent) {
> +	if (!muxc->parent) {
>  		dev_err(dev, "Cannot find parent bus\n");
>  		return -EPROBE_DEFER;
>  	}
>  
>  	/* Actually add the mux adapter */
> -	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
> +	arb->child = i2c_add_mux_adapter(muxc, dev, arb, 0, 0, 0,
>  					 i2c_arbitrator_select,
>  					 i2c_arbitrator_deselect);
>  	if (!arb->child) {
>  		dev_err(dev, "Failed to add adapter\n");
>  		ret = -ENODEV;
> -		i2c_put_adapter(arb->parent);
> +		i2c_put_adapter(muxc->parent);
>  	}
>  
>  	return ret;

--
With best wishes,
Vladimir

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24 11:05       ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-03-24 11:05 UTC (permalink / raw)
  To: Vladimir Zapolskiy
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Vladimir,

On 2016-03-24 10:50, Vladimir Zapolskiy wrote:
> Hi Peter,
> 
> On 05.01.2016 17:57, Peter Rosin wrote:
>> From: Peter Rosin <peda@axentia.se>
>>
>> The initial core mux structure starts off small with only the parent
>> adapter pointer, which all muxes have, and a priv pointer for mux
>> driver private data.
>>
>> Add i2c_mux_alloc function to unify the creation of a mux.
>>
>> Where appropriate, pass around the mux core structure instead of the
>> parent adapter or the driver private data.
>>
>> Remove the parent adapter pointer from the driver private data for all
>> mux drivers.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
> 
> is it still under review? If yes, please find one question from me below :)

Yes, the series is still under review/testing, with an update planned in a
week or so.

> [snip]
> 
>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>  		dev_err(dev, "Cannot parse i2c-parent\n");
>>  		return -EINVAL;
>>  	}
>> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
>> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
> 
> why do you prefer here to use "unlocked" version of API?
> 
> Foe example would it be safe/possible to unload an I2C bus device driver
> module or unbind I2C device itself in runtime?

I think you ask why I change from of_get_i2c_... to of_find_i2c_..., and that
change was not intentional. It was the result of a bad merge during an early
rebase.

Does that cover it?

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24 11:05       ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-03-24 11:05 UTC (permalink / raw)
  To: Vladimir Zapolskiy
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire

Hi Vladimir,

On 2016-03-24 10:50, Vladimir Zapolskiy wrote:
> Hi Peter,
> 
> On 05.01.2016 17:57, Peter Rosin wrote:
>> From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>
>> The initial core mux structure starts off small with only the parent
>> adapter pointer, which all muxes have, and a priv pointer for mux
>> driver private data.
>>
>> Add i2c_mux_alloc function to unify the creation of a mux.
>>
>> Where appropriate, pass around the mux core structure instead of the
>> parent adapter or the driver private data.
>>
>> Remove the parent adapter pointer from the driver private data for all
>> mux drivers.
>>
>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
> 
> is it still under review? If yes, please find one question from me below :)

Yes, the series is still under review/testing, with an update planned in a
week or so.

> [snip]
> 
>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>  		dev_err(dev, "Cannot parse i2c-parent\n");
>>  		return -EINVAL;
>>  	}
>> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
>> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
> 
> why do you prefer here to use "unlocked" version of API?
> 
> Foe example would it be safe/possible to unload an I2C bus device driver
> module or unbind I2C device itself in runtime?

I think you ask why I change from of_get_i2c_... to of_find_i2c_..., and that
change was not intentional. It was the result of a bad merge during an early
rebase.

Does that cover it?

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24 14:24         ` Vladimir Zapolskiy
  0 siblings, 0 replies; 52+ messages in thread
From: Vladimir Zapolskiy @ 2016-03-24 14:24 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Peter,

On 24.03.2016 13:05, Peter Rosin wrote:
> Hi Vladimir,
> 
> On 2016-03-24 10:50, Vladimir Zapolskiy wrote:
>> Hi Peter,
>>
>> On 05.01.2016 17:57, Peter Rosin wrote:
>>> From: Peter Rosin <peda@axentia.se>
>>>
>>> The initial core mux structure starts off small with only the parent
>>> adapter pointer, which all muxes have, and a priv pointer for mux
>>> driver private data.
>>>
>>> Add i2c_mux_alloc function to unify the creation of a mux.
>>>
>>> Where appropriate, pass around the mux core structure instead of the
>>> parent adapter or the driver private data.
>>>
>>> Remove the parent adapter pointer from the driver private data for all
>>> mux drivers.
>>>
>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>
>> is it still under review? If yes, please find one question from me below :)
> 
> Yes, the series is still under review/testing, with an update planned in a
> week or so.
> 
>> [snip]
>>
>>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>>  		dev_err(dev, "Cannot parse i2c-parent\n");
>>>  		return -EINVAL;
>>>  	}
>>> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
>>> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>>
>> why do you prefer here to use "unlocked" version of API?
>>
>> Foe example would it be safe/possible to unload an I2C bus device driver
>> module or unbind I2C device itself in runtime?
> 
> I think you ask why I change from of_get_i2c_... to of_find_i2c_..., and that
> change was not intentional. It was the result of a bad merge during an early
> rebase.
> 
> Does that cover it?
> 

Yep, thank you for clarification, please account this in v3.

I'll try to find some time to review the whole changeset carefully,
in fact I briefly reviewed it two months ago, but I didn't find
anything obviously wrong that time.

--
With best wishes,
Vladimir

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24 14:24         ` Vladimir Zapolskiy
  0 siblings, 0 replies; 52+ messages in thread
From: Vladimir Zapolskiy @ 2016-03-24 14:24 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire

Hi Peter,

On 24.03.2016 13:05, Peter Rosin wrote:
> Hi Vladimir,
> 
> On 2016-03-24 10:50, Vladimir Zapolskiy wrote:
>> Hi Peter,
>>
>> On 05.01.2016 17:57, Peter Rosin wrote:
>>> From: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>>
>>> The initial core mux structure starts off small with only the parent
>>> adapter pointer, which all muxes have, and a priv pointer for mux
>>> driver private data.
>>>
>>> Add i2c_mux_alloc function to unify the creation of a mux.
>>>
>>> Where appropriate, pass around the mux core structure instead of the
>>> parent adapter or the driver private data.
>>>
>>> Remove the parent adapter pointer from the driver private data for all
>>> mux drivers.
>>>
>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>
>> is it still under review? If yes, please find one question from me below :)
> 
> Yes, the series is still under review/testing, with an update planned in a
> week or so.
> 
>> [snip]
>>
>>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>>  		dev_err(dev, "Cannot parse i2c-parent\n");
>>>  		return -EINVAL;
>>>  	}
>>> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
>>> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>>
>> why do you prefer here to use "unlocked" version of API?
>>
>> Foe example would it be safe/possible to unload an I2C bus device driver
>> module or unbind I2C device itself in runtime?
> 
> I think you ask why I change from of_get_i2c_... to of_find_i2c_..., and that
> change was not intentional. It was the result of a bad merge during an early
> rebase.
> 
> Does that cover it?
> 

Yep, thank you for clarification, please account this in v3.

I'll try to find some time to review the whole changeset carefully,
in fact I briefly reviewed it two months ago, but I didn't find
anything obviously wrong that time.

--
With best wishes,
Vladimir

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24 18:59           ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-03-24 18:59 UTC (permalink / raw)
  To: Vladimir Zapolskiy
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire,
	Olli Salonen, linux-i2c, devicetree, linux-kernel, linux-iio,
	linux-media

Hi Vladimir,

On 2016-03-24 15:24, Vladimir Zapolskiy wrote:
> On 24.03.2016 13:05, Peter Rosin wrote:
>> On 2016-03-24 10:50, Vladimir Zapolskiy wrote:
>>> On 05.01.2016 17:57, Peter Rosin wrote:
>>>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>>>  		dev_err(dev, "Cannot parse i2c-parent\n");
>>>>  		return -EINVAL;
>>>>  	}
>>>> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
>>>> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>>>
>>> why do you prefer here to use "unlocked" version of API?
>>>
>>> Foe example would it be safe/possible to unload an I2C bus device driver
>>> module or unbind I2C device itself in runtime?
>>
>> I think you ask why I change from of_get_i2c_... to of_find_i2c_..., and that
>> change was not intentional. It was the result of a bad merge during an early
>> rebase.
>>
>> Does that cover it?
>>
> 
> Yep, thank you for clarification, please account this in v3.

Oh , v3 is old news, v4 was sent out some weeks ago, and there is a v5
on a github branch. This bad rebase was fixed in v4.

> I'll try to find some time to review the whole changeset carefully,
> in fact I briefly reviewed it two months ago, but I didn't find
> anything obviously wrong that time.

Please put that on hold until I have rebased ontop of v4.6-rc1 and
changed a couple of other things. I'd hate for you to waste your
time on outdated patches.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-03-24 18:59           ` Peter Rosin
  0 siblings, 0 replies; 52+ messages in thread
From: Peter Rosin @ 2016-03-24 18:59 UTC (permalink / raw)
  To: Vladimir Zapolskiy
  Cc: Wolfram Sang, Peter Rosin, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Peter Korsgaard, Guenter Roeck,
	Jonathan Cameron, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, Antti Palosaari, Mauro Carvalho Chehab,
	Frank Rowand, Grant Likely, Adriana Reus, Srinivas Pandruvada,
	Krzysztof Kozlowski, Hans Verkuil, Nicholas Mc Guire

Hi Vladimir,

On 2016-03-24 15:24, Vladimir Zapolskiy wrote:
> On 24.03.2016 13:05, Peter Rosin wrote:
>> On 2016-03-24 10:50, Vladimir Zapolskiy wrote:
>>> On 05.01.2016 17:57, Peter Rosin wrote:
>>>> @@ -196,21 +195,21 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
>>>>  		dev_err(dev, "Cannot parse i2c-parent\n");
>>>>  		return -EINVAL;
>>>>  	}
>>>> -	arb->parent = of_get_i2c_adapter_by_node(parent_np);
>>>> +	muxc->parent = of_find_i2c_adapter_by_node(parent_np);
>>>
>>> why do you prefer here to use "unlocked" version of API?
>>>
>>> Foe example would it be safe/possible to unload an I2C bus device driver
>>> module or unbind I2C device itself in runtime?
>>
>> I think you ask why I change from of_get_i2c_... to of_find_i2c_..., and that
>> change was not intentional. It was the result of a bad merge during an early
>> rebase.
>>
>> Does that cover it?
>>
> 
> Yep, thank you for clarification, please account this in v3.

Oh , v3 is old news, v4 was sent out some weeks ago, and there is a v5
on a github branch. This bad rebase was fixed in v4.

> I'll try to find some time to review the whole changeset carefully,
> in fact I briefly reviewed it two months ago, but I didn't find
> anything obviously wrong that time.

Please put that on hold until I have rebased ontop of v4.6-rc1 and
changed a couple of other things. I'd hate for you to waste your
time on outdated patches.

Cheers,
Peter

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
  2016-03-24 18:59           ` Peter Rosin
@ 2016-04-11 20:59             ` Wolfram Sang
  -1 siblings, 0 replies; 52+ messages in thread
From: Wolfram Sang @ 2016-04-11 20:59 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Vladimir Zapolskiy, Peter Rosin, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Peter Korsgaard,
	Guenter Roeck, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire, Olli Salonen, linux-i2c, devicetree,
	linux-kernel, linux-iio, linux-media

[-- Attachment #1: Type: text/plain, Size: 468 bytes --]

Hi Vladimir,

> > I'll try to find some time to review the whole changeset carefully,
> > in fact I briefly reviewed it two months ago, but I didn't find
> > anything obviously wrong that time.
> 
> Please put that on hold until I have rebased ontop of v4.6-rc1 and
> changed a couple of other things. I'd hate for you to waste your
> time on outdated patches.

v6 is out now. Any help with reviewing/testing is much appreciated!

Thanks,

   Wolfram


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH v2 1/8] i2c-mux: add common core data for every mux instance
@ 2016-04-11 20:59             ` Wolfram Sang
  0 siblings, 0 replies; 52+ messages in thread
From: Wolfram Sang @ 2016-04-11 20:59 UTC (permalink / raw)
  To: Peter Rosin
  Cc: Vladimir Zapolskiy, Peter Rosin, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Peter Korsgaard,
	Guenter Roeck, Jonathan Cameron, Hartmut Knaack,
	Lars-Peter Clausen, Peter Meerwald, Antti Palosaari,
	Mauro Carvalho Chehab, Frank Rowand, Grant Likely, Adriana Reus,
	Srinivas Pandruvada, Krzysztof Kozlowski, Hans Verkuil,
	Nicholas Mc Guire

[-- Attachment #1: Type: text/plain, Size: 468 bytes --]

Hi Vladimir,

> > I'll try to find some time to review the whole changeset carefully,
> > in fact I briefly reviewed it two months ago, but I didn't find
> > anything obviously wrong that time.
> 
> Please put that on hold until I have rebased ontop of v4.6-rc1 and
> changed a couple of other things. I'd hate for you to waste your
> time on outdated patches.

v6 is out now. Any help with reviewing/testing is much appreciated!

Thanks,

   Wolfram


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2016-04-11 21:01 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-05 15:57 [PATCH v2 0/8] i2c mux cleanup and locking update Peter Rosin
2016-01-05 15:57 ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 1/8] i2c-mux: add common core data for every mux instance Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 16:42   ` Guenter Roeck
2016-01-05 16:42     ` Guenter Roeck
2016-01-05 18:55     ` Peter Rosin
2016-01-05 18:55       ` Peter Rosin
2016-03-24  9:50   ` Vladimir Zapolskiy
2016-03-24  9:50     ` Vladimir Zapolskiy
2016-03-24 11:05     ` Peter Rosin
2016-03-24 11:05       ` Peter Rosin
2016-03-24 14:24       ` Vladimir Zapolskiy
2016-03-24 14:24         ` Vladimir Zapolskiy
2016-03-24 18:59         ` Peter Rosin
2016-03-24 18:59           ` Peter Rosin
2016-04-11 20:59           ` Wolfram Sang
2016-04-11 20:59             ` Wolfram Sang
2016-01-05 15:57 ` [PATCH v2 2/8] i2c-mux: move select and deselect ops to i2c_mux_core Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 3/8] i2c-mux: move the slave side adapter management " Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 16:49   ` kbuild test robot
2016-01-05 16:49     ` kbuild test robot
2016-01-05 19:16     ` Peter Rosin
2016-01-05 19:16       ` Peter Rosin
2016-01-05 22:17   ` Peter Rosin
2016-01-05 22:17     ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 4/8] i2c-mux: remove the mux dev pointer from the mux per channel data Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 5/8] i2c-mux: pinctrl: get rid of the driver private struct device pointer Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 6/8] i2c: allow adapter drivers to override the adapter locking Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 7/8] i2c: muxes always lock the parent adapter Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-05 15:57 ` [PATCH v2 8/8] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing Peter Rosin
2016-01-05 15:57   ` Peter Rosin
2016-01-06 14:49   ` Rob Herring
2016-01-06 14:49     ` Rob Herring
2016-01-07  8:21     ` Peter Rosin
2016-01-07  8:21       ` Peter Rosin
2016-01-05 18:48 ` [PATCH v2 0/8] i2c mux cleanup and locking update Wolfram Sang
2016-01-05 18:48   ` Wolfram Sang
2016-01-05 19:01   ` Peter Rosin
2016-01-05 19:01     ` Peter Rosin
2016-01-06 13:23   ` Crt Mori
2016-01-06 13:23     ` Crt Mori
2016-01-06 17:17 ` Antti Palosaari
2016-01-06 17:17   ` Antti Palosaari
2016-01-07  8:14   ` Peter Rosin
2016-01-07  8:14     ` Peter Rosin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.