2016-03-03 22:27:52

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 00/18] i2c mux cleanup and locking update

From: Peter Rosin <[email protected]>

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. 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 code to i2c-mux-gpio and
i2c-mux-pinctrl that determines if all involved devices used to update the
mux are controlled by the same root i2c adapter that is muxed. When this
is the case, the select-transfer-deselect operations should be locked
individually to avoid the deadlock. The i2c bus *is* still 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 i2c 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. But there is no risk for regressions, since
it did not work at all previously.
- When doing an i2c_transfer() in_atomic() context or 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. Again, no risk
for regressions.
- Is the detection of i2c-controlled gpios and pinctrls sane (i.e. the
usage of the new i2c_root_adapter() function in 18/18)?

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

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

v4 compared to v3:
- Rebase on top of v4.5-rc6.
- Update to add new i2c-mux interfaces in 01/18 including glue to implement
the old interfaces in terms of the new interfaces, then change the
mux users over to the new interfaces one by one (in 02/18 through 14/18),
and finally removing the old interfaces in 15/18. I.e. the first 15
patches of v4 replaces the first 5 patches of v3, with the following
points describing changes in the end result. Each patch is now touching
only one subsystem.
- Rename i2c_add_mux_adapter and i2c_del_mux_adapters to i2c_mux_add_adapter
and i2c_mux_del_adapters (so that the old functions can live on during the
transition).
- Make i2c_mux_alloc take a parent and the select/deselect ops as
arguments. Also add a flags argument to prevent churn later on.
- Add a new interface i2c_mux_one_adapter(). Make use of it in suitable
mux users with a single child adapter.
- Adjust to a rename in struct gpio_chip.
- Update a couple of comments to match the new code.

v3 compared to v2:
- Fix devm_kfree of a NULL pointer in i2c_mux_reserve_adapters().
- Remove device tree "i2c-controlled" property and determine this by walking
the dev tree instead.
- Fix compile problems with inv_mpu_acpi.c
- Wait with adding the client pointer to patch 2/8 for pca9541 and pca954x.

v2 compared to v1:
- Allocate mux core and (optional) priv in a combined allocation.
- Kill dev_err messages triggered by memory allocation failure.
- Fix the device specific i2c muxes that I had overlooked.
- Rebase on top of v4.4-rc8 (was based on v4.4-rc6 previously).
- Drop the last two patches in the series.

Cheers,
Peter

Peter Rosin (18):
i2c-mux: add common data for every i2c-mux instance
i2c: i2c-mux-gpio: convert to use an explicit i2c mux core
i2c: i2c-mux-pinctrl: convert to use an explicit i2c mux core
i2c: i2c-arb-gpio-challenge: convert to use an explicit i2c mux core
i2c: i2c-mux-pca9541: convert to use an explicit i2c mux core
i2c: i2c-mux-pca954x: convert to use an explicit i2c mux core
i2c: i2c-mux-reg: convert to use an explicit i2c mux core
iio: imu: inv_mpu6050: convert to use an explicit i2c mux core
[media] m88ds3103: convert to use an explicit i2c mux core
[media] rtl2830: convert to use an explicit i2c mux core
[media] rtl2832: convert to use an explicit i2c mux core
[media] si2168: convert to use an explicit i2c mux core
[media] cx231xx: convert to use an explicit i2c mux core
of/unittest: convert to use an explicit i2c mux core
i2c-mux: drop old unused i2c-mux api
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

drivers/i2c/i2c-core.c | 59 ++---
drivers/i2c/i2c-mux.c | 338 ++++++++++++++++++++++-----
drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 47 ++--
drivers/i2c/muxes/i2c-mux-gpio.c | 73 +++---
drivers/i2c/muxes/i2c-mux-pca9541.c | 55 ++---
drivers/i2c/muxes/i2c-mux-pca954x.c | 64 ++---
drivers/i2c/muxes/i2c-mux-pinctrl.c | 125 +++++-----
drivers/i2c/muxes/i2c-mux-reg.c | 63 ++---
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c | 2 +-
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 30 ++-
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 3 +-
drivers/media/dvb-frontends/m88ds3103.c | 18 +-
drivers/media/dvb-frontends/m88ds3103_priv.h | 2 +-
drivers/media/dvb-frontends/rtl2830.c | 17 +-
drivers/media/dvb-frontends/rtl2830_priv.h | 2 +-
drivers/media/dvb-frontends/rtl2832.c | 22 +-
drivers/media/dvb-frontends/rtl2832_priv.h | 2 +-
drivers/media/dvb-frontends/si2168.c | 22 +-
drivers/media/dvb-frontends/si2168_priv.h | 2 +-
drivers/media/usb/cx231xx/cx231xx-core.c | 6 +-
drivers/media/usb/cx231xx/cx231xx-i2c.c | 47 ++--
drivers/media/usb/cx231xx/cx231xx.h | 4 +-
drivers/of/unittest.c | 40 ++--
include/linux/i2c-mux.h | 65 ++++--
include/linux/i2c.h | 28 ++-
25 files changed, 703 insertions(+), 433 deletions(-)

--
2.1.4


2016-03-03 22:28:00

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 01/18] i2c-mux: add common data for every i2c-mux instance

From: Peter Rosin <[email protected]>

All i2c-muxes have a parent adapter and one or many child
adapters. A mux also has some means of selection. Previously,
this was stored per child adapter, but it is only needed
to keep track of this per mux.

Add an i2c mux core, that keeps track of this consistently.

Also add some glue for users of the old interface, which will
create one implicit mux core per child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/i2c-mux.c | 236 ++++++++++++++++++++++++++++++++++++++----------
include/linux/i2c-mux.h | 47 ++++++++++
2 files changed, 236 insertions(+), 47 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 00fc5b1c7b66..7df323a01661 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -28,33 +28,34 @@
#include <linux/acpi.h>

/* multiplexer per channel data */
+struct i2c_mux_priv_old {
+ void *mux_priv;
+ int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
+ int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
+};
+
struct i2c_mux_priv {
struct i2c_adapter adap;
struct i2c_algorithm algo;
-
- struct i2c_adapter *parent;
- struct device *mux_dev;
- void *mux_priv;
+ struct i2c_mux_core *muxc;
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,
struct i2c_msg msgs[], int num)
{
struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_adapter *parent = priv->parent;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
int ret;

/* Switch to the right mux port and perform the transfer. */

- 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;
}
@@ -65,17 +66,18 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
int size, union i2c_smbus_data *data)
{
struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_adapter *parent = priv->parent;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
int ret;

/* Select the right mux port and perform the transfer. */

- 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;
}
@@ -84,7 +86,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
static u32 i2c_mux_functionality(struct i2c_adapter *adap)
{
struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_adapter *parent = priv->parent;
+ struct i2c_adapter *parent = priv->muxc->parent;

return parent->algo->functionality(parent);
}
@@ -102,30 +104,80 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
return class;
}

-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
- struct 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))
+int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
+{
+ struct i2c_adapter **adapter;
+
+ if (adapters <= muxc->max_adapters)
+ return 0;
+
+ adapter = devm_kmalloc_array(muxc->dev,
+ adapters, sizeof(*adapter),
+ GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ if (muxc->adapter) {
+ memcpy(adapter, muxc->adapter,
+ muxc->max_adapters * sizeof(*adapter));
+ devm_kfree(muxc->dev, muxc->adapter);
+ }
+
+ muxc->adapter = adapter;
+ muxc->max_adapters = adapters;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_reserve_adapters);
+
+struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
+ struct device *dev, int sizeof_priv,
+ u32 flags,
+ int (*select)(struct i2c_mux_core *, u32),
+ int (*deselect)(struct i2c_mux_core *, u32))
{
+ struct i2c_mux_core *muxc;
+
+ muxc = devm_kzalloc(dev, sizeof(*muxc) + sizeof_priv, GFP_KERNEL);
+ if (!muxc)
+ return NULL;
+ if (sizeof_priv)
+ muxc->priv = muxc + 1;
+
+ muxc->parent = parent;
+ muxc->dev = dev;
+ muxc->select = select;
+ muxc->deselect = deselect;
+
+ return muxc;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_alloc);
+
+int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
+ 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->parent = parent;
- priv->mux_dev = mux_dev;
- priv->mux_priv = mux_priv;
+ priv->muxc = muxc;
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.
@@ -159,11 +211,11 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
* 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;
@@ -177,8 +229,9 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
/*
* 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) {
@@ -192,33 +245,122 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
"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"),
- "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));

- return &priv->adap;
+ muxc->adapter[muxc->adapters++] = &priv->adap;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_add_adapter);
+
+struct i2c_mux_core *i2c_mux_one_adapter(struct i2c_adapter *parent,
+ struct device *dev, int sizeof_priv,
+ u32 flags, u32 force_nr,
+ u32 chan_id, unsigned int class,
+ int (*select)(struct i2c_mux_core *,
+ u32),
+ int (*deselect)(struct i2c_mux_core *,
+ u32))
+{
+ struct i2c_mux_core *muxc;
+ int ret;
+
+ muxc = i2c_mux_alloc(parent, dev, sizeof_priv, flags, select, deselect);
+ if (!muxc)
+ return ERR_PTR(-ENOMEM);
+
+ ret = i2c_mux_add_adapter(muxc, force_nr, chan_id, class);
+ if (ret) {
+ devm_kfree(dev, muxc);
+ return ERR_PTR(ret);
+ }
+
+ return muxc;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_one_adapter);
+
+static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
+{
+ struct i2c_mux_priv_old *priv = i2c_mux_priv(muxc);
+
+ return priv->select(muxc->parent, priv->mux_priv, chan);
+}
+
+static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+ struct i2c_mux_priv_old *priv = i2c_mux_priv(muxc);
+
+ return priv->deselect(muxc->parent, priv->mux_priv, chan);
+}
+
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+ 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 i2c_mux_core *muxc;
+ struct i2c_mux_priv_old *priv;
+
+ muxc = i2c_mux_one_adapter(parent, mux_dev, sizeof(*priv), 0,
+ force_nr, chan_id, class,
+ i2c_mux_select,
+ deselect ? i2c_mux_deselect : NULL);
+ if (IS_ERR(muxc))
+ return NULL;
+
+ priv = i2c_mux_priv(muxc);
+ priv->select = select;
+ priv->deselect = deselect;
+ priv->mux_priv = mux_priv;
+
+ return muxc->adapter[0];
}
EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);

-void i2c_del_mux_adapter(struct i2c_adapter *adap)
+void i2c_mux_del_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;
+
+ muxc->adapter[muxc->adapters] = NULL;
+
+ snprintf(symlink_name, sizeof(symlink_name),
+ "channel-%u", priv->chan_id);
+ sysfs_remove_link(&muxc->dev->kobj, symlink_name);
+
+ sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
+ i2c_del_adapter(adap);
+ kfree(priv);
+ }
+}
+EXPORT_SYMBOL_GPL(i2c_mux_del_adapters);
+
+void i2c_del_mux_adapter(struct i2c_adapter *adap)
+{
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;

- sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
- i2c_del_adapter(adap);
- kfree(priv);
+ i2c_mux_del_adapters(muxc);
+ devm_kfree(muxc->dev, muxc->adapter);
+ devm_kfree(muxc->dev, muxc);
}
EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);

diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index b5f9a007a3ab..0d97d7a3f03c 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -27,6 +27,32 @@

#ifdef __KERNEL__

+struct i2c_mux_core {
+ struct i2c_adapter *parent;
+ struct i2c_adapter **adapter;
+ int adapters;
+ int max_adapters;
+ 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 i2c_adapter *parent,
+ struct device *dev, int sizeof_priv,
+ u32 flags,
+ int (*select)(struct i2c_mux_core *, u32),
+ int (*deselect)(struct i2c_mux_core *, u32));
+
+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
@@ -41,8 +67,29 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
void *mux_dev, u32 chan_id),
int (*deselect) (struct i2c_adapter *,
void *mux_dev, u32 chan_id));
+/*
+ * Called to create a i2c bus on a multiplexed bus segment.
+ * The chan_id parameter is passed to the select and deselect
+ * callback functions to perform hardware-specific mux control.
+ */
+int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
+ u32 force_nr, u32 chan_id,
+ unsigned int class);
+
+/*
+ * Allocate an i2c_mux_core and add one adapter with one call.
+ */
+struct i2c_mux_core *i2c_mux_one_adapter(struct i2c_adapter *parent,
+ struct device *dev, int sizeof_priv,
+ u32 flags, u32 force_nr,
+ u32 chan_id, unsigned int class,
+ int (*select)(struct i2c_mux_core *,
+ u32),
+ int (*deselect)(struct i2c_mux_core *,
+ u32));

void i2c_del_mux_adapter(struct i2c_adapter *adap);
+void i2c_mux_del_adapters(struct i2c_mux_core *muxc);

#endif /* __KERNEL__ */

--
2.1.4

2016-03-03 22:28:25

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 02/18] i2c: i2c-mux-gpio: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/muxes/i2c-mux-gpio.c | 54 ++++++++++++++++------------------------
1 file changed, 21 insertions(+), 33 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index b8e11c16d98c..1bcc26737359 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -18,8 +18,6 @@
#include <linux/of_gpio.h>

struct gpiomux {
- struct i2c_adapter *parent;
- struct i2c_adapter **adap; /* child busses */
struct i2c_mux_gpio_platform_data data;
unsigned gpio_base;
};
@@ -33,18 +31,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);

@@ -136,19 +134,19 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,

static int i2c_mux_gpio_probe(struct platform_device *pdev)
{
+ struct i2c_mux_core *muxc;
struct gpiomux *mux;
struct i2c_adapter *parent;
- int (*deselect) (struct i2c_adapter *, void *, u32);
unsigned initial_state, gpio_base;
int i, ret;

- mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
- if (!mux) {
- dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
+ muxc = i2c_mux_alloc(NULL, &pdev->dev, sizeof(*mux), 0,
+ i2c_mux_gpio_select, NULL);
+ if (!muxc)
return -ENOMEM;
- }
+ mux = i2c_mux_priv(muxc);

- platform_set_drvdata(pdev, mux);
+ platform_set_drvdata(pdev, muxc);

if (!dev_get_platdata(&pdev->dev)) {
ret = i2c_mux_gpio_probe_dt(mux, pdev);
@@ -180,24 +178,18 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
if (!parent)
return -EPROBE_DEFER;

- mux->parent = parent;
+ muxc->parent = parent;
mux->gpio_base = gpio_base;

- mux->adap = devm_kzalloc(&pdev->dev,
- sizeof(*mux->adap) * mux->data.n_values,
- GFP_KERNEL);
- if (!mux->adap) {
- dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
- ret = -ENOMEM;
+ ret = i2c_mux_reserve_adapters(muxc, mux->data.n_values);
+ if (ret)
goto alloc_failed;
- }

if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle;
- deselect = i2c_mux_gpio_deselect;
+ muxc->deselect = i2c_mux_gpio_deselect;
} else {
initial_state = mux->data.values[0];
- deselect = NULL;
}

for (i = 0; i < mux->data.n_gpios; i++) {
@@ -223,11 +215,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(parent, &pdev->dev, mux, nr,
- mux->data.values[i], class,
- i2c_mux_gpio_select, deselect);
- if (!mux->adap[i]) {
- ret = -ENODEV;
+ ret = i2c_mux_add_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;
}
@@ -239,8 +228,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_mux_del_adapters(muxc);
i = mux->data.n_gpios;
err_request_gpio:
for (; i > 0; i--)
@@ -253,16 +241,16 @@ alloc_failed:

static int i2c_mux_gpio_remove(struct platform_device *pdev)
{
- struct gpiomux *mux = platform_get_drvdata(pdev);
+ struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
+ struct gpiomux *mux = i2c_mux_priv(muxc);
int i;

- for (i = 0; i < mux->data.n_values; i++)
- i2c_del_mux_adapter(mux->adap[i]);
+ i2c_mux_del_adapters(muxc);

for (i = 0; i < mux->data.n_gpios; i++)
gpio_free(mux->gpio_base + mux->data.gpios[i]);

- i2c_put_adapter(mux->parent);
+ i2c_put_adapter(muxc->parent);

return 0;
}
--
2.1.4

2016-03-03 22:28:35

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 03/18] i2c: i2c-mux-pinctrl: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/muxes/i2c-mux-pinctrl.c | 86 +++++++++++++------------------------
1 file changed, 30 insertions(+), 56 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index b5a982ba8898..bbfabf4f52be 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -26,27 +26,22 @@
#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;
struct pinctrl_state *state_idle;
- struct i2c_adapter *parent;
- 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);
}
@@ -55,6 +50,7 @@ static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
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;
@@ -64,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
return 0;

mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
- if (!mux->pdata) {
- dev_err(mux->dev,
- "Cannot allocate i2c_mux_pinctrl_platform_data\n");
+ if (!mux->pdata)
return -ENOMEM;
- }

num_names = of_property_count_strings(np, "pinctrl-names");
if (num_names < 0) {
- dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+ dev_err(muxc->dev, "Cannot parse pinctrl-names: %d\n",
num_names);
return num_names;
}
@@ -80,23 +73,21 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
sizeof(*mux->pdata->pinctrl_states) * num_names,
GFP_KERNEL);
- if (!mux->pdata->pinctrl_states) {
- dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
+ if (!mux->pdata->pinctrl_states)
return -ENOMEM;
- }

for (i = 0; i < num_names; i++) {
ret = of_property_read_string_index(np, "pinctrl-names", i,
&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
if (ret < 0) {
- dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+ dev_err(muxc->dev, "Cannot parse pinctrl-names: %d\n",
ret);
return ret;
}
if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
"idle")) {
if (i != num_names - 1) {
- dev_err(mux->dev, "idle state must be last\n");
+ dev_err(muxc->dev, "idle state must be last\n");
return -EINVAL;
}
mux->pdata->pinctrl_state_idle = "idle";
@@ -107,13 +98,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,

adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) {
- dev_err(mux->dev, "Cannot parse i2c-parent\n");
+ dev_err(muxc->dev, "Cannot parse i2c-parent\n");
return -ENODEV;
}
adapter = of_find_i2c_adapter_by_node(adapter_np);
of_node_put(adapter_np);
if (!adapter) {
- dev_err(mux->dev, "Cannot find parent bus\n");
+ dev_err(muxc->dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}
mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
@@ -131,19 +122,18 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,

static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
{
+ struct i2c_mux_core *muxc;
struct i2c_mux_pinctrl *mux;
- int (*deselect)(struct i2c_adapter *, void *, u32);
int i, ret;

- mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
- if (!mux) {
- dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
+ muxc = i2c_mux_alloc(NULL, &pdev->dev, sizeof(*mux), 0,
+ i2c_mux_pinctrl_select, NULL);
+ if (!muxc) {
ret = -ENOMEM;
goto err;
}
- platform_set_drvdata(pdev, mux);
-
- mux->dev = &pdev->dev;
+ mux = i2c_mux_priv(muxc);
+ platform_set_drvdata(pdev, muxc);

mux->pdata = dev_get_platdata(&pdev->dev);
if (!mux->pdata) {
@@ -166,14 +156,9 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err;
}

- mux->busses = devm_kzalloc(&pdev->dev,
- sizeof(*mux->busses) * mux->pdata->bus_count,
- GFP_KERNEL);
- if (!mux->busses) {
- dev_err(&pdev->dev, "Cannot allocate busses\n");
- ret = -ENOMEM;
+ ret = i2c_mux_reserve_adapters(muxc, mux->pdata->bus_count);
+ if (ret)
goto err;
- }

mux->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(mux->pinctrl)) {
@@ -203,13 +188,11 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err;
}

- deselect = i2c_mux_pinctrl_deselect;
- } else {
- deselect = NULL;
+ muxc->deselect = i2c_mux_pinctrl_deselect;
}

- mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
- if (!mux->parent) {
+ muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
+ if (!muxc->parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
mux->pdata->parent_bus_num);
ret = -EPROBE_DEFER;
@@ -220,12 +203,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
u32 bus = mux->pdata->base_bus_num ?
(mux->pdata->base_bus_num + i) : 0;

- mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
- mux, bus, i, 0,
- i2c_mux_pinctrl_select,
- deselect);
- if (!mux->busses[i]) {
- ret = -ENODEV;
+ ret = i2c_mux_add_adapter(muxc, bus, i, 0);
+ if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto err_del_adapter;
}
@@ -234,23 +213,18 @@ 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_put_adapter(mux->parent);
+ i2c_mux_del_adapters(muxc);
+ i2c_put_adapter(muxc->parent);
err:
return ret;
}

static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
{
- struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < mux->pdata->bus_count; i++)
- i2c_del_mux_adapter(mux->busses[i]);
-
- i2c_put_adapter(mux->parent);
+ struct i2c_mux_core *muxc = platform_get_drvdata(pdev);

+ i2c_mux_del_adapters(muxc);
+ i2c_put_adapter(muxc->parent);
return 0;
}

--
2.1.4

2016-03-03 22:28:46

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 04/18] i2c: i2c-arb-gpio-challenge: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 47 +++++++++++++-----------------
1 file changed, 20 insertions(+), 27 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 402e3a6c671a..a42827b3c672 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -28,8 +28,6 @@
/**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
*
- * @parent: Parent adapter
- * @child: Child bus
* @our_gpio: GPIO we'll use to claim.
* @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released.
@@ -42,8 +40,6 @@
*/

struct i2c_arbitrator_data {
- struct i2c_adapter *parent;
- struct i2c_adapter *child;
int our_gpio;
int our_gpio_release;
int their_gpio;
@@ -59,9 +55,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 */
@@ -93,7 +89,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;
}

@@ -102,10 +98,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);
@@ -119,6 +114,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *parent_np;
+ struct i2c_mux_core *muxc;
struct i2c_arbitrator_data *arb;
enum of_gpio_flags gpio_flags;
unsigned long out_init;
@@ -134,12 +130,13 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
return -EINVAL;
}

- arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
- if (!arb) {
- dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
+ muxc = i2c_mux_alloc(NULL, dev, sizeof(*arb), 0,
+ i2c_arbitrator_select, i2c_arbitrator_deselect);
+ if (!muxc)
return -ENOMEM;
- }
- platform_set_drvdata(pdev, arb);
+ arb = i2c_mux_priv(muxc);
+
+ platform_set_drvdata(pdev, muxc);

/* Request GPIOs */
ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
@@ -196,21 +193,18 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
dev_err(dev, "Cannot parse i2c-parent\n");
return -EINVAL;
}
- arb->parent = of_get_i2c_adapter_by_node(parent_np);
+ muxc->parent = of_get_i2c_adapter_by_node(parent_np);
of_node_put(parent_np);
- if (!arb->parent) {
+ if (!muxc->parent) {
dev_err(dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}

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

return ret;
@@ -218,11 +212,10 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)

static int i2c_arbitrator_remove(struct platform_device *pdev)
{
- struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev);
-
- i2c_del_mux_adapter(arb->child);
- i2c_put_adapter(arb->parent);
+ struct i2c_mux_core *muxc = platform_get_drvdata(pdev);

+ i2c_mux_del_adapters(muxc);
+ i2c_put_adapter(muxc->parent);
return 0;
}

--
2.1.4

2016-03-03 22:28:53

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 05/18] i2c: i2c-mux-pca9541: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/muxes/i2c-mux-pca9541.c | 55 ++++++++++++++++---------------------
1 file changed, 23 insertions(+), 32 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index d0ba424adebc..93bea073ed13 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -73,7 +73,7 @@
#define SELECT_DELAY_LONG 1000

struct pca9541 {
- struct i2c_adapter *mux_adap;
+ struct i2c_client *client;
unsigned long select_timeout;
unsigned long arb_timeout;
};
@@ -217,7 +217,8 @@ static const u8 pca9541_control[16] = {
*/
static int pca9541_arbitrate(struct i2c_client *client)
{
- struct pca9541 *data = i2c_get_clientdata(client);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct pca9541 *data = i2c_mux_priv(muxc);
int reg;

reg = pca9541_reg_read(client, PCA9541_CONTROL);
@@ -285,9 +286,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 */
@@ -309,9 +311,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;
}
@@ -324,20 +328,12 @@ static int pca9541_probe(struct i2c_client *client,
{
struct i2c_adapter *adap = client->adapter;
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct i2c_mux_core *muxc;
struct pca9541 *data;
int force;
- int ret = -ENODEV;

if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
- goto err;
-
- data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
- if (!data) {
- ret = -ENOMEM;
- goto err;
- }
-
- i2c_set_clientdata(client, data);
+ return -ENODEV;

/*
* I2C accesses are unprotected here.
@@ -352,34 +348,29 @@ static int pca9541_probe(struct i2c_client *client,
force = 0;
if (pdata)
force = pdata->modes[0].adap_id;
- data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
- force, 0, 0,
- pca9541_select_chan,
- pca9541_release_chan);
-
- if (data->mux_adap == NULL) {
+ muxc = i2c_mux_one_adapter(adap, &client->dev, sizeof(*data), 0,
+ force, 0, 0,
+ pca9541_select_chan, pca9541_release_chan);
+ if (IS_ERR(muxc)) {
dev_err(&client->dev, "failed to register master selector\n");
- goto exit_free;
+ return PTR_ERR(muxc);
}
+ data = i2c_mux_priv(muxc);
+ data->client = client;
+
+ i2c_set_clientdata(client, muxc);

dev_info(&client->dev, "registered master selector for I2C %s\n",
client->name);

return 0;
-
-exit_free:
- kfree(data);
-err:
- return ret;
}

static int pca9541_remove(struct i2c_client *client)
{
- struct pca9541 *data = i2c_get_clientdata(client);
-
- i2c_del_mux_adapter(data->mux_adap);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);

- kfree(data);
+ i2c_mux_del_adapters(muxc);
return 0;
}

--
2.1.4

2016-03-03 22:29:03

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 06/18] i2c: i2c-mux-pca954x: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Add a mask to handle the case where not all child adapters should
cause a mux deselect to happen, now that there is a common deselect op
for all child adapters.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/muxes/i2c-mux-pca954x.c | 64 +++++++++++++++++++------------------
1 file changed, 33 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index acfcef3d4068..1693d29c11a4 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -60,9 +60,10 @@ 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;
+ struct i2c_client *client;
};

struct chip_desc {
@@ -146,10 +147,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;
@@ -162,21 +163,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);
}

/*
@@ -191,17 +195,21 @@ static int pca954x_probe(struct i2c_client *client,
bool idle_disconnect_dt;
struct gpio_desc *gpio;
int num, force, class;
+ struct i2c_mux_core *muxc;
struct pca954x *data;
int ret;

if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
return -ENODEV;

- data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
- if (!data)
+ muxc = i2c_mux_alloc(adap, &client->dev, sizeof(*data), 0,
+ pca954x_select_chan, pca954x_deselect_mux);
+ if (!muxc)
return -ENOMEM;
+ data = i2c_mux_priv(muxc);

- i2c_set_clientdata(client, data);
+ i2c_set_clientdata(client, muxc);
+ data->client = client;

/* Get the mux out of reset if a reset GPIO is specified. */
gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
@@ -220,6 +228,10 @@ static int pca954x_probe(struct i2c_client *client,
data->type = id->driver_data;
data->last_chan = 0; /* force the first selection */

+ ret = i2c_mux_reserve_adapters(muxc, chips[data->type].nchans);
+ if (ret)
+ return ret;
+
idle_disconnect_dt = of_node &&
of_property_read_bool(of_node, "i2c-mux-idle-disconnect");

@@ -238,16 +250,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(adap, &client->dev, client,
- force, num, class, pca954x_select_chan,
- (idle_disconnect_pd || idle_disconnect_dt)
- ? pca954x_deselect_mux : NULL);
+ ret = i2c_mux_add_adapter(muxc, 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);
@@ -263,23 +272,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_mux_del_adapters(muxc);
return ret;
}

static int pca954x_remove(struct i2c_client *client)
{
- struct pca954x *data = i2c_get_clientdata(client);
- 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;
- }
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);

+ i2c_mux_del_adapters(muxc);
return 0;
}

@@ -287,7 +288,8 @@ static int pca954x_remove(struct i2c_client *client)
static int pca954x_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- struct pca954x *data = i2c_get_clientdata(client);
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+ struct pca954x *data = i2c_mux_priv(muxc);

data->last_chan = 0;
return i2c_smbus_write_byte(client, 0);
--
2.1.4

2016-03-03 22:29:13

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 07/18] i2c: i2c-mux-reg: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/muxes/i2c-mux-reg.c | 63 ++++++++++++++++-------------------------
1 file changed, 24 insertions(+), 39 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 5fbd5bd0878f..3ac9a2dab111 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -21,8 +21,6 @@
#include <linux/slab.h>

struct regmux {
- struct i2c_adapter *parent;
- struct i2c_adapter **adap; /* child busses */
struct i2c_mux_reg_platform_data data;
};

@@ -64,18 +62,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);
@@ -87,6 +83,7 @@ static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
static int i2c_mux_reg_probe_dt(struct regmux *mux,
struct platform_device *pdev)
{
+ struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
struct i2c_adapter *adapter;
@@ -107,7 +104,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
if (!adapter)
return -EPROBE_DEFER;

- mux->parent = adapter;
+ muxc->parent = adapter;
mux->data.parent = i2c_adapter_id(adapter);
put_device(&adapter->dev);

@@ -169,18 +166,20 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,

static int i2c_mux_reg_probe(struct platform_device *pdev)
{
+ struct i2c_mux_core *muxc;
struct regmux *mux;
struct i2c_adapter *parent;
struct resource *res;
- int (*deselect)(struct i2c_adapter *, void *, u32);
unsigned int class;
int i, ret, nr;

- mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
- if (!mux)
+ muxc = i2c_mux_alloc(NULL, &pdev->dev, sizeof(*mux), 0,
+ i2c_mux_reg_select, NULL);
+ if (!muxc)
return -ENOMEM;
+ mux = i2c_mux_priv(muxc);

- platform_set_drvdata(pdev, mux);
+ platform_set_drvdata(pdev, muxc);

if (dev_get_platdata(&pdev->dev)) {
memcpy(&mux->data, dev_get_platdata(&pdev->dev),
@@ -190,7 +189,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
if (!parent)
return -EPROBE_DEFER;

- mux->parent = parent;
+ muxc->parent = parent;
} else {
ret = i2c_mux_reg_probe_dt(mux, pdev);
if (ret < 0) {
@@ -215,55 +214,41 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
return -EINVAL;
}

- mux->adap = devm_kzalloc(&pdev->dev,
- sizeof(*mux->adap) * mux->data.n_values,
- GFP_KERNEL);
- if (!mux->adap) {
- dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
- return -ENOMEM;
- }
+ ret = i2c_mux_reserve_adapters(muxc, mux->data.n_values);
+ if (ret)
+ return ret;

if (mux->data.idle_in_use)
- deselect = i2c_mux_reg_deselect;
- else
- deselect = NULL;
+ muxc->deselect = i2c_mux_reg_deselect;

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(mux->parent, &pdev->dev, mux,
- nr, mux->data.values[i],
- class, i2c_mux_reg_select,
- deselect);
- if (!mux->adap[i]) {
- ret = -ENODEV;
+ ret = i2c_mux_add_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;
}
}

dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
- mux->data.n_values, mux->parent->name);
+ mux->data.n_values, muxc->parent->name);

return 0;

add_adapter_failed:
- for (; i > 0; i--)
- i2c_del_mux_adapter(mux->adap[i - 1]);
+ i2c_mux_del_adapters(muxc);

return ret;
}

static int i2c_mux_reg_remove(struct platform_device *pdev)
{
- struct regmux *mux = platform_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < mux->data.n_values; i++)
- i2c_del_mux_adapter(mux->adap[i]);
+ struct i2c_mux_core *muxc = platform_get_drvdata(pdev);

- i2c_put_adapter(mux->parent);
+ i2c_mux_del_adapters(muxc);
+ i2c_put_adapter(muxc->parent);

return 0;
}
--
2.1.4

2016-03-03 22:29:24

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 08/18] iio: imu: inv_mpu6050: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c | 2 +-
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 30 +++++++++++++-----------------
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 3 ++-
3 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
index 1c982a56acd5..d433e7b64011 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
@@ -182,7 +182,7 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
} else
return 0; /* no secondary addr, which is OK */
}
- st->mux_client = i2c_new_device(st->mux_adapter, &info);
+ st->mux_client = i2c_new_device(st->muxc->adapter[0], &info);
if (!st->mux_client)
return -ENODEV;

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index f0e06093b5e8..642f22013d17 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,7 +23,6 @@
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
-#include <linux/i2c-mux.h>
#include <linux/acpi.h>
#include "inv_mpu_iio.h"

@@ -109,10 +108,9 @@ static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st,
return 0;
}

-static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
- u32 chan_id)
+static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
{
- struct iio_dev *indio_dev = mux_priv;
+ struct iio_dev *indio_dev = i2c_mux_priv(muxc);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int ret = 0;

@@ -138,10 +136,9 @@ write_error:
return ret;
}

-static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
- void *mux_priv, u32 chan_id)
+static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
{
- struct iio_dev *indio_dev = mux_priv;
+ struct iio_dev *indio_dev = i2c_mux_priv(muxc);
struct inv_mpu6050_state *st = iio_priv(indio_dev);

mutex_lock(&indio_dev->mlock);
@@ -842,16 +839,15 @@ static int inv_mpu_probe(struct i2c_client *client,
goto out_remove_trigger;
}

- st->mux_adapter = i2c_add_mux_adapter(client->adapter,
- &client->dev,
- indio_dev,
- 0, 0, 0,
- inv_mpu6050_select_bypass,
- inv_mpu6050_deselect_bypass);
- if (!st->mux_adapter) {
- result = -ENODEV;
+ st->muxc = i2c_mux_one_adapter(client->adapter, &client->dev, 0, 0,
+ 0, 0, 0,
+ inv_mpu6050_select_bypass,
+ inv_mpu6050_deselect_bypass);
+ if (IS_ERR(st->muxc)) {
+ result = PTR_ERR(st->muxc);
goto out_unreg_device;
}
+ st->muxc->priv = indio_dev;

result = inv_mpu_acpi_create_mux_client(st);
if (result)
@@ -860,7 +856,7 @@ static int inv_mpu_probe(struct i2c_client *client,
return 0;

out_del_mux:
- i2c_del_mux_adapter(st->mux_adapter);
+ i2c_mux_del_adapters(st->muxc);
out_unreg_device:
iio_device_unregister(indio_dev);
out_remove_trigger:
@@ -876,7 +872,7 @@ static int inv_mpu_remove(struct i2c_client *client)
struct inv_mpu6050_state *st = iio_priv(indio_dev);

inv_mpu_acpi_delete_mux_client(st);
- i2c_del_mux_adapter(st->mux_adapter);
+ i2c_mux_del_adapters(st->muxc);
iio_device_unregister(indio_dev);
inv_mpu6050_remove_trigger(st);
iio_triggered_buffer_cleanup(indio_dev);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index db0a4a2758ab..61a3a04b84b8 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
@@ -120,7 +121,7 @@ struct inv_mpu6050_state {
enum inv_devices chip_type;
spinlock_t time_stamp_lock;
struct i2c_client *client;
- struct i2c_adapter *mux_adapter;
+ struct i2c_mux_core *muxc;
struct i2c_client *mux_client;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
--
2.1.4

2016-03-03 22:29:34

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 10/18] [media] rtl2830: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select op to be in terms of the i2c mux core instead
of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/media/dvb-frontends/rtl2830.c | 17 +++++++++--------
drivers/media/dvb-frontends/rtl2830_priv.h | 2 +-
2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index b792f305cf15..0fa60fe09b81 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -677,9 +677,9 @@ err:
* adapter lock is already taken by tuner driver.
* Gate is closed automatically after single I2C transfer.
*/
-static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2830_select(struct i2c_mux_core *muxc, u32 chan_id)
{
- struct i2c_client *client = mux_priv;
+ struct i2c_client *client = i2c_mux_priv(muxc);
struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;

@@ -712,7 +712,7 @@ static struct i2c_adapter *rtl2830_get_i2c_adapter(struct i2c_client *client)

dev_dbg(&client->dev, "\n");

- return dev->adapter;
+ return dev->muxc->adapter[0];
}

/*
@@ -865,12 +865,13 @@ static int rtl2830_probe(struct i2c_client *client,
goto err_regmap_exit;

/* create muxed i2c adapter for tuner */
- dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
- client, 0, 0, 0, rtl2830_select, NULL);
- if (dev->adapter == NULL) {
- ret = -ENODEV;
+ dev->muxc = i2c_mux_one_adapter(client->adapter, &client->dev, 0, 0,
+ 0, 0, 0, rtl2830_select, NULL);
+ if (IS_ERR(dev->muxc)) {
+ ret = PTR_ERR(dev->muxc);
goto err_regmap_exit;
}
+ dev->muxc->priv = client;

/* create dvb frontend */
memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops));
@@ -900,7 +901,7 @@ static int rtl2830_remove(struct i2c_client *client)

dev_dbg(&client->dev, "\n");

- i2c_del_mux_adapter(dev->adapter);
+ i2c_mux_del_adapters(dev->muxc);
regmap_exit(dev->regmap);
kfree(dev);

diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
index cf793f39a09b..da4909543da2 100644
--- a/drivers/media/dvb-frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -29,7 +29,7 @@ struct rtl2830_dev {
struct rtl2830_platform_data *pdata;
struct i2c_client *client;
struct regmap *regmap;
- struct i2c_adapter *adapter;
+ struct i2c_mux_core *muxc;
struct dvb_frontend fe;
bool sleeping;
unsigned long filters;
--
2.1.4

2016-03-03 22:29:39

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 11/18] [media] rtl2832: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/media/dvb-frontends/rtl2832.c | 22 +++++++++++-----------
drivers/media/dvb-frontends/rtl2832_priv.h | 2 +-
2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 10f2119935da..775444898599 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -866,9 +866,9 @@ err:
dev_dbg(&client->dev, "failed=%d\n", ret);
}

-static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2832_select(struct i2c_mux_core *muxc, u32 chan_id)
{
- struct rtl2832_dev *dev = mux_priv;
+ struct rtl2832_dev *dev = i2c_mux_priv(muxc);
struct i2c_client *client = dev->client;
int ret;

@@ -889,10 +889,9 @@ err:
return ret;
}

-static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
- u32 chan_id)
+static int rtl2832_deselect(struct i2c_mux_core *muxc, u32 chan_id)
{
- struct rtl2832_dev *dev = mux_priv;
+ struct rtl2832_dev *dev = i2c_mux_priv(muxc);

schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100));
return 0;
@@ -1078,7 +1077,7 @@ static struct i2c_adapter *rtl2832_get_i2c_adapter(struct i2c_client *client)
struct rtl2832_dev *dev = i2c_get_clientdata(client);

dev_dbg(&client->dev, "\n");
- return dev->i2c_adapter_tuner;
+ return dev->muxc->adapter[0];
}

static int rtl2832_enable_slave_ts(struct i2c_client *client)
@@ -1253,12 +1252,13 @@ static int rtl2832_probe(struct i2c_client *client,
goto err_regmap_exit;

/* create muxed i2c adapter for demod tuner bus */
- dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
- 0, 0, 0, rtl2832_select, rtl2832_deselect);
- if (dev->i2c_adapter_tuner == NULL) {
- ret = -ENODEV;
+ dev->muxc = i2c_mux_one_adapter(i2c, &i2c->dev, 0, 0, 0, 0, 0,
+ rtl2832_select, rtl2832_deselect);
+ if (IS_ERR(dev->muxc)) {
+ ret = PTR_ERR(dev->muxc);
goto err_regmap_exit;
}
+ dev->muxc->priv = dev;

/* create dvb_frontend */
memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
@@ -1293,7 +1293,7 @@ static int rtl2832_remove(struct i2c_client *client)

cancel_delayed_work_sync(&dev->i2c_gate_work);

- i2c_del_mux_adapter(dev->i2c_adapter_tuner);
+ i2c_mux_del_adapters(dev->muxc);

regmap_exit(dev->regmap);

diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 5dcd3a41d23f..6b3cd23a2c26 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -36,7 +36,7 @@ struct rtl2832_dev {
struct mutex regmap_mutex;
struct regmap_config regmap_config;
struct regmap *regmap;
- struct i2c_adapter *i2c_adapter_tuner;
+ struct i2c_mux_core *muxc;
struct dvb_frontend fe;
struct delayed_work stat_work;
enum fe_status fe_status;
--
2.1.4

2016-03-03 22:29:45

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 12/18] [media] si2168: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select/deselect ops to be in terms of the i2c mux core
instead of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/media/dvb-frontends/si2168.c | 22 ++++++++++++----------
drivers/media/dvb-frontends/si2168_priv.h | 2 +-
2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 821a8f481507..ca455d01c71d 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -615,9 +615,9 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
* We must use unlocked I2C I/O because I2C adapter lock is already taken
* by the caller (usually tuner driver).
*/
-static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
{
- struct i2c_client *client = mux_priv;
+ struct i2c_client *client = i2c_mux_priv(muxc);
int ret;
struct si2168_cmd cmd;

@@ -635,9 +635,9 @@ err:
return ret;
}

-static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan)
{
- struct i2c_client *client = mux_priv;
+ struct i2c_client *client = i2c_mux_priv(muxc);
int ret;
struct si2168_cmd cmd;

@@ -709,17 +709,19 @@ static int si2168_probe(struct i2c_client *client,
}

/* create mux i2c adapter for tuner */
- dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
- client, 0, 0, 0, si2168_select, si2168_deselect);
- if (dev->adapter == NULL) {
- ret = -ENODEV;
+ dev->muxc = i2c_mux_one_adapter(client->adapter, &client->dev, 0, 0,
+ 0, 0, 0,
+ si2168_select, si2168_deselect);
+ if (IS_ERR(dev->muxc)) {
+ ret = PTR_ERR(dev->muxc);
goto err_kfree;
}
+ dev->muxc->priv = client;

/* create dvb_frontend */
memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
dev->fe.demodulator_priv = client;
- *config->i2c_adapter = dev->adapter;
+ *config->i2c_adapter = dev->muxc->adapter[0];
*config->fe = &dev->fe;
dev->ts_mode = config->ts_mode;
dev->ts_clock_inv = config->ts_clock_inv;
@@ -743,7 +745,7 @@ static int si2168_remove(struct i2c_client *client)

dev_dbg(&client->dev, "\n");

- i2c_del_mux_adapter(dev->adapter);
+ i2c_mux_del_adapters(dev->muxc);

dev->fe.ops.release = NULL;
dev->fe.demodulator_priv = NULL;
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index c07e6fe2cb10..165bf1412063 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -29,7 +29,7 @@

/* state struct */
struct si2168_dev {
- struct i2c_adapter *adapter;
+ struct i2c_mux_core *muxc;
struct dvb_frontend fe;
enum fe_delivery_system delivery_system;
enum fe_status fe_status;
--
2.1.4

2016-03-03 22:29:53

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 13/18] [media] cx231xx: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select op to be in terms of the i2c mux core instead
of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/media/usb/cx231xx/cx231xx-core.c | 6 ++--
drivers/media/usb/cx231xx/cx231xx-i2c.c | 47 ++++++++++++++++----------------
drivers/media/usb/cx231xx/cx231xx.h | 4 ++-
3 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index f497888d94bf..f7aac2abd783 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1304,6 +1304,9 @@ int cx231xx_dev_init(struct cx231xx *dev)
cx231xx_i2c_register(&dev->i2c_bus[1]);
cx231xx_i2c_register(&dev->i2c_bus[2]);

+ errCode = cx231xx_i2c_mux_create(dev);
+ if (errCode < 0)
+ return errCode;
cx231xx_i2c_mux_register(dev, 0);
cx231xx_i2c_mux_register(dev, 1);

@@ -1426,8 +1429,7 @@ EXPORT_SYMBOL_GPL(cx231xx_dev_init);
void cx231xx_dev_uninit(struct cx231xx *dev)
{
/* Un Initialize I2C bus */
- cx231xx_i2c_mux_unregister(dev, 1);
- cx231xx_i2c_mux_unregister(dev, 0);
+ cx231xx_i2c_mux_unregister(dev);
cx231xx_i2c_unregister(&dev->i2c_bus[2]);
cx231xx_i2c_unregister(&dev->i2c_bus[1]);
cx231xx_i2c_unregister(&dev->i2c_bus[0]);
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index a29c345b027d..eb22e05d4add 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -557,40 +557,41 @@ int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
* cx231xx_i2c_mux_select()
* switch i2c master number 1 between port1 and port3
*/
-static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
- void *mux_priv, u32 chan_id)
+static int cx231xx_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan_id)
{
- struct cx231xx *dev = mux_priv;
+ struct cx231xx *dev = i2c_mux_priv(muxc);

return cx231xx_enable_i2c_port_3(dev, chan_id);
}

+int cx231xx_i2c_mux_create(struct cx231xx *dev)
+{
+ dev->muxc = i2c_mux_alloc(&dev->i2c_bus[1].i2c_adap, dev->dev, 0, 0,
+ cx231xx_i2c_mux_select, NULL);
+ if (!dev->muxc)
+ return -ENOMEM;
+ dev->muxc->priv = dev;
+ return 0;
+}
+
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
{
- struct i2c_adapter *i2c_parent = &dev->i2c_bus[1].i2c_adap;
- /* what is the correct mux_dev? */
- struct device *mux_dev = dev->dev;
-
- dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
- mux_dev,
- dev /* mux_priv */,
- 0,
- mux_no /* chan_id */,
- 0 /* class */,
- &cx231xx_i2c_mux_select,
- NULL);
-
- if (!dev->i2c_mux_adap[mux_no])
+ int rc;
+
+ rc = i2c_mux_add_adapter(dev->muxc,
+ 0,
+ mux_no /* chan_id */,
+ 0 /* class */);
+ if (rc)
dev_warn(dev->dev,
"i2c mux %d register FAILED\n", mux_no);

- return 0;
+ return rc;
}

-void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no)
+void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
{
- i2c_del_mux_adapter(dev->i2c_mux_adap[mux_no]);
- dev->i2c_mux_adap[mux_no] = NULL;
+ i2c_mux_del_adapters(dev->muxc);
}

struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
@@ -603,9 +604,9 @@ struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
case I2C_2:
return &dev->i2c_bus[2].i2c_adap;
case I2C_1_MUX_1:
- return dev->i2c_mux_adap[0];
+ return dev->muxc->adapter[0];
case I2C_1_MUX_3:
- return dev->i2c_mux_adap[1];
+ return dev->muxc->adapter[1];
default:
return NULL;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index ec6d3f5bc36d..fab222059e51 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -625,6 +625,7 @@ struct cx231xx {

/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
struct cx231xx_i2c i2c_bus[3];
+ struct i2c_mux_core *muxc;
struct i2c_adapter *i2c_mux_adap[2];

unsigned int xc_fw_load_done:1;
@@ -759,8 +760,9 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev);
void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port);
int cx231xx_i2c_register(struct cx231xx_i2c *bus);
int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
+int cx231xx_i2c_mux_create(struct cx231xx *dev);
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no);
-void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no);
+void cx231xx_i2c_mux_unregister(struct cx231xx *dev);
struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);

/* Internal block control functions */
--
2.1.4

2016-03-03 22:30:13

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 15/18] i2c-mux: drop old unused i2c-mux api

From: Peter Rosin <[email protected]>

All i2c mux users are using an explicit i2c mux core, drop support
for implicit i2c mux cores.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/i2c/i2c-mux.c | 59 -------------------------------------------------
include/linux/i2c-mux.h | 15 -------------
2 files changed, 74 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 7df323a01661..e7ac7a4a7a83 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -28,12 +28,6 @@
#include <linux/acpi.h>

/* multiplexer per channel data */
-struct i2c_mux_priv_old {
- void *mux_priv;
- int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
- int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
-};
-
struct i2c_mux_priv {
struct i2c_adapter adap;
struct i2c_algorithm algo;
@@ -290,48 +284,6 @@ struct i2c_mux_core *i2c_mux_one_adapter(struct i2c_adapter *parent,
}
EXPORT_SYMBOL_GPL(i2c_mux_one_adapter);

-static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
-{
- struct i2c_mux_priv_old *priv = i2c_mux_priv(muxc);
-
- return priv->select(muxc->parent, priv->mux_priv, chan);
-}
-
-static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
-{
- struct i2c_mux_priv_old *priv = i2c_mux_priv(muxc);
-
- return priv->deselect(muxc->parent, priv->mux_priv, chan);
-}
-
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
- 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 i2c_mux_core *muxc;
- struct i2c_mux_priv_old *priv;
-
- muxc = i2c_mux_one_adapter(parent, mux_dev, sizeof(*priv), 0,
- force_nr, chan_id, class,
- i2c_mux_select,
- deselect ? i2c_mux_deselect : NULL);
- if (IS_ERR(muxc))
- return NULL;
-
- priv = i2c_mux_priv(muxc);
- priv->select = select;
- priv->deselect = deselect;
- priv->mux_priv = mux_priv;
-
- return muxc->adapter[0];
-}
-EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
-
void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
{
char symlink_name[20];
@@ -353,17 +305,6 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
}
EXPORT_SYMBOL_GPL(i2c_mux_del_adapters);

-void i2c_del_mux_adapter(struct i2c_adapter *adap)
-{
- struct i2c_mux_priv *priv = adap->algo_data;
- struct i2c_mux_core *muxc = priv->muxc;
-
- i2c_mux_del_adapters(muxc);
- devm_kfree(muxc->dev, muxc->adapter);
- devm_kfree(muxc->dev, muxc);
-}
-EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
-
MODULE_AUTHOR("Rodolfo Giometti <[email protected]>");
MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 0d97d7a3f03c..25c88ccf9c38 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -55,20 +55,6 @@ 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_adapter *parent,
- 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));
-/*
- * Called to create a i2c bus on a multiplexed bus segment.
* The chan_id parameter is passed to the select and deselect
* callback functions to perform hardware-specific mux control.
*/
@@ -88,7 +74,6 @@ struct i2c_mux_core *i2c_mux_one_adapter(struct i2c_adapter *parent,
int (*deselect)(struct i2c_mux_core *,
u32));

-void i2c_del_mux_adapter(struct i2c_adapter *adap);
void i2c_mux_del_adapters(struct i2c_mux_core *muxc);

#endif /* __KERNEL__ */
--
2.1.4

2016-03-03 22:30:22

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 16/18] i2c: allow adapter drivers to override the adapter locking

From: Peter Rosin <[email protected]>

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

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

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

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

Annotate some of the locking with explicit I2C_LOCK_SEGMENT flags.

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

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index ffe715d346d8..946afd8e9f78 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -959,10 +959,10 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
}

/**
- * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
*/
-void i2c_lock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);

@@ -971,27 +971,26 @@ void i2c_lock_adapter(struct i2c_adapter *adapter)
else
rt_mutex_lock(&adapter->bus_lock);
}
-EXPORT_SYMBOL_GPL(i2c_lock_adapter);

/**
- * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
*/
-static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);

if (parent)
- return i2c_trylock_adapter(parent);
+ return parent->trylock_bus(parent, flags);
else
return rt_mutex_trylock(&adapter->bus_lock);
}

/**
- * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
*/
-void i2c_unlock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, int flags)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);

@@ -1000,7 +999,6 @@ void i2c_unlock_adapter(struct i2c_adapter *adapter)
else
rt_mutex_unlock(&adapter->bus_lock);
}
-EXPORT_SYMBOL_GPL(i2c_unlock_adapter);

static void i2c_dev_set_name(struct i2c_adapter *adap,
struct i2c_client *client)
@@ -1546,6 +1544,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return -EINVAL;
}

+ if (!adap->lock_bus) {
+ adap->lock_bus = i2c_adapter_lock_bus;
+ adap->trylock_bus = i2c_adapter_trylock_bus;
+ adap->unlock_bus = i2c_adapter_unlock_bus;
+ }
+
rt_mutex_init(&adap->bus_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
@@ -2310,16 +2314,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif

if (in_atomic() || irqs_disabled()) {
- ret = i2c_trylock_adapter(adap);
+ ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
- i2c_lock_adapter(adap);
+ i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
}

ret = __i2c_transfer(adap, msgs, num);
- i2c_unlock_adapter(adap);
+ i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);

return ret;
} else {
@@ -3094,7 +3098,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;

if (adapter->algo->smbus_xfer) {
- i2c_lock_adapter(adapter);
+ i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);

/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
@@ -3108,7 +3112,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout))
break;
}
- i2c_unlock_adapter(adapter);
+ i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);

if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
goto trace;
@@ -3219,9 +3223,9 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)

client->slave_cb = slave_cb;

- i2c_lock_adapter(client->adapter);
+ i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = client->adapter->algo->reg_slave(client);
- i2c_unlock_adapter(client->adapter);
+ i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);

if (ret) {
client->slave_cb = NULL;
@@ -3241,9 +3245,9 @@ int i2c_slave_unregister(struct i2c_client *client)
return -EOPNOTSUPP;
}

- i2c_lock_adapter(client->adapter);
+ i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT);
ret = client->adapter->algo->unreg_slave(client);
- i2c_unlock_adapter(client->adapter);
+ i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT);

if (ret == 0)
client->slave_cb = NULL;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 200cf13b00f6..c5f79fec1bfb 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -538,6 +538,10 @@ struct i2c_adapter {

struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
+
+ void (*lock_bus)(struct i2c_adapter *, int flags);
+ int (*trylock_bus)(struct i2c_adapter *, int flags);
+ void (*unlock_bus)(struct i2c_adapter *, int flags);
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)

@@ -567,8 +571,28 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));

/* Adapter locking functions, exported for shared pin cases */
-void i2c_lock_adapter(struct i2c_adapter *);
-void i2c_unlock_adapter(struct i2c_adapter *);
+#define I2C_LOCK_ADAPTER 0x01
+#define I2C_LOCK_SEGMENT 0x02
+static inline void
+i2c_lock_bus(struct i2c_adapter *adapter, int flags)
+{
+ adapter->lock_bus(adapter, flags);
+}
+static inline void
+i2c_unlock_bus(struct i2c_adapter *adapter, int flags)
+{
+ adapter->unlock_bus(adapter, flags);
+}
+static inline void
+i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+ i2c_lock_bus(adapter, I2C_LOCK_ADAPTER);
+}
+static inline void
+i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+ i2c_unlock_bus(adapter, I2C_LOCK_ADAPTER);
+}

/*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
--
2.1.4

2016-03-03 22:30:29

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 17/18] i2c: muxes always lock the parent adapter

From: Peter Rosin <[email protected]>

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 <[email protected]>
---
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 946afd8e9f78..6be266c3d39b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -964,12 +964,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);
}

/**
@@ -978,12 +973,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);
}

/**
@@ -992,12 +982,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 e7ac7a4a7a83..6f5c70c527b8 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;
@@ -192,6 +216,9 @@ int i2c_mux_add_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

2016-03-03 22:30:33

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 18/18] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing

From: Peter Rosin <[email protected]>

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 code to i2c-mux-gpio and i2c-mux-pinctrl that checks if all involved
gpio/pinctrl devices have a parent that is an i2c adapter in the same
adapter tree that is muxed.

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 <[email protected]>
---
drivers/i2c/i2c-mux.c | 136 ++++++++++++++++++++++++++++++++++--
drivers/i2c/muxes/i2c-mux-gpio.c | 19 +++++
drivers/i2c/muxes/i2c-mux-pinctrl.c | 39 +++++++++++
include/linux/i2c-mux.h | 7 ++
4 files changed, 194 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 6f5c70c527b8..40a4e0397826 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;
@@ -122,6 +202,31 @@ static void i2c_parent_unlock_bus(struct i2c_adapter *adapter, int flags)
parent->unlock_bus(parent, flags);
}

+struct i2c_adapter *i2c_root_adapter(struct device *dev)
+{
+ struct device *i2c;
+ struct i2c_adapter *i2c_root;
+
+ /*
+ * Walk up the device tree to find an i2c adapter, indicating
+ * that this is an i2c client device. Check all ancestors to
+ * handle mfd devices etc.
+ */
+ for (i2c = dev; i2c; i2c = i2c->parent) {
+ if (i2c->type == &i2c_adapter_type)
+ break;
+ }
+ if (!i2c)
+ return NULL;
+
+ /* Continue up the tree to find the root i2c adapter */
+ i2c_root = to_i2c_adapter(i2c);
+ while (i2c_parent_is_i2c_adapter(i2c_root))
+ i2c_root = i2c_parent_is_i2c_adapter(i2c_root);
+
+ return i2c_root;
+}
+
int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
{
struct i2c_adapter **adapter;
@@ -163,9 +268,12 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,

muxc->parent = parent;
muxc->dev = dev;
+ if (flags & I2C_CONTROLLED_MUX)
+ muxc->i2c_controlled = 1;
muxc->select = select;
muxc->deselect = deselect;

+ rt_mutex_init(&muxc->bus_lock);
return muxc;
}
EXPORT_SYMBOL_GPL(i2c_mux_alloc);
@@ -200,10 +308,18 @@ int i2c_mux_add_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 */
@@ -216,9 +332,15 @@ int i2c_mux_add_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 1bcc26737359..f7a9d36b5e09 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
+#include "../../gpio/gpiolib.h"
#include <linux/of_gpio.h>

struct gpiomux {
@@ -137,6 +138,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
struct i2c_mux_core *muxc;
struct gpiomux *mux;
struct i2c_adapter *parent;
+ struct i2c_adapter *root;
unsigned initial_state, gpio_base;
int i, ret;

@@ -178,6 +180,9 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
if (!parent)
return -EPROBE_DEFER;

+ root = i2c_root_adapter(&parent->dev);
+
+ muxc->i2c_controlled = true;
muxc->parent = parent;
mux->gpio_base = gpio_base;

@@ -193,6 +198,9 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
}

for (i = 0; i < mux->data.n_gpios; i++) {
+ struct device *gpio_dev;
+ struct gpio_desc *gpio_desc;
+
ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
if (ret) {
dev_err(&pdev->dev, "Failed to request GPIO %d\n",
@@ -209,8 +217,19 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
i++; /* gpio_request above succeeded, so must free */
goto err_request_gpio;
}
+
+ if (!muxc->i2c_controlled)
+ continue;
+
+ gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
+ gpio_dev = gpio_desc->chip->parent;
+ muxc->i2c_controlled = i2c_root_adapter(gpio_dev) == root;
}

+ if (muxc->i2c_controlled)
+ dev_info(&pdev->dev,
+ "lock select-transfer-deselect individually\n");
+
for (i = 0; i < mux->data.n_values; i++) {
u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index bbfabf4f52be..d2532959e8bc 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include "../../pinctrl/core.h"

struct i2c_mux_pinctrl {
struct i2c_mux_pinctrl_platform_data *pdata;
@@ -120,10 +121,31 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
}
#endif

+static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
+ struct pinctrl_state *state)
+{
+ struct i2c_adapter *root = NULL;
+ struct pinctrl_setting *setting;
+ struct i2c_adapter *pin_root;
+
+ list_for_each_entry(setting, &state->settings, node) {
+ pin_root = i2c_root_adapter(setting->pctldev->dev);
+ if (!pin_root)
+ return NULL;
+ if (!root)
+ root = pin_root;
+ else if (root != pin_root)
+ return NULL;
+ }
+
+ return root;
+}
+
static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
{
struct i2c_mux_core *muxc;
struct i2c_mux_pinctrl *mux;
+ struct i2c_adapter *root;
int i, ret;

muxc = i2c_mux_alloc(NULL, &pdev->dev, sizeof(*mux), 0,
@@ -199,6 +221,23 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err;
}

+ root = i2c_root_adapter(&muxc->parent->dev);
+
+ muxc->i2c_controlled = true;
+ for (i = 0; i < mux->pdata->bus_count; i++) {
+ if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
+ muxc->i2c_controlled = false;
+ break;
+ }
+ }
+ if (muxc->i2c_controlled && mux->pdata->pinctrl_state_idle
+ && root != i2c_mux_pinctrl_root_adapter(mux->state_idle))
+ muxc->i2c_controlled = false;
+
+ if (muxc->i2c_controlled)
+ dev_info(&pdev->dev,
+ "lock select-transfer-deselect individually\n");
+
for (i = 0; i < mux->pdata->bus_count; i++) {
u32 bus = mux->pdata->base_bus_num ?
(mux->pdata->base_bus_num + i) : 0;
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 25c88ccf9c38..d0b7e2d9f4dd 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;

@@ -46,11 +48,16 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
int (*select)(struct i2c_mux_core *, u32),
int (*deselect)(struct i2c_mux_core *, u32));

+/* flags for i2c_mux_alloc */
+#define I2C_CONTROLLED_MUX (1<<0)
+
static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
{
return muxc->priv;
}

+struct i2c_adapter *i2c_root_adapter(struct device *dev);
+
int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters);

/*
--
2.1.4

2016-03-03 22:31:46

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 14/18] of/unittest: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select op to be in terms of the i2c mux core instead
of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/of/unittest.c | 40 +++++++++++++++-------------------------
1 file changed, 15 insertions(+), 25 deletions(-)

diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 979b6e415cea..a6dc4b18047e 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1687,13 +1687,7 @@ static struct i2c_driver unittest_i2c_dev_driver = {

#if IS_BUILTIN(CONFIG_I2C_MUX)

-struct unittest_i2c_mux_data {
- int nchans;
- struct i2c_adapter *adap[];
-};
-
-static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
- void *client, u32 chan)
+static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
return 0;
}
@@ -1701,11 +1695,11 @@ static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
static int unittest_i2c_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int ret, i, nchans, size;
+ int ret, i, nchans;
struct device *dev = &client->dev;
struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
struct device_node *np = client->dev.of_node, *child;
- struct unittest_i2c_mux_data *stm;
+ struct i2c_mux_core *muxc;
u32 reg, max_reg;

dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@@ -1729,25 +1723,23 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
return -EINVAL;
}

- size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
- stm = devm_kzalloc(dev, size, GFP_KERNEL);
- if (!stm) {
- dev_err(dev, "Out of memory\n");
+ muxc = i2c_mux_alloc(adap, dev, 0, 0,
+ unittest_i2c_mux_select_chan, NULL);
+ if (!muxc)
return -ENOMEM;
- }
- stm->nchans = nchans;
+ ret = i2c_mux_reserve_adapters(muxc, nchans);
+ if (ret)
+ return ret;
for (i = 0; i < nchans; i++) {
- stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
- 0, i, 0, unittest_i2c_mux_select_chan, NULL);
- if (!stm->adap[i]) {
+ ret = i2c_mux_add_adapter(muxc, 0, i, 0);
+ if (ret) {
dev_err(dev, "Failed to register mux #%d\n", i);
- for (i--; i >= 0; i--)
- i2c_del_mux_adapter(stm->adap[i]);
+ i2c_mux_del_adapters(muxc);
return -ENODEV;
}
}

- i2c_set_clientdata(client, stm);
+ i2c_set_clientdata(client, muxc);

return 0;
};
@@ -1756,12 +1748,10 @@ static int unittest_i2c_mux_remove(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *np = client->dev.of_node;
- struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
- int i;
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);

dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
- for (i = stm->nchans - 1; i >= 0; i--)
- i2c_del_mux_adapter(stm->adap[i]);
+ i2c_mux_del_adapters(muxc);
return 0;
}

--
2.1.4

2016-03-03 22:33:52

by Peter Rosin

[permalink] [raw]
Subject: [PATCH v4 09/18] [media] m88ds3103: convert to use an explicit i2c mux core

From: Peter Rosin <[email protected]>

Allocate an explicit i2c mux core to handle parent and child adapters
etc. Update the select op to be in terms of the i2c mux core instead
of the child adapter.

Signed-off-by: Peter Rosin <[email protected]>
---
drivers/media/dvb-frontends/m88ds3103.c | 18 +++++++++---------
drivers/media/dvb-frontends/m88ds3103_priv.h | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index ce73a5ec6036..845d206eb70f 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1251,9 +1251,9 @@ static void m88ds3103_release(struct dvb_frontend *fe)
i2c_unregister_device(client);
}

-static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan)
{
- struct m88ds3103_dev *dev = mux_priv;
+ struct m88ds3103_dev *dev = i2c_mux_priv(muxc);
struct i2c_client *client = dev->client;
int ret;
struct i2c_msg msg = {
@@ -1374,7 +1374,7 @@ static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client)

dev_dbg(&client->dev, "\n");

- return dev->i2c_adapter;
+ return dev->muxc->adapter[0];
}

static int m88ds3103_probe(struct i2c_client *client,
@@ -1467,13 +1467,13 @@ static int m88ds3103_probe(struct i2c_client *client,
goto err_kfree;

/* create mux i2c adapter for tuner */
- dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
- dev, 0, 0, 0, m88ds3103_select,
- NULL);
- if (dev->i2c_adapter == NULL) {
- ret = -ENOMEM;
+ dev->muxc = i2c_mux_one_adapter(client->adapter, &client->dev, 0, 0,
+ 0, 0, 0, m88ds3103_select, NULL);
+ if (IS_ERR(dev->muxc)) {
+ ret = PTR_ERR(dev->muxc);
goto err_kfree;
}
+ dev->muxc->priv = dev;

/* create dvb_frontend */
memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
@@ -1502,7 +1502,7 @@ static int m88ds3103_remove(struct i2c_client *client)

dev_dbg(&client->dev, "\n");

- i2c_del_mux_adapter(dev->i2c_adapter);
+ i2c_mux_del_adapters(dev->muxc);

kfree(dev);
return 0;
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index eee8c22c51ec..c5b4e177c6ea 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -42,7 +42,7 @@ struct m88ds3103_dev {
enum fe_status fe_status;
u32 dvbv3_ber; /* for old DVBv3 API read_ber */
bool warm; /* FW running */
- struct i2c_adapter *i2c_adapter;
+ struct i2c_mux_core *muxc;
/* auto detect chip id to do different config */
u8 chip_id;
/* main mclk is calculated for M88RS6000 dynamically */
--
2.1.4

2016-03-04 05:22:52

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 18/18] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing

Hi Peter,

[auto build test ERROR on v4.5-rc6]
[cannot apply to wsa/i2c/for-next sailus-media/master next-20160303]
[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/20160304-112229
config: i386-randconfig-i0-201609 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

>> ERROR: "i2c_root_adapter" [drivers/i2c/muxes/i2c-mux-pinctrl.ko] undefined!

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


Attachments:
(No filename) (757.00 B)
.config.gz (25.60 kB)
Download all attachments

2016-03-04 05:59:45

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 16/18] i2c: allow adapter drivers to override the adapter locking

Hi Peter,

[auto build test WARNING on v4.5-rc6]
[cannot apply to wsa/i2c/for-next sailus-media/master next-20160303]
[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/20160304-112229
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

include/linux/init.h:1: warning: no structured comments found
kernel/sys.c:1: warning: no structured comments found
drivers/dma-buf/seqno-fence.c:1: warning: no structured comments found
drivers/dma-buf/reservation.c:1: warning: no structured comments found
include/linux/reservation.h:1: warning: no structured comments found
include/linux/spi/spi.h:540: warning: No description found for parameter 'max_transfer_size'
>> drivers/i2c/i2c-core.c:966: warning: No description found for parameter 'flags'
drivers/i2c/i2c-core.c:980: warning: No description found for parameter 'flags'
drivers/i2c/i2c-core.c:994: warning: No description found for parameter 'flags'

vim +/flags +966 drivers/i2c/i2c-core.c

0826374b Michael Lawnick 2010-08-11 950
97cc4d49 Jean Delvare 2010-10-24 951 if (parent)
97cc4d49 Jean Delvare 2010-10-24 952 result = i2c_check_mux_parents(parent, addr);
0826374b Michael Lawnick 2010-08-11 953
0826374b Michael Lawnick 2010-08-11 954 if (!result)
0826374b Michael Lawnick 2010-08-11 955 result = device_for_each_child(&adapter->dev, &addr,
0826374b Michael Lawnick 2010-08-11 956 i2c_check_mux_children);
0826374b Michael Lawnick 2010-08-11 957
0826374b Michael Lawnick 2010-08-11 958 return result;
3b5f794b Jean Delvare 2010-06-03 959 }
3b5f794b Jean Delvare 2010-06-03 960
9c1600ed David Brownell 2007-05-01 961 /**
7adc3913 Peter Rosin 2016-03-03 962 * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
fe61e07e Jean Delvare 2010-08-11 963 * @adapter: Target I2C bus segment
fe61e07e Jean Delvare 2010-08-11 964 */
7adc3913 Peter Rosin 2016-03-03 965 static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
fe61e07e Jean Delvare 2010-08-11 @966 {
97cc4d49 Jean Delvare 2010-10-24 967 struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
97cc4d49 Jean Delvare 2010-10-24 968
97cc4d49 Jean Delvare 2010-10-24 969 if (parent)
97cc4d49 Jean Delvare 2010-10-24 970 i2c_lock_adapter(parent);
0826374b Michael Lawnick 2010-08-11 971 else
fe61e07e Jean Delvare 2010-08-11 972 rt_mutex_lock(&adapter->bus_lock);
fe61e07e Jean Delvare 2010-08-11 973 }
fe61e07e Jean Delvare 2010-08-11 974

:::::: The code at line 966 was first introduced by commit
:::::: fe61e07e9ebc890c70d97a1f72ddaad4bee2d848 i2c: Move adapter locking helpers to i2c-core

:::::: TO: Jean Delvare <[email protected]>
:::::: CC: Jean Delvare <[email protected]>

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


Attachments:
(No filename) (3.04 kB)
.config.gz (6.08 kB)
Download all attachments

2016-03-04 07:11:00

by Peter Rosin

[permalink] [raw]
Subject: Re: [PATCH v4 18/18] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing

Hi!

Here's a fixup for a problem found by the test robot. Sorry for the
inconvenience.

Cheers,
Peter

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 40a4e0397826..b73c42eddca3 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -226,6 +226,7 @@ struct i2c_adapter *i2c_root_adapter(struct device *dev)

return i2c_root;
}
+EXPORT_SYMBOL_GPL(i2c_root_adapter);

int i2c_mux_reserve_adapters(struct i2c_mux_core *muxc, int adapters)
{
--
2.1.4


2016-03-04 09:33:31

by Peter Rosin

[permalink] [raw]
Subject: Re: [PATCH v4 16/18] i2c: allow adapter drivers to override the adapter locking

Hi!

Here's a fixup for a problem found by the test robot. Sorry for the
inconvenience.

Cheers,
Peter

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6be266c3d39b..5ecc6fc52ce0 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -961,6 +961,8 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
/**
* i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
+ * locks only this branch in the adapter tree
*/
static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
{
@@ -970,6 +972,8 @@ static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, int flags)
/**
* i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT
+ * trylocks only this branch in the adapter tree
*/
static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
{
@@ -979,6 +983,8 @@ static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, int flags)
/**
* i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
+ * unlocks only this branch in the adapter tree
*/
static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, int flags)
{
--
2.1.4

2016-03-04 11:01:59

by Peter Rosin

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] i2c mux cleanup and locking update

I wrote:
> Concerns:
> - The locking is perhaps too complex?

Ok, to highlight the benefits of this series, I expect that patches such as
[1] and the one inlined below can follow up to clean up ad-hoc i2c locking
in drivers. Putting this locking in one place instead of having it spread
out in random drivers is a good thing.

PS. the inlined patch has not been tested as I have no hw, it's a proof of
concept. Maybe the simplifications can be extended into rtl2832_sdr.c as well?
Anyway, please do test this patch on top of the v4 series if you have the hw.

Cheers,
Peter

[1] https://lkml.org/lkml/2016/3/3/932

diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 775444898599..fd1f05e9e79a 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -158,36 +158,24 @@ static int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg,
const void *val, size_t val_count)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
- int ret;

- i2c_lock_adapter(client->adapter);
- ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
- i2c_unlock_adapter(client->adapter);
- return ret;
+ return regmap_bulk_write(dev->regmap, reg, val, val_count);
}

static int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
unsigned int mask, unsigned int val)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
- int ret;

- i2c_lock_adapter(client->adapter);
- ret = regmap_update_bits(dev->regmap, reg, mask, val);
- i2c_unlock_adapter(client->adapter);
- return ret;
+ return regmap_update_bits(dev->regmap, reg, mask, val);
}

static int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg,
void *val, size_t val_count)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
- int ret;

- i2c_lock_adapter(client->adapter);
- ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
- i2c_unlock_adapter(client->adapter);
- return ret;
+ return regmap_bulk_read(dev->regmap, reg, val, val_count);
}

static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
@@ -204,7 +192,7 @@ static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);

- ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
+ ret = regmap_bulk_read(dev->regmap, reg_start_addr, reading, len);
if (ret)
goto err;

@@ -234,7 +222,7 @@ static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val)
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);

- ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
+ ret = regmap_bulk_read(dev->regmap, reg_start_addr, reading, len);
if (ret)
goto err;

@@ -248,7 +236,7 @@ static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val)
for (i = 0; i < len; i++)
writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;

- ret = rtl2832_bulk_write(client, reg_start_addr, writing, len);
+ ret = regmap_bulk_write(dev->regmap, reg_start_addr, writing, len);
if (ret)
goto err;

@@ -492,7 +480,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
fe->ops.tuner_ops.set_params(fe);

/* PIP mode related */
- ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3);
+ ret = regmap_bulk_write(dev->regmap, 0x192, "\x00\x0f\xff", 3);
if (ret)
goto err;

@@ -530,7 +518,7 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
}

for (j = 0; j < sizeof(bw_params[0]); j++) {
- ret = rtl2832_bulk_write(client, 0x11c + j, &bw_params[i][j], 1);
+ ret = regmap_bulk_write(dev->regmap, 0x11c + j, &bw_params[i][j], 1);
if (ret)
goto err;
}
@@ -586,11 +574,11 @@ static int rtl2832_get_frontend(struct dvb_frontend *fe)
if (dev->sleeping)
return 0;

- ret = rtl2832_bulk_read(client, 0x33c, buf, 2);
+ ret = regmap_bulk_read(dev->regmap, 0x33c, buf, 2);
if (ret)
goto err;

- ret = rtl2832_bulk_read(client, 0x351, &buf[2], 1);
+ ret = regmap_bulk_read(dev->regmap, 0x351, &buf[2], 1);
if (ret)
goto err;

@@ -757,7 +745,7 @@ static void rtl2832_stat_work(struct work_struct *work)
/* signal strength */
if (dev->fe_status & FE_HAS_SIGNAL) {
/* read digital AGC */
- ret = rtl2832_bulk_read(client, 0x305, &u8tmp, 1);
+ ret = regmap_bulk_read(dev->regmap, 0x305, &u8tmp, 1);
if (ret)
goto err;

@@ -783,7 +771,7 @@ static void rtl2832_stat_work(struct work_struct *work)
{87659938, 87659938, 87885178, 88241743},
};

- ret = rtl2832_bulk_read(client, 0x33c, &u8tmp, 1);
+ ret = regmap_bulk_read(dev->regmap, 0x33c, &u8tmp, 1);
if (ret)
goto err;

@@ -795,7 +783,7 @@ static void rtl2832_stat_work(struct work_struct *work)
if (hierarchy > HIERARCHY_NUM - 1)
goto err_schedule_delayed_work;

- ret = rtl2832_bulk_read(client, 0x40c, buf, 2);
+ ret = regmap_bulk_read(dev->regmap, 0x40c, buf, 2);
if (ret)
goto err;

@@ -816,7 +804,7 @@ static void rtl2832_stat_work(struct work_struct *work)

/* BER */
if (dev->fe_status & FE_HAS_LOCK) {
- ret = rtl2832_bulk_read(client, 0x34e, buf, 2);
+ ret = regmap_bulk_read(dev->regmap, 0x34e, buf, 2);
if (ret)
goto err;

@@ -844,8 +832,6 @@ err:

/*
* I2C gate/mux/repeater logic
- * We must use unlocked __i2c_transfer() here (through regmap) because of I2C
- * adapter lock is already taken by tuner driver.
* There is delay mechanism to avoid unneeded I2C gate open / close. Gate close
* is delayed here a little bit in order to see if there is sequence of I2C
* messages sent to same I2C bus.
@@ -857,7 +843,7 @@ static void rtl2832_i2c_gate_work(struct work_struct *work)
int ret;

/* close gate */
- ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
+ ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x00);
if (ret)
goto err;

@@ -875,10 +861,7 @@ static int rtl2832_select(struct i2c_mux_core *muxc, u32 chan_id)
/* terminate possible gate closing */
cancel_delayed_work(&dev->i2c_gate_work);

- /*
- * I2C adapter lock is already taken and due to that we will use
- * regmap_update_bits() which does not lock again I2C adapter.
- */
+ /* open gate */
ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
if (ret)
goto err;
@@ -950,120 +933,6 @@ static bool rtl2832_volatile_reg(struct device *dev, unsigned int reg)
return false;
}

-/*
- * We implement own I2C access routines for regmap in order to get manual access
- * to I2C adapter lock, which is needed for I2C mux adapter.
- */
-static int rtl2832_regmap_read(void *context, const void *reg_buf,
- size_t reg_size, void *val_buf, size_t val_size)
-{
- struct i2c_client *client = context;
- int ret;
- struct i2c_msg msg[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = reg_size,
- .buf = (u8 *)reg_buf,
- }, {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = val_size,
- .buf = val_buf,
- }
- };
-
- ret = __i2c_transfer(client->adapter, msg, 2);
- if (ret != 2) {
- dev_warn(&client->dev, "i2c reg read failed %d reg %02x\n",
- ret, *(u8 *)reg_buf);
- if (ret >= 0)
- ret = -EREMOTEIO;
- return ret;
- }
- return 0;
-}
-
-static int rtl2832_regmap_write(void *context, const void *data, size_t count)
-{
- struct i2c_client *client = context;
- int ret;
- struct i2c_msg msg[1] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = count,
- .buf = (u8 *)data,
- }
- };
-
- ret = __i2c_transfer(client->adapter, msg, 1);
- if (ret != 1) {
- dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
- ret, *(u8 *)data);
- if (ret >= 0)
- ret = -EREMOTEIO;
- return ret;
- }
- return 0;
-}
-
-static int rtl2832_regmap_gather_write(void *context, const void *reg,
- size_t reg_len, const void *val,
- size_t val_len)
-{
- struct i2c_client *client = context;
- int ret;
- u8 buf[256];
- struct i2c_msg msg[1] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1 + val_len,
- .buf = buf,
- }
- };
-
- buf[0] = *(u8 const *)reg;
- memcpy(&buf[1], val, val_len);
-
- ret = __i2c_transfer(client->adapter, msg, 1);
- if (ret != 1) {
- dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
- ret, *(u8 const *)reg);
- if (ret >= 0)
- ret = -EREMOTEIO;
- return ret;
- }
- return 0;
-}
-
-/*
- * FIXME: Hack. Implement own regmap locking in order to silence lockdep
- * recursive lock warning. That happens when regmap I2C client calls I2C mux
- * adapter, which leads demod I2C repeater enable via demod regmap. Operation
- * takes two regmap locks recursively - but those are different regmap instances
- * in a two different I2C drivers, so it is not deadlock. Proper fix is to make
- * regmap aware of lockdep.
- */
-static void rtl2832_regmap_lock(void *__dev)
-{
- struct rtl2832_dev *dev = __dev;
- struct i2c_client *client = dev->client;
-
- dev_dbg(&client->dev, "\n");
- mutex_lock(&dev->regmap_mutex);
-}
-
-static void rtl2832_regmap_unlock(void *__dev)
-{
- struct rtl2832_dev *dev = __dev;
- struct i2c_client *client = dev->client;
-
- dev_dbg(&client->dev, "\n");
- mutex_unlock(&dev->regmap_mutex);
-}
-
static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
@@ -1087,7 +956,7 @@ static int rtl2832_enable_slave_ts(struct i2c_client *client)

dev_dbg(&client->dev, "\n");

- ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2);
+ ret = regmap_bulk_write(dev->regmap, 0x10c, "\x5f\xff", 2);
if (ret)
goto err;

@@ -1095,11 +964,11 @@ static int rtl2832_enable_slave_ts(struct i2c_client *client)
if (ret)
goto err;

- ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1);
+ ret = regmap_bulk_write(dev->regmap, 0x0bc, "\x18", 1);
if (ret)
goto err;

- ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
+ ret = regmap_bulk_write(dev->regmap, 0x192, "\x7f\xf7\xff", 3);
if (ret)
goto err;

@@ -1133,7 +1002,7 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
else
u8tmp = 0x00;

- ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp);
+ ret = regmap_update_bits(dev->regmap, 0x061, 0xc0, u8tmp);
if (ret)
goto err;

@@ -1168,14 +1037,14 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid,
buf[1] = (dev->filters >> 8) & 0xff;
buf[2] = (dev->filters >> 16) & 0xff;
buf[3] = (dev->filters >> 24) & 0xff;
- ret = rtl2832_bulk_write(client, 0x062, buf, 4);
+ ret = regmap_bulk_write(dev->regmap, 0x062, buf, 4);
if (ret)
goto err;

/* add PID */
buf[0] = (pid >> 8) & 0xff;
buf[1] = (pid >> 0) & 0xff;
- ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2);
+ ret = regmap_bulk_write(dev->regmap, 0x066 + 2 * index, buf, 2);
if (ret)
goto err;

@@ -1193,12 +1062,6 @@ static int rtl2832_probe(struct i2c_client *client,
struct rtl2832_dev *dev;
int ret;
u8 tmp;
- static const struct regmap_bus regmap_bus = {
- .read = rtl2832_regmap_read,
- .write = rtl2832_regmap_write,
- .gather_write = rtl2832_regmap_gather_write,
- .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
- };
static const struct regmap_range_cfg regmap_range_cfg[] = {
{
.selector_reg = 0x00,
@@ -1231,15 +1094,12 @@ static int rtl2832_probe(struct i2c_client *client,
mutex_init(&dev->regmap_mutex);
dev->regmap_config.reg_bits = 8,
dev->regmap_config.val_bits = 8,
- dev->regmap_config.lock = rtl2832_regmap_lock,
- dev->regmap_config.unlock = rtl2832_regmap_unlock,
- dev->regmap_config.lock_arg = dev,
dev->regmap_config.volatile_reg = rtl2832_volatile_reg,
dev->regmap_config.max_register = 5 * 0x100,
dev->regmap_config.ranges = regmap_range_cfg,
dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg),
dev->regmap_config.cache_type = REGCACHE_NONE,
- dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
+ dev->regmap = regmap_init(&client->dev, NULL, client,
&dev->regmap_config);
if (IS_ERR(dev->regmap)) {
ret = PTR_ERR(dev->regmap);
@@ -1247,12 +1107,13 @@ static int rtl2832_probe(struct i2c_client *client,
}

/* check if the demod is there */
- ret = rtl2832_bulk_read(client, 0x000, &tmp, 1);
+ ret = regmap_bulk_read(dev->regmap, 0x000, &tmp, 1);
if (ret)
goto err_regmap_exit;

/* create muxed i2c adapter for demod tuner bus */
- dev->muxc = i2c_mux_one_adapter(i2c, &i2c->dev, 0, 0, 0, 0, 0,
+ dev->muxc = i2c_mux_one_adapter(i2c, &i2c->dev, 0,
+ I2C_CONTROLLED_MUX, 0, 0, 0,
rtl2832_select, rtl2832_deselect);
if (IS_ERR(dev->muxc)) {
ret = PTR_ERR(dev->muxc);
--
2.1.4

2016-03-04 14:49:44

by Peter Rosin

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] i2c mux cleanup and locking update

I wrote:
> I wrote:
>> Concerns:
>> - The locking is perhaps too complex?
>
> Ok, to highlight the benefits of this series, I expect that patches such as
> [1] and the one inlined below can follow up to clean up ad-hoc i2c locking
> in drivers. Putting this locking in one place instead of having it spread
> out in random drivers is a good thing.
>
> PS. the inlined patch has not been tested as I have no hw, it's a proof of
> concept. Maybe the simplifications can be extended into rtl2832_sdr.c as well?
> Anyway, please do test this patch on top of the v4 series if you have the hw.

The untested patch in the previous message indeed has some obvious problems, so
I fixed that and folded some more removed code now that rtl2832_sdr does not
need to do anything special to access device registers.

The result builds for me, that's all the testing I have done.

diffstat for the two patches combined:
drivers/media/dvb-frontends/rtl2832.c | 216 ++++-------------------------
drivers/media/dvb-frontends/rtl2832.h | 4 +-
drivers/media/dvb-frontends/rtl2832_priv.h | 1 -
drivers/media/dvb-frontends/rtl2832_sdr.c | 13 +-
drivers/media/dvb-frontends/rtl2832_sdr.h | 5 +-
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 5 +-
6 files changed, 34 insertions(+), 210 deletions(-)

Cheers,
Peter

diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index fd1f05e9e79a..6ade321503f0 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -153,31 +153,6 @@ static const struct rtl2832_reg_entry registers[] = {
[DVBT_REG_4MSEL] = {0x013, 0, 0},
};

-/* Our regmap is bypassing I2C adapter lock, thus we do it! */
-static int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg,
- const void *val, size_t val_count)
-{
- struct rtl2832_dev *dev = i2c_get_clientdata(client);
-
- return regmap_bulk_write(dev->regmap, reg, val, val_count);
-}
-
-static int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
- unsigned int mask, unsigned int val)
-{
- struct rtl2832_dev *dev = i2c_get_clientdata(client);
-
- return regmap_update_bits(dev->regmap, reg, mask, val);
-}
-
-static int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg,
- void *val, size_t val_count)
-{
- struct rtl2832_dev *dev = i2c_get_clientdata(client);
-
- return regmap_bulk_read(dev->regmap, reg, val, val_count);
-}
-
static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
{
struct i2c_client *client = dev->client;
@@ -1091,7 +1066,6 @@ static int rtl2832_probe(struct i2c_client *client,
INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
INIT_DELAYED_WORK(&dev->stat_work, rtl2832_stat_work);
/* create regmap */
- mutex_init(&dev->regmap_mutex);
dev->regmap_config.reg_bits = 8,
dev->regmap_config.val_bits = 8,
dev->regmap_config.volatile_reg = rtl2832_volatile_reg,
@@ -1099,8 +1073,7 @@ static int rtl2832_probe(struct i2c_client *client,
dev->regmap_config.ranges = regmap_range_cfg,
dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg),
dev->regmap_config.cache_type = REGCACHE_NONE,
- dev->regmap = regmap_init(&client->dev, NULL, client,
- &dev->regmap_config);
+ dev->regmap = regmap_init_i2c(client, &dev->regmap_config);
if (IS_ERR(dev->regmap)) {
ret = PTR_ERR(dev->regmap);
goto err_kfree;
@@ -1131,9 +1104,7 @@ static int rtl2832_probe(struct i2c_client *client,
pdata->enable_slave_ts = rtl2832_enable_slave_ts;
pdata->pid_filter = rtl2832_pid_filter;
pdata->pid_filter_ctrl = rtl2832_pid_filter_ctrl;
- pdata->bulk_read = rtl2832_bulk_read;
- pdata->bulk_write = rtl2832_bulk_write;
- pdata->update_bits = rtl2832_update_bits;
+ pdata->regmap = dev->regmap;

dev_info(&client->dev, "Realtek RTL2832 successfully attached\n");
return 0;
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index c29a4c2bf71a..fab2f99672d6 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -57,9 +57,7 @@ struct rtl2832_platform_data {
int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
int (*pid_filter_ctrl)(struct dvb_frontend *, int);
/* private: Register access for SDR module use only */
- int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
- int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
- int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+ struct regmap *regmap;
};

#endif /* RTL2832_H */
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 6b3cd23a2c26..8657e0e578c5 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -33,7 +33,6 @@
struct rtl2832_dev {
struct rtl2832_platform_data *pdata;
struct i2c_client *client;
- struct mutex regmap_mutex;
struct regmap_config regmap_config;
struct regmap *regmap;
struct i2c_mux_core *muxc;
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index b860f02a4e55..6a6b1debe277 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -35,6 +35,7 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/math64.h>
+#include <linux/regmap.h>

static bool rtl2832_sdr_emulated_fmt;
module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644);
@@ -169,9 +170,9 @@ static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_dev *dev, u16 reg,
{
struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
- struct i2c_client *client = pdata->i2c_client;
+ struct regmap *regmap = pdata->regmap;

- return pdata->bulk_write(client, reg, val, len);
+ return regmap_bulk_write(regmap, reg, val, len);
}

#if 0
@@ -181,9 +182,9 @@ static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val,
{
struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
- struct i2c_client *client = pdata->i2c_client;
+ struct regmap *regmap = pdata->regmap;

- return pdata->bulk_read(client, reg, val, len);
+ return regmap_bulk_read(regmap, reg, val, len);
}
#endif

@@ -199,9 +200,9 @@ static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_dev *dev, u16 reg,
{
struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
- struct i2c_client *client = pdata->i2c_client;
+ struct regmap *regmap = pdata->regmap;

- return pdata->update_bits(client, reg, mask, val);
+ return regmap_update_bits(regmap, reg, mask, val);
}

/* Private functions */
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.h b/drivers/media/dvb-frontends/rtl2832_sdr.h
index 342ea84860df..d8fc7e7212e3 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.h
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.h
@@ -56,10 +56,7 @@ struct rtl2832_sdr_platform_data {
#define RTL2832_SDR_TUNER_R828D 0x2b
u8 tuner;

- struct i2c_client *i2c_client;
- int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
- int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
- int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+ struct regmap *regmap;
struct dvb_frontend *dvb_frontend;
struct v4l2_subdev *v4l2_subdev;
struct dvb_usb_device *dvb_usb_device;
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index eb5787a3191e..799def499f67 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1325,10 +1325,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
case TUNER_RTL2832_R828D:
pdata.clk = dev->rtl2832_platform_data.clk;
pdata.tuner = dev->tuner;
- pdata.i2c_client = dev->i2c_client_demod;
- pdata.bulk_read = dev->rtl2832_platform_data.bulk_read;
- pdata.bulk_write = dev->rtl2832_platform_data.bulk_write;
- pdata.update_bits = dev->rtl2832_platform_data.update_bits;
+ pdata.regmap = dev->rtl2832_platform_data.regmap;
pdata.dvb_frontend = adap->fe[0];
pdata.dvb_usb_device = d;
pdata.v4l2_subdev = subdev;
--
2.1.4

2016-03-04 17:45:32

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 18/18] i2c-mux: relax locking of the top i2c adapter during i2c controlled muxing

Hi Peter,

[auto build test ERROR on v4.5-rc6]
[cannot apply to wsa/i2c/for-next sailus-media/master next-20160303]
[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/20160304-112229
config: i386-allmodconfig (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

>> ERROR: "i2c_root_adapter" undefined!
>> ERROR: "i2c_root_adapter" undefined!

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


Attachments:
(No filename) (750.00 B)
.config.gz (52.21 kB)
Download all attachments

2016-03-15 14:10:04

by Peter Rosin

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] i2c mux cleanup and locking update

Hi!

On 2016-03-03 23:27, Peter Rosin wrote:
> From: Peter Rosin <[email protected]>
>
> 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. 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.

etc etc

I've made a few changes, but instead of posting another copy of a rather long
series, I decided to push it to github and only post a note about it here. The
plan is to then rebase (if needed) on top of v4.6-rc1 and at that point post
all the patches (this is, after all, at least 4.7 material). At the same time
I do not want to hide the latest version from anyone wanting to have a look or
test.

The series will be posted again for review. This is just a heads up.

v5 compared to v4:
- Rebase on top of v4.5-rc7.
- A new patch making me maintainer of i2c muxes (also sent separately).
- A new file Documentation/i2c/i2c-topology that describes various muxing
issues.
- Rename "i2c-controlled" muxes "self-locked" instead, as it is perfectly
reasonable to have i2c-controlled muxes that use the pre-existing locking
scheme. The pre-existing locking scheme for i2c muxes is from here on
called "parent-locked".
- Rename i2c-mux.c:i2c_mux_master_xfer to __i2c_mux_master_xfer since it
calls __i2c_transfer, which leaves room for a new i2c_mux_master_xfer
that calls i2c_transfer. Similar rename shuffle for i2c_mux_smbus_xfer.
- Use sizeof(*priv) instead of sizeof(struct i2c_mux_priv). One instance.
- Some follow-up patches that were posted in response to v2-v4 cleaning up
and simplifying various i2c muxes outside drivers/i2c/, among those is
an unrelated cleanup patch to drivers/media/dvb-frontends/rtl2832.c that
I carry here since it conflicts (trivially) with this series. That
unrelated patch is (currently) the last patch in the series.


The series looks like this now:

The following changes since commit f6cede5b49e822ebc41a099fe41ab4989f64e2cb:

Linux 4.5-rc7 (2016-03-06 14:48:03 -0800)

are available in the git repository at:

https://github.com/peda-r/i2c-mux.git mux-core-and-locking-5

for you to fetch changes up to c1ef4a249b0bd45ba97e14f15f6ee89e7fbc0222:

[media] rtl2832: regmap is aware of lockdep, drop local locking hack (2016-03-15 10:02:15 +0100)

----------------------------------------------------------------
Antti Palosaari (1):
[media] si2168: declare that the i2c gate is self-locked

Peter Rosin (24):
MAINTAINERS: add myself as i2c mux maintainer
i2c-mux: add common data for every i2c-mux instance
i2c: i2c-mux-gpio: convert to use an explicit i2c mux core
i2c: i2c-mux-pinctrl: convert to use an explicit i2c mux core
i2c: i2c-arb-gpio-challenge: convert to use an explicit i2c mux core
i2c: i2c-mux-pca9541: convert to use an explicit i2c mux core
i2c: i2c-mux-pca954x: convert to use an explicit i2c mux core
i2c: i2c-mux-reg: convert to use an explicit i2c mux core
iio: imu: inv_mpu6050: convert to use an explicit i2c mux core
[media] m88ds3103: convert to use an explicit i2c mux core
[media] rtl2830: convert to use an explicit i2c mux core
[media] rtl2832: convert to use an explicit i2c mux core
[media] si2168: convert to use an explicit i2c mux core
[media] cx231xx: convert to use an explicit i2c mux core
of/unittest: convert to use an explicit i2c mux core
i2c-mux: drop old unused i2c-mux api
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 self-locked muxing
i2c-mux: document i2c muxes and elaborate on parent-/self-locked muxes
iio: imu: inv_mpu6050: declare that the i2c gate is self-locked
[media] rtl2832: declare that the i2c gate is self-locked
[media] rtl2832_sdr: get rid of empty regmap wrappers
[media] rtl2832: regmap is aware of lockdep, drop local locking hack

Documentation/i2c/i2c-topology | 312 ++++++++++++++++++++++++
MAINTAINERS | 11 +
drivers/i2c/i2c-core.c | 65 +++--
drivers/i2c/i2c-mux.c | 347 ++++++++++++++++++++++-----
drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 47 ++--
drivers/i2c/muxes/i2c-mux-gpio.c | 72 +++---
drivers/i2c/muxes/i2c-mux-pca9541.c | 55 ++---
drivers/i2c/muxes/i2c-mux-pca954x.c | 64 ++---
drivers/i2c/muxes/i2c-mux-pinctrl.c | 124 +++++-----
drivers/i2c/muxes/i2c-mux-reg.c | 63 ++---
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c | 2 +-
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 75 ++----
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 3 +-
drivers/media/dvb-frontends/m88ds3103.c | 18 +-
drivers/media/dvb-frontends/m88ds3103_priv.h | 2 +-
drivers/media/dvb-frontends/rtl2830.c | 17 +-
drivers/media/dvb-frontends/rtl2830_priv.h | 2 +-
drivers/media/dvb-frontends/rtl2832.c | 236 +++---------------
drivers/media/dvb-frontends/rtl2832.h | 4 +-
drivers/media/dvb-frontends/rtl2832_priv.h | 3 +-
drivers/media/dvb-frontends/rtl2832_sdr.c | 303 ++++++++++-------------
drivers/media/dvb-frontends/rtl2832_sdr.h | 5 +-
drivers/media/dvb-frontends/si2168.c | 82 ++-----
drivers/media/dvb-frontends/si2168_priv.h | 2 +-
drivers/media/usb/cx231xx/cx231xx-core.c | 6 +-
drivers/media/usb/cx231xx/cx231xx-i2c.c | 47 ++--
drivers/media/usb/cx231xx/cx231xx.h | 4 +-
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 5 +-
drivers/of/unittest.c | 40 ++-
include/linux/i2c-mux.h | 65 ++++-
include/linux/i2c.h | 28 ++-
31 files changed, 1206 insertions(+), 903 deletions(-)
create mode 100644 Documentation/i2c/i2c-topology

2016-03-15 17:08:29

by Antti Palosaari

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] i2c mux cleanup and locking update

On 03/15/2016 04:09 PM, Peter Rosin wrote:

> The series will be posted again for review. This is just a heads up.
>
> v5 compared to v4:
> - Rebase on top of v4.5-rc7.
> - A new patch making me maintainer of i2c muxes (also sent separately).
> - A new file Documentation/i2c/i2c-topology that describes various muxing
> issues.
> - Rename "i2c-controlled" muxes "self-locked" instead, as it is perfectly
> reasonable to have i2c-controlled muxes that use the pre-existing locking
> scheme. The pre-existing locking scheme for i2c muxes is from here on
> called "parent-locked".
> - Rename i2c-mux.c:i2c_mux_master_xfer to __i2c_mux_master_xfer since it
> calls __i2c_transfer, which leaves room for a new i2c_mux_master_xfer
> that calls i2c_transfer. Similar rename shuffle for i2c_mux_smbus_xfer.
> - Use sizeof(*priv) instead of sizeof(struct i2c_mux_priv). One instance.
> - Some follow-up patches that were posted in response to v2-v4 cleaning up
> and simplifying various i2c muxes outside drivers/i2c/, among those is
> an unrelated cleanup patch to drivers/media/dvb-frontends/rtl2832.c that
> I carry here since it conflicts (trivially) with this series. That
> unrelated patch is (currently) the last patch in the series.
>
>
> The series looks like this now:
>
> The following changes since commit f6cede5b49e822ebc41a099fe41ab4989f64e2cb:
>
> Linux 4.5-rc7 (2016-03-06 14:48:03 -0800)
>
> are available in the git repository at:
>
> https://github.com/peda-r/i2c-mux.git mux-core-and-locking-5

I reviewed and tested these patches:

c1ef4a2 [media] rtl2832: regmap is aware of lockdep, drop local locking hack
6636178 [media] rtl2832_sdr: get rid of empty regmap wrappers
001ad6b [media] rtl2832: declare that the i2c gate is self-locked
e2e82e4 [media] si2168: declare that the i2c gate is self-locked
b52f766 [media] si2168: convert to use an explicit i2c mux core
4ba9115 [media] rtl2832: convert to use an explicit i2c mux core
3f1778b [media] rtl2830: convert to use an explicit i2c mux core
5c8bfc8 [media] m88ds3103: convert to use an explicit i2c mux core


Reviewed-by: Antti Palosaari <[email protected]>
Tested-by: Antti Palosaari <[email protected]>

regards
Antti

--
http://palosaari.fi/