Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1300805 > unrolled thread

[PATCH 00/10] i2c mux cleanup and locking update

Started byPeter Rosin <peda@lysator.liu.se>
First post2016-01-04 16:20 +0100
Last post2016-01-04 16:20 +0100
Articles 13 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/10] i2c mux cleanup and locking update Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 07/10] i2c: muxes always lock the parent adapter Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
      Re: [PATCH 02/10] i2c-mux: move select and deselect ops to  i2c_mux_core kbuild test robot <lkp@intel.com> - 2016-01-04 17:00 +0100
      Re: [PATCH 02/10] i2c-mux: move select and deselect ops to  i2c_mux_core kbuild test robot <lkp@intel.com> - 2016-01-04 17:00 +0100
      Re: [PATCH 02/10] i2c-mux: move select and deselect ops to  i2c_mux_core kbuild test robot <lkp@intel.com> - 2016-01-04 17:10 +0100
      Re: [PATCH 02/10] i2c-mux: move select and deselect ops to  i2c_mux_core kbuild test robot <lkp@intel.com> - 2016-01-04 17:10 +0100
    [PATCH 10/10] i2c: pca954x: get rid of the i2c deadlock workaround Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 05/10] i2c-mux: pinctrl: get rid of the driver private struct device pointer Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 09/10] i2c: pca9541: get rid of the i2c deadlock workaround Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 08/10] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 04/10] i2c-mux: remove the mux dev pointer from the mux per channel data Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100
    [PATCH 03/10] i2c-mux: move the slave side adapter management to i2c_mux_core Peter Rosin <peda@lysator.liu.se> - 2016-01-04 16:20 +0100

#1300805 — [PATCH 00/10] i2c mux cleanup and locking update

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 00/10] i2c mux cleanup and locking update
Message-ID<qNf5n-59c-5@gated-at.bofh.it>
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 second half of the series, with the real meat
in 8/10. The tail of the series cleans up the open-coded unlocked i2c-
transfers in the pca9541 and pca954x drivers.

Further work: Looking at i2c_adapter_lock users in drivers/, it seems that
at least some of them are there just so that the driver can work behind an
i2c controlled mux (e.g. media/dvb-frontends/rtl2830.c). Those kind of
kludges can be removed. Other users lump several transfers together to
prevent mishaps, and at least some of those could probably be converted to
lock the i2c segment instead of the master bus adapter, so that the driver
doesn't deadlock even if the device sits behind an i2c controlled mux.

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

Cheers,
Peter

Peter Rosin (10):
  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
  i2c: pca9541: get rid of the i2c deadlock workaround
  i2c: pca954x: get rid of the i2c deadlock workaround

 .../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                              | 279 +++++++++++++++++----
 drivers/i2c/muxes/i2c-arb-gpio-challenge.c         |  46 ++--
 drivers/i2c/muxes/i2c-mux-gpio.c                   |  58 ++---
 drivers/i2c/muxes/i2c-mux-pca9541.c                | 141 ++++-------
 drivers/i2c/muxes/i2c-mux-pca954x.c                | 104 ++++----
 drivers/i2c/muxes/i2c-mux-pinctrl.c                |  85 +++----
 drivers/i2c/muxes/i2c-mux-reg.c                    |  63 ++---
 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 ++-
 14 files changed, 524 insertions(+), 388 deletions(-)

-- 
2.1.4

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

[toc] | [next] | [standalone]


#1300807 — [PATCH 07/10] i2c: muxes always lock the parent adapter

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 07/10] i2c: muxes always lock the parent adapter
Message-ID<qNf5o-59c-23@gated-at.bofh.it>
In reply to#1300805
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 b507a799f222..605333757a5e 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;
@@ -188,6 +212,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

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

[toc] | [prev] | [next] | [standalone]


#1300810 — [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core
Message-ID<qNf5o-59c-35@gated-at.bofh.it>
In reply to#1300805
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 +++++++++-----------
 include/linux/i2c-mux.h                    | 15 ++++++++-------
 8 files changed, 81 insertions(+), 91 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 99fd9106abc6..00ffbdba2cf8 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;
 }
@@ -116,6 +111,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 		if (!muxc->priv)
 			goto fail;
 	}
+	muxc->dev = dev;
 	return muxc;
 
 fail:
@@ -125,13 +121,9 @@ fail:
 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;
@@ -145,10 +137,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 dd616c0280ad..1c4741cf290f 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);
@@ -142,6 +141,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)) {
@@ -205,9 +207,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 3de6dc79c1db..bd000406e160 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;
 
@@ -182,6 +181,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,
@@ -195,10 +195,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++) {
@@ -224,9 +224,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 b2525a772d3b..178c22981636 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;
 }
@@ -345,6 +348,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.
@@ -359,10 +364,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 00eda06a667e..edc6693ffea9 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);
 }
 
 /*
@@ -225,6 +229,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 */
 
@@ -246,13 +252,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 cd3b73e208ce..79bd1ea75444 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));
@@ -204,10 +201,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) {
@@ -222,9 +220,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 76244aca154e..d85879c46d90 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;
 
@@ -227,19 +224,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/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

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

[toc] | [prev] | [next] | [standalone]


#1300846 — Re: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core

Fromkbuild test robot <lkp@intel.com>
Date2016-01-04 17:00 +0100
SubjectRe: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core
Message-ID<qNfI7-5oL-21@gated-at.bofh.it>
In reply to#1300810

[Multipart message — attachments visible in raw view] — view raw

Hi Peter,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.4-rc8 next-20160104]
[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/20160104-231355
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: x86_64-randconfig-i0-201601 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All error/warnings (new ones prefixed by >>):

   drivers/media/dvb-frontends/m88ds3103.c: In function 'm88ds3103_probe':
   drivers/media/dvb-frontends/m88ds3103.c:1470:41: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                                            ^
   In file included from drivers/media/dvb-frontends/m88ds3103_priv.h:24:0,
                    from drivers/media/dvb-frontends/m88ds3103.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/media/dvb-frontends/m88ds3103.c:1471:13: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
                dev, 0, 0, 0, m88ds3103_select,
                ^
   In file included from drivers/media/dvb-frontends/m88ds3103_priv.h:24:0,
                    from drivers/media/dvb-frontends/m88ds3103.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct m88ds3103_dev *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/media/dvb-frontends/m88ds3103.c:1470:21: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                        ^
   In file included from drivers/media/dvb-frontends/m88ds3103_priv.h:24:0,
                    from drivers/media/dvb-frontends/m88ds3103.c:17:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   drivers/media/dvb-frontends/rtl2830.c: In function 'rtl2830_probe':
   drivers/media/dvb-frontends/rtl2830.c:868:37: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                                        ^
   In file included from drivers/media/dvb-frontends/rtl2830_priv.h:24:0,
                    from drivers/media/dvb-frontends/rtl2830.c:18:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/media/dvb-frontends/rtl2830.c:869:4: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
       client, 0, 0, 0, rtl2830_select, NULL);
       ^
   In file included from drivers/media/dvb-frontends/rtl2830_priv.h:24:0,
                    from drivers/media/dvb-frontends/rtl2830.c:18:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct i2c_client *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/media/dvb-frontends/rtl2830.c:868:17: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                    ^
   In file included from drivers/media/dvb-frontends/rtl2830_priv.h:24:0,
                    from drivers/media/dvb-frontends/rtl2830.c:18:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^

vim +/i2c_add_mux_adapter +1470 drivers/media/dvb-frontends/m88ds3103.c

f01919e8f Antti Palosaari 2015-04-16  1464  		goto err_kfree;
56ea37da3 Antti Palosaari 2015-10-03  1465  	ret = m88ds3103_update_bits(dev, 0x23, 0x10, 0x10);
395d00d1c Antti Palosaari 2013-02-25  1466  	if (ret)
f01919e8f Antti Palosaari 2015-04-16  1467  		goto err_kfree;
395d00d1c Antti Palosaari 2013-02-25  1468  
44b9055b4 Antti Palosaari 2013-11-19  1469  	/* create mux i2c adapter for tuner */
f01919e8f Antti Palosaari 2015-04-16 @1470  	dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
f01919e8f Antti Palosaari 2015-04-16 @1471  					       dev, 0, 0, 0, m88ds3103_select,
478932b16 Antti Palosaari 2015-04-16  1472  					       NULL);
4347df6a7 Dan Carpenter   2015-06-02  1473  	if (dev->i2c_adapter == NULL) {
4347df6a7 Dan Carpenter   2015-06-02  1474  		ret = -ENOMEM;

:::::: The code at line 1470 was first introduced by commit
:::::: f01919e8f54f645fb00fdb823fe266e21eebe3b1 [media] m88ds3103: add I2C client binding

:::::: TO: Antti Palosaari <crope@iki.fi>
:::::: CC: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

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

[toc] | [prev] | [next] | [standalone]


#1300848 — Re: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core

Fromkbuild test robot <lkp@intel.com>
Date2016-01-04 17:00 +0100
SubjectRe: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core
Message-ID<qNfI7-5oL-23@gated-at.bofh.it>
In reply to#1300810

[Multipart message — attachments visible in raw view] — view raw

Hi Peter,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.4-rc8 next-20160104]
[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/20160104-231355
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: i386-randconfig-i0-01042049 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c: In function 'inv_mpu_probe':
   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:845:40: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     st->mux_adapter = i2c_add_mux_adapter(client->adapter,
                                           ^
   In file included from drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:26:0:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:847:12: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
               indio_dev,
               ^
   In file included from drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:26:0:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct iio_dev *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:845:20: error: too many arguments to function 'i2c_add_mux_adapter'
     st->mux_adapter = i2c_add_mux_adapter(client->adapter,
                       ^
   In file included from drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:26:0:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   drivers/of/unittest.c: In function 'unittest_i2c_mux_probe':
   drivers/of/unittest.c:1730:38: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
      stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
                                         ^
   In file included from drivers/of/unittest.c:24:0:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/of/unittest.c:1730:49: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
      stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
                                                    ^
   In file included from drivers/of/unittest.c:24:0:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct i2c_client *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/of/unittest.c:1730:18: error: too many arguments to function 'i2c_add_mux_adapter'
      stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
                     ^
   In file included from drivers/of/unittest.c:24:0:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^

vim +/i2c_add_mux_adapter +845 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c

09a642b7 Ge Gao              2013-02-02  839  	result = iio_device_register(indio_dev);
09a642b7 Ge Gao              2013-02-02  840  	if (result) {
09a642b7 Ge Gao              2013-02-02  841  		dev_err(&st->client->dev, "IIO register fail %d\n", result);
09a642b7 Ge Gao              2013-02-02  842  		goto out_remove_trigger;
09a642b7 Ge Gao              2013-02-02  843  	}
09a642b7 Ge Gao              2013-02-02  844  
3a2ecc3d Srinivas Pandruvada 2014-12-05 @845  	st->mux_adapter = i2c_add_mux_adapter(client->adapter,
3a2ecc3d Srinivas Pandruvada 2014-12-05  846  					      &client->dev,
3a2ecc3d Srinivas Pandruvada 2014-12-05 @847  					      indio_dev,
3a2ecc3d Srinivas Pandruvada 2014-12-05  848  					      0, 0, 0,
3a2ecc3d Srinivas Pandruvada 2014-12-05  849  					      inv_mpu6050_select_bypass,
3a2ecc3d Srinivas Pandruvada 2014-12-05  850  					      inv_mpu6050_deselect_bypass);

:::::: The code at line 845 was first introduced by commit
:::::: 3a2ecc3d2dce6e051b6afc319bb380c829e4e4fd iio: imu: inv_mpu6050: Add i2c mux for by pass

:::::: 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

[toc] | [prev] | [next] | [standalone]


#1300853 — Re: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core

Fromkbuild test robot <lkp@intel.com>
Date2016-01-04 17:10 +0100
SubjectRe: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core
Message-ID<qNfRM-5IQ-19@gated-at.bofh.it>
In reply to#1300810
Hi Peter,

[auto build test WARNING on wsa/i2c/for-next]
[also build test WARNING on v4.4-rc8 next-20160104]
[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/20160104-231355
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

   include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:845:46: sparse: too many arguments for function i2c_add_mux_adapter
   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c: In function 'inv_mpu_probe':
   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:845:40: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     st->mux_adapter = i2c_add_mux_adapter(client->adapter,
                                           ^
   In file included from drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:26:0:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:847:12: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
               indio_dev,
               ^
   In file included from drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:26:0:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct iio_dev *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:845:20: error: too many arguments to function 'i2c_add_mux_adapter'
     st->mux_adapter = i2c_add_mux_adapter(client->adapter,
                       ^
   In file included from drivers/iio/imu/inv_mpu6050/inv_mpu_core.c:26:0:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/media/dvb-frontends/si2168.c:712:43: sparse: too many arguments for function i2c_add_mux_adapter
   drivers/media/dvb-frontends/si2168.c: In function 'si2168_probe':
   drivers/media/dvb-frontends/si2168.c:712:37: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                                        ^
   In file included from drivers/media/dvb-frontends/si2168_priv.h:23:0,
                    from drivers/media/dvb-frontends/si2168.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/si2168.c:713:4: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
       client, 0, 0, 0, si2168_select, si2168_deselect);
       ^
   In file included from drivers/media/dvb-frontends/si2168_priv.h:23:0,
                    from drivers/media/dvb-frontends/si2168.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct i2c_client *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/si2168.c:712:17: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                    ^
   In file included from drivers/media/dvb-frontends/si2168_priv.h:23:0,
                    from drivers/media/dvb-frontends/si2168.c:17:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/media/dvb-frontends/m88ds3103.c:1470:47: sparse: too many arguments for function i2c_add_mux_adapter
   drivers/media/dvb-frontends/m88ds3103.c: In function 'm88ds3103_probe':
   drivers/media/dvb-frontends/m88ds3103.c:1470:41: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                                            ^
   In file included from drivers/media/dvb-frontends/m88ds3103_priv.h:24:0,
                    from drivers/media/dvb-frontends/m88ds3103.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/m88ds3103.c:1471:13: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
                dev, 0, 0, 0, m88ds3103_select,
                ^
   In file included from drivers/media/dvb-frontends/m88ds3103_priv.h:24:0,
                    from drivers/media/dvb-frontends/m88ds3103.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct m88ds3103_dev *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/m88ds3103.c:1470:21: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                        ^
   In file included from drivers/media/dvb-frontends/m88ds3103_priv.h:24:0,
                    from drivers/media/dvb-frontends/m88ds3103.c:17:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/media/dvb-frontends/rtl2830.c:868:43: sparse: too many arguments for function i2c_add_mux_adapter
   drivers/media/dvb-frontends/rtl2830.c: In function 'rtl2830_probe':
   drivers/media/dvb-frontends/rtl2830.c:868:37: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                                        ^
   In file included from drivers/media/dvb-frontends/rtl2830_priv.h:24:0,
                    from drivers/media/dvb-frontends/rtl2830.c:18:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/rtl2830.c:869:4: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
       client, 0, 0, 0, rtl2830_select, NULL);
       ^
   In file included from drivers/media/dvb-frontends/rtl2830_priv.h:24:0,
                    from drivers/media/dvb-frontends/rtl2830.c:18:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct i2c_client *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/rtl2830.c:868:17: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                    ^
   In file included from drivers/media/dvb-frontends/rtl2830_priv.h:24:0,
                    from drivers/media/dvb-frontends/rtl2830.c:18:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/media/dvb-frontends/rtl2832.c:1265:53: sparse: too many arguments for function i2c_add_mux_adapter
   drivers/media/dvb-frontends/rtl2832.c: In function 'rtl2832_probe':
   drivers/media/dvb-frontends/rtl2832.c:1265:47: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
                                                  ^
   In file included from drivers/media/dvb-frontends/rtl2832.h:26:0,
                    from drivers/media/dvb-frontends/rtl2832_priv.h:31,
                    from drivers/media/dvb-frontends/rtl2832.c:22:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/rtl2832.c:1265:63: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
     dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
                                                                  ^
   In file included from drivers/media/dvb-frontends/rtl2832.h:26:0,
                    from drivers/media/dvb-frontends/rtl2832_priv.h:31,
                    from drivers/media/dvb-frontends/rtl2832.c:22:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct rtl2832_dev *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/dvb-frontends/rtl2832.c:1265:27: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
                              ^
   In file included from drivers/media/dvb-frontends/rtl2832.h:26:0,
                    from drivers/media/dvb-frontends/rtl2832_priv.h:31,
                    from drivers/media/dvb-frontends/rtl2832.c:22:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
--
   include/linux/compiler.h:228:8: sparse: attribute 'no_sanitize_address': unknown attribute
>> drivers/media/usb/cx231xx/cx231xx-i2c.c:574:56: sparse: too many arguments for function i2c_add_mux_adapter
   drivers/media/usb/cx231xx/cx231xx-i2c.c: In function 'cx231xx_i2c_mux_register':
   drivers/media/usb/cx231xx/cx231xx-i2c.c:574:50: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
                                                     ^
   In file included from drivers/media/usb/cx231xx/cx231xx-i2c.c:27:0:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/usb/cx231xx/cx231xx-i2c.c:576:5: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
        dev /* mux_priv */,
        ^
   In file included from drivers/media/usb/cx231xx/cx231xx-i2c.c:27:0:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct cx231xx *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
   drivers/media/usb/cx231xx/cx231xx-i2c.c:574:30: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
                                 ^
   In file included from drivers/media/usb/cx231xx/cx231xx-i2c.c:27:0:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^

vim +845 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c

452204ae Sachin Kamat        2013-07-30  829  		return result;
09a642b7 Ge Gao              2013-02-02  830  	}
09a642b7 Ge Gao              2013-02-02  831  	result = inv_mpu6050_probe_trigger(indio_dev);
09a642b7 Ge Gao              2013-02-02  832  	if (result) {
09a642b7 Ge Gao              2013-02-02  833  		dev_err(&st->client->dev, "trigger probe fail %d\n", result);
09a642b7 Ge Gao              2013-02-02  834  		goto out_unreg_ring;
09a642b7 Ge Gao              2013-02-02  835  	}
09a642b7 Ge Gao              2013-02-02  836  
09a642b7 Ge Gao              2013-02-02  837  	INIT_KFIFO(st->timestamps);
09a642b7 Ge Gao              2013-02-02  838  	spin_lock_init(&st->time_stamp_lock);
09a642b7 Ge Gao              2013-02-02  839  	result = iio_device_register(indio_dev);
09a642b7 Ge Gao              2013-02-02  840  	if (result) {
09a642b7 Ge Gao              2013-02-02  841  		dev_err(&st->client->dev, "IIO register fail %d\n", result);
09a642b7 Ge Gao              2013-02-02  842  		goto out_remove_trigger;
09a642b7 Ge Gao              2013-02-02  843  	}
09a642b7 Ge Gao              2013-02-02  844  
3a2ecc3d Srinivas Pandruvada 2014-12-05 @845  	st->mux_adapter = i2c_add_mux_adapter(client->adapter,
3a2ecc3d Srinivas Pandruvada 2014-12-05  846  					      &client->dev,
3a2ecc3d Srinivas Pandruvada 2014-12-05  847  					      indio_dev,
3a2ecc3d Srinivas Pandruvada 2014-12-05  848  					      0, 0, 0,
3a2ecc3d Srinivas Pandruvada 2014-12-05  849  					      inv_mpu6050_select_bypass,
3a2ecc3d Srinivas Pandruvada 2014-12-05  850  					      inv_mpu6050_deselect_bypass);
3a2ecc3d Srinivas Pandruvada 2014-12-05  851  	if (!st->mux_adapter) {
3a2ecc3d Srinivas Pandruvada 2014-12-05  852  		result = -ENODEV;
3a2ecc3d Srinivas Pandruvada 2014-12-05  853  		goto out_unreg_device;

:::::: The code at line 845 was first introduced by commit
:::::: 3a2ecc3d2dce6e051b6afc319bb380c829e4e4fd iio: imu: inv_mpu6050: Add i2c mux for by pass

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

[toc] | [prev] | [next] | [standalone]


#1300854 — Re: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core

Fromkbuild test robot <lkp@intel.com>
Date2016-01-04 17:10 +0100
SubjectRe: [PATCH 02/10] i2c-mux: move select and deselect ops to i2c_mux_core
Message-ID<qNfRM-5IQ-15@gated-at.bofh.it>
In reply to#1300810

[Multipart message — attachments visible in raw view] — view raw

Hi Peter,

[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on v4.4-rc8 next-20160104]
[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/20160104-231355
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux i2c/for-next
config: x86_64-randconfig-s4-01042328 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All error/warnings (new ones prefixed by >>):

   drivers/media/dvb-frontends/si2168.c: In function 'si2168_probe':
   drivers/media/dvb-frontends/si2168.c:712:37: warning: passing argument 1 of 'i2c_add_mux_adapter' from incompatible pointer type [-Wincompatible-pointer-types]
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                                        ^
   In file included from drivers/media/dvb-frontends/si2168_priv.h:23:0,
                    from drivers/media/dvb-frontends/si2168.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'struct i2c_mux_core *' but argument is of type 'struct i2c_adapter *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/media/dvb-frontends/si2168.c:713:4: warning: passing argument 3 of 'i2c_add_mux_adapter' makes integer from pointer without a cast [-Wint-conversion]
       client, 0, 0, 0, si2168_select, si2168_deselect);
       ^
   In file included from drivers/media/dvb-frontends/si2168_priv.h:23:0,
                    from drivers/media/dvb-frontends/si2168.c:17:
   include/linux/i2c-mux.h:53:21: note: expected 'u32 {aka unsigned int}' but argument is of type 'struct i2c_client *'
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^
>> drivers/media/dvb-frontends/si2168.c:712:17: error: too many arguments to function 'i2c_add_mux_adapter'
     dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
                    ^
   In file included from drivers/media/dvb-frontends/si2168_priv.h:23:0,
                    from drivers/media/dvb-frontends/si2168.c:17:
   include/linux/i2c-mux.h:53:21: note: declared here
    struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
                        ^

vim +/i2c_add_mux_adapter +712 drivers/media/dvb-frontends/si2168.c

845f3505 Antti Palosaari 2014-04-10  706  		ret = -ENOMEM;
37b4e43d Olli Salonen    2014-08-05  707  		dev_err(&client->dev, "kzalloc() failed\n");
1ee5e7dd Antti Palosaari 2014-12-05  708  		goto err;
845f3505 Antti Palosaari 2014-04-10  709  	}
845f3505 Antti Palosaari 2014-04-10  710  
845f3505 Antti Palosaari 2014-04-10  711  	/* create mux i2c adapter for tuner */
6307b560 Antti Palosaari 2014-11-25 @712  	dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
6307b560 Antti Palosaari 2014-11-25 @713  			client, 0, 0, 0, si2168_select, si2168_deselect);
bd01c766 Antti Palosaari 2014-11-25  714  	if (dev->adapter == NULL) {
4d6efc7a Luis Alves      2014-07-17  715  		ret = -ENODEV;
346d4900 Antti Palosaari 2014-12-05  716  		goto err_kfree;

:::::: The code at line 712 was first introduced by commit
:::::: 6307b560800fd92b915a851186653317460039ad [media] si2168: carry pointer to client instead of state

:::::: TO: Antti Palosaari <crope@iki.fi>
:::::: CC: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

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

[toc] | [prev] | [next] | [standalone]


#1300812 — [PATCH 10/10] i2c: pca954x: get rid of the i2c deadlock workaround

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 10/10] i2c: pca954x: get rid of the i2c deadlock workaround
Message-ID<qNf5n-59c-7@gated-at.bofh.it>
In reply to#1300805
From: Peter Rosin <peda@axentia.se>

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index bd89da42b417..929ce28bc657 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -119,32 +119,19 @@ static const struct i2c_device_id pca954x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca954x_id);
 
-/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
-   for this as they will try to lock adapter a second time */
 static int pca954x_reg_write(struct i2c_adapter *adap,
 			     struct i2c_client *client, u8 val)
 {
-	int ret = -ENODEV;
-
-	if (adap->algo->master_xfer) {
-		struct i2c_msg msg;
-		char buf[1];
-
-		msg.addr = client->addr;
-		msg.flags = 0;
-		msg.len = 1;
-		buf[0] = val;
-		msg.buf = buf;
-		ret = __i2c_transfer(adap, &msg, 1);
-	} else {
-		union i2c_smbus_data data;
-		ret = adap->algo->smbus_xfer(adap, client->addr,
-					     client->flags,
-					     I2C_SMBUS_WRITE,
-					     val, I2C_SMBUS_BYTE, &data);
-	}
+	union i2c_smbus_data data;
 
-	return ret;
+	if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
+		return i2c_smbus_xfer(adap, client->addr, client->flags,
+				      I2C_SMBUS_WRITE, val,
+				      I2C_SMBUS_QUICK, NULL);
+	else
+		return i2c_smbus_xfer(adap, client->addr, client->flags,
+				      I2C_SMBUS_WRITE, val,
+				      I2C_SMBUS_BYTE, &data);
 }
 
 static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
@@ -227,6 +214,7 @@ static int pca954x_probe(struct i2c_client *client,
 		return -ENODEV;
 	}
 
+	muxc->i2c_controlled = true;
 	muxc->parent = adap;
 	muxc->select = pca954x_select_chan;
 	muxc->deselect = pca954x_deselect_mux;
-- 
2.1.4

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

[toc] | [prev] | [next] | [standalone]


#1300813 — [PATCH 05/10] i2c-mux: pinctrl: get rid of the driver private struct device pointer

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 05/10] i2c-mux: pinctrl: get rid of the driver private struct device pointer
Message-ID<qNf5o-59c-41@gated-at.bofh.it>
In reply to#1300805
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 | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 24c8f218760f..e27f66bf5341 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;
@@ -61,14 +61,14 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 
 	mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
 	if (!mux->pdata) {
-		dev_err(mux->dev,
+		dev_err(muxc->dev,
 			"Cannot allocate i2c_mux_pinctrl_platform_data\n");
 		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;
 	}
@@ -77,7 +77,7 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		sizeof(*mux->pdata->pinctrl_states) * num_names,
 		GFP_KERNEL);
 	if (!mux->pdata->pinctrl_states) {
-		dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
+		dev_err(muxc->dev, "Cannot allocate pinctrl_states\n");
 		return -ENOMEM;
 	}
 
@@ -85,14 +85,14 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		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 +103,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);
@@ -140,8 +140,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

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

[toc] | [prev] | [next] | [standalone]


#1300816 — [PATCH 09/10] i2c: pca9541: get rid of the i2c deadlock workaround

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 09/10] i2c: pca9541: get rid of the i2c deadlock workaround
Message-ID<qNf5p-59c-53@gated-at.bofh.it>
In reply to#1300805
From: Peter Rosin <peda@axentia.se>

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

diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index 9ee0d8b70283..7d2e5dbd8617 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -85,81 +85,28 @@ static const struct i2c_device_id pca9541_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, pca9541_id);
 
-/*
- * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
- * as they will try to lock the adapter a second time.
- */
 static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
 {
-	struct i2c_adapter *adap = client->adapter;
-	int ret;
-
-	if (adap->algo->master_xfer) {
-		struct i2c_msg msg;
-		char buf[2];
-
-		msg.addr = client->addr;
-		msg.flags = 0;
-		msg.len = 2;
-		buf[0] = command;
-		buf[1] = val;
-		msg.buf = buf;
-		ret = __i2c_transfer(adap, &msg, 1);
-	} else {
-		union i2c_smbus_data data;
-
-		data.byte = val;
-		ret = adap->algo->smbus_xfer(adap, client->addr,
-					     client->flags,
-					     I2C_SMBUS_WRITE,
-					     command,
-					     I2C_SMBUS_BYTE_DATA, &data);
-	}
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	union i2c_smbus_data data;
 
-	return ret;
+	data.byte = val;
+	return i2c_smbus_xfer(muxc->parent, client->addr, client->flags,
+			      I2C_SMBUS_WRITE, command,
+			      I2C_SMBUS_BYTE_DATA, &data);
 }
 
-/*
- * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
- * as they will try to lock adapter a second time.
- */
 static int pca9541_reg_read(struct i2c_client *client, u8 command)
 {
-	struct i2c_adapter *adap = client->adapter;
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	union i2c_smbus_data data;
 	int ret;
-	u8 val;
-
-	if (adap->algo->master_xfer) {
-		struct i2c_msg msg[2] = {
-			{
-				.addr = client->addr,
-				.flags = 0,
-				.len = 1,
-				.buf = &command
-			},
-			{
-				.addr = client->addr,
-				.flags = I2C_M_RD,
-				.len = 1,
-				.buf = &val
-			}
-		};
-		ret = __i2c_transfer(adap, msg, 2);
-		if (ret == 2)
-			ret = val;
-		else if (ret >= 0)
-			ret = -EIO;
-	} else {
-		union i2c_smbus_data data;
-
-		ret = adap->algo->smbus_xfer(adap, client->addr,
-					     client->flags,
-					     I2C_SMBUS_READ,
-					     command,
-					     I2C_SMBUS_BYTE_DATA, &data);
-		if (!ret)
-			ret = data.byte;
-	}
+
+	ret = i2c_smbus_xfer(muxc->parent, client->addr, client->flags,
+			     I2C_SMBUS_READ, command,
+			     I2C_SMBUS_BYTE_DATA, &data);
+	if (!ret)
+		ret = data.byte;
 	return ret;
 }
 
@@ -347,6 +294,7 @@ static int pca9541_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, muxc);
 
 	data->client = client;
+	muxc->i2c_controlled = true;
 	muxc->parent = adap;
 	muxc->select = pca9541_select_chan;
 	muxc->deselect = pca9541_release_chan;
-- 
2.1.4

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

[toc] | [prev] | [next] | [standalone]


#1300818 — [PATCH 08/10] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 08/10] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing
Message-ID<qNf5p-59c-55@gated-at.bofh.it>
In reply to#1300805
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 605333757a5e..91066cfe5a95 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;
@@ -158,6 +238,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct device *dev, int sizeof_priv)
 			goto fail;
 	}
 	muxc->dev = dev;
+	rt_mutex_init(&muxc->bus_lock);
 	return muxc;
 
 fail:
@@ -196,10 +277,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 */
@@ -212,9 +301,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 4641ea0da516..af984d438fe1 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");
@@ -179,6 +181,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 e27f66bf5341..541c17567dbf 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -101,6 +101,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");
@@ -201,6 +203,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

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

[toc] | [prev] | [next] | [standalone]


#1300819 — [PATCH 04/10] i2c-mux: remove the mux dev pointer from the mux per channel data

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 04/10] i2c-mux: remove the mux dev pointer from the mux per channel data
Message-ID<qNf5p-59c-63@gated-at.bofh.it>
In reply to#1300805
From: Peter Rosin <peda@axentia.se>

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

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 +--
 include/linux/i2c-mux.h                    |  1 -
 8 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 84169a1c9c1b..b507a799f222 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;
 };
 
@@ -144,7 +143,6 @@ fail:
 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)
 {
@@ -169,7 +167,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
@@ -204,11 +201,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;
@@ -222,8 +219,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) {
@@ -240,12 +238,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));
 
@@ -266,7 +266,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 49aca5f26ebb..13379762d91a 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -206,7 +206,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 49b8d83fbc22..4641ea0da516 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -220,8 +220,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 791efe1d3dbc..9ee0d8b70283 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -364,7 +364,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 e3219ba9307c..bd89da42b417 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -262,8 +262,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 23792a1b2b3c..24c8f218760f 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -215,8 +215,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 73de562b7731..3624635f70ff 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -231,8 +231,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/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

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

[toc] | [prev] | [next] | [standalone]


#1300820 — [PATCH 03/10] i2c-mux: move the slave side adapter management to i2c_mux_core

FromPeter Rosin <peda@lysator.liu.se>
Date2016-01-04 16:20 +0100
Subject[PATCH 03/10] i2c-mux: move the slave side adapter management to i2c_mux_core
Message-ID<qNf5p-59c-59@gated-at.bofh.it>
In reply to#1300805
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        | 29 +++++-------
 drivers/i2c/muxes/i2c-mux-pinctrl.c        | 27 ++++--------
 drivers/i2c/muxes/i2c-mux-reg.c            | 26 ++++-------
 include/linux/i2c-mux.h                    | 15 ++++---
 8 files changed, 110 insertions(+), 104 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 00ffbdba2cf8..84169a1c9c1b 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;
@@ -120,19 +143,29 @@ fail:
 }
 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;
@@ -204,7 +237,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"),
@@ -216,23 +249,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 1c4741cf290f..49aca5f26ebb 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;
@@ -207,10 +206,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);
 	}
 
@@ -220,11 +218,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 bd000406e160..49b8d83fbc22 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;
 };
@@ -184,12 +183,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) {
+		dev_err(&pdev->dev, "Cannot allocate i2c_adapter structures\n");
 		goto alloc_failed;
 	}
 
@@ -224,10 +220,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;
 		}
@@ -239,8 +234,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--)
@@ -257,8 +251,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 178c22981636..791efe1d3dbc 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;
@@ -364,11 +364,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",
@@ -380,10 +379,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 edc6693ffea9..e3219ba9307c 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;
@@ -234,6 +233,13 @@ 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) {
+		dev_err(&client->dev,
+			"Cannot allocate i2c_adapter structures\n");
+		return ret;
+	}
+
 	idle_disconnect_dt = of_node &&
 		of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
 
@@ -256,12 +262,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);
@@ -277,24 +281,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 79bd1ea75444..23792a1b2b3c 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)
@@ -164,12 +163,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) {
+		dev_err(&pdev->dev, "Cannot reserve adapters\n");
 		goto err;
 	}
 
@@ -219,10 +215,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;
 		}
@@ -231,8 +226,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;
@@ -241,14 +235,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 d85879c46d90..73de562b7731 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;
 };
 
@@ -216,11 +215,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");
+	ret = i2c_mux_reserve_adapters(muxc, mux->data.n_values);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot allocate i2c_adapter structures\n");
 		return -ENOMEM;
 	}
 
@@ -234,11 +231,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;
 		}
@@ -250,8 +245,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;
 }
@@ -259,12 +253,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/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 5cd6e1e664e0..bfcdcc46f2a6 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -29,6 +29,9 @@
 
 struct i2c_mux_core {
 	struct i2c_adapter *parent;
+	struct i2c_adapter **adapter;
+	int adapters;
+	int max_adapters;
 	struct device *dev;
 
 	void *priv;
@@ -44,18 +47,20 @@ static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
 	return muxc->priv;
 }
 
+int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters);
+
 /*
  * Called to create a i2c bus on a multiplexed bus segment.
  * The mux_dev and chan_id parameters are passed to the select
  * and deselect callback functions to perform hardware-specific
  * mux control.
  */
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_mux_core *muxc,
-					struct device *mux_dev,
-					u32 force_nr, u32 chan_id,
-					unsigned int class);
+int i2c_add_mux_adapter(struct i2c_mux_core *muxc,
+			struct device *mux_dev,
+			u32 force_nr, u32 chan_id,
+			unsigned int class);
 
-void i2c_del_mux_adapter(struct i2c_adapter *adap);
+void i2c_del_mux_adapters(struct i2c_mux_core *muxc);
 
 #endif /* __KERNEL__ */
 
-- 
2.1.4

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

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web