All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
To: Michael Lawnick <ml.lawnick-Mmb7MZpHnFY@public.gmane.org>
Cc: Linux I2C <linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Rodolfo Giometti
	<giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org>
Subject: Re: [PATCH v2 1/2] i2c: Multiplexed I2C bus core support
Date: Thu, 10 Jun 2010 15:24:11 +0200	[thread overview]
Message-ID: <20100610152411.5497461c@hyperion.delvare> (raw)
In-Reply-To: <4BE01741.1010909-Mmb7MZpHnFY@public.gmane.org>

Hi Michael,

On Tue, 04 May 2010 14:46:57 +0200, Michael Lawnick wrote:
> Add multiplexed bus core support. I2C multiplexer and switches
> like pca954x get instantiated as new adapters per output.
> 
> Signed-off-by: Michael Lawnick <ml.lawnick-Mmb7MZpHnFY@public.gmane.org>
> 
> ---
> Based on kernel 2.6.33 +
> [PATCH] i2c-core: Use per-adapter userspace device lists
> by Jean Delware <20100424201914.08b3f008-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
> <http://article.gmane.org/gmane.linux.drivers.i2c/5994/>

Future patches should be based on 2.6.34 at least... 2.6.35-rc2 would
be even better.

Review follows. Need some more work I fear, but not that much... Please
let me know if you are going to submit another iteration, or if you
prefer to let me fix things the way I like (in which case I'll still
ask you to test my version of the patch when I'm done.)

> 
>  drivers/i2c/Kconfig     |    8 ++
>  drivers/i2c/Makefile    |    1 +
>  drivers/i2c/i2c-core.c  |   93 ++++++++++++++++++++++--
>  drivers/i2c/i2c-dev.c   |   46 ++++++++++++-
>  drivers/i2c/i2c-mux.c   |  184 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/i2c-mux.h |   46 ++++++++++++
>  include/linux/i2c.h     |   11 +++
>  7 files changed, 381 insertions(+), 8 deletions(-)
>  create mode 100755 drivers/i2c/i2c-mux.c
>  create mode 100755 include/linux/i2c-mux.h
> 
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 8d8a00e..2cd6d78 100755
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -36,6 +36,14 @@ config I2C_COMPAT
>  	  other user-space package which expects i2c adapters to be class
>  	  devices. If you don't know, say Y.
>  
> +config I2C_MUX
> +	tristate "I2C bus multiplexing support"
> +	depends on I2C

Dependency on I2C isn't needed: this configuration item is already
in an "if I2C" block. A dependency on EXPERIMENTAL might be a good idea
for the time being though.

> +	help
> +	  Say Y here if you want the I2C core to support the ability to
> +	  handle multiplexed I2C bus topologies, by presenting each
> +	  multiplexed segment as a I2C adapter.

For support that can be build as a module, we usually add a sentence
saying so and giving the name of the module.

> +

I would move config I2C_MUX below config I2C_CHARDEV, to make it
consistent with Makefile, and also because users expect new options to
be added after existing options.

>  config I2C_CHARDEV
>  	tristate "I2C device interface"
>  	help
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index ba26e6c..a488e8b 100755
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -5,6 +5,7 @@
>  obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
>  obj-$(CONFIG_I2C)		+= i2c-core.o
>  obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
> +obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
>  obj-y				+= busses/ chips/ algos/
>  
>  ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index fc93e28..682966a 100755
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -20,7 +20,10 @@
>  /* With some changes from Kyösti Mälkki <kmalkki-kf+aQKke1yb1KXRcyAk9cg@public.gmane.org>.
>     All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
>     SMBus 2.0 support by Mark Studebaker <mdsxyz123-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> and
> -   Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> */
> +   Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
> +   Mux support by Rodolfo Giometti <giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org> and
> +   Michael Lawnick <michael.lawnick.ext-OYasijW0DpE@public.gmane.org> */
> +

Extra blank line.

>  
>  #include <linux/module.h>
>  #include <linux/kernel.h>
> @@ -288,6 +291,12 @@ struct i2c_client *i2c_verify_client(struct device *dev)
>  }
>  EXPORT_SYMBOL(i2c_verify_client);
>  
> +static int i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
> +{
> +	return adapter->dev.parent != NULL
> +		&& adapter->dev.parent->bus == &i2c_bus_type;
> +}
> +
>  
>  /**
>   * i2c_new_device - instantiate an i2c device
> @@ -624,6 +633,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
>  
>  	rt_mutex_init(&adap->bus_lock);
>  	INIT_LIST_HEAD(&adap->userspace_clients);
> +	INIT_LIST_HEAD(&adap->mux_list_head);
>  
>  	/* Set default timeout to 1 second if not already set */
>  	if (adap->timeout == 0)
> @@ -949,9 +959,78 @@ static int __i2c_check_addr(struct device *dev, void *addrp)
>  	return 0;
>  }
>  
> +/* walk up mux tree */
> +static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
> +{
> +	int	result;
> +
> +	result = device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
> +
> +	if (!result && i2c_parent_is_i2c_adapter(adapter))
> +		result = i2c_check_mux_parents(
> +				    to_i2c_adapter(adapter->dev.parent), addr);
> +
> +	return result;
> +}
> +
> +/* recurse down mux tree */
> +static int i2c_check_mux_childs(struct i2c_adapter *adapter, int addr)

"childs" doesn't exist in proper English, the right work is "children" ;)

> +{
> +	int			result = 0;
> +	struct i2c_adapter	*child, *next;
> +
> +	list_for_each_entry_safe(child, next, &adapter->mux_list_head,
> +							 mux_list) {
> +		result = device_for_each_child(&child->dev, &addr,
> +							     __i2c_check_addr);
> +		if (result)
> +			break;
> +		result = i2c_check_mux_childs(child, addr);

This value is ignored, except for the last child. I think you should
break here too.

> +	}
> +	return result;
> +}
> +
>  static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
>  {
> -	return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
> +	int	result;
> +
> +	result = i2c_check_mux_parents(adapter, addr);
> +
> +	if (!result)
> +		result = i2c_check_mux_childs(adapter, addr);
> +
> +	return result;
> +}

I am worried about (the lack of) locking when the above function is
called. The problem isn't new with your patch, but your patch makes it
worse: beforehand, the driver core would complain if we hit a race
here, because we would try to create two clients with the same bus_id as
a result. But now, we may create 2 conflicting clients with different
bus_id, so the driver core will not complain.

I'll think about it some more, and add locking if needed.

> +static void i2c_mux_tree_lock(struct i2c_adapter *adap)
> +{
> +	if (i2c_parent_is_i2c_adapter(adap))
> +		i2c_mux_tree_lock(to_i2c_adapter(adap->dev.parent));
> +	else
> +		i2c_lock_adapter(adap);
> +}
> +
> +static int i2c_mux_tree_trylock(struct i2c_adapter *adap)
> +{
> +	int			ret;
> +	struct i2c_adapter	*parent;
> +
> +	if (i2c_parent_is_i2c_adapter(adap)) {
> +		parent = to_i2c_adapter(adap->dev.parent);
> +		ret = i2c_mux_tree_trylock(parent);
> +	} else {
> +		ret = i2c_trylock_adapter(adap);
> +	}
> +
> +	return ret;
> +}
> +
> +static void i2c_mux_tree_unlock(struct i2c_adapter *adap)
> +{
> +	if (i2c_parent_is_i2c_adapter(adap))
> +		i2c_mux_tree_unlock(to_i2c_adapter(adap->dev.parent));
> +	else
> +		i2c_unlock_adapter(adap);
>  }
>  
>  /**
> @@ -1104,12 +1183,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
>  #endif
>  
>  		if (in_atomic() || irqs_disabled()) {
> -			ret = rt_mutex_trylock(&adap->bus_lock);
> +			ret = i2c_mux_tree_trylock(adap);
>  			if (!ret)
>  				/* I2C activity is ongoing. */
>  				return -EAGAIN;
>  		} else {
> -			rt_mutex_lock(&adap->bus_lock);
> +			i2c_mux_tree_lock(adap);
>  		}
>  
>  		/* Retry automatically on arbitration loss */
> @@ -1121,7 +1200,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
>  			if (time_after(jiffies, orig_jiffies + adap->timeout))
>  				break;
>  		}
> -		rt_mutex_unlock(&adap->bus_lock);
> +		i2c_mux_tree_unlock(adap);
>  
>  		return ret;
>  	} else {
> @@ -1857,7 +1936,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
>  	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
>  
>  	if (adapter->algo->smbus_xfer) {
> -		rt_mutex_lock(&adapter->bus_lock);
> +		i2c_mux_tree_lock(adapter);
>  
>  		/* Retry automatically on arbitration loss */
>  		orig_jiffies = jiffies;
> @@ -1871,7 +1950,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
>  				       orig_jiffies + adapter->timeout))
>  				break;
>  		}
> -		rt_mutex_unlock(&adapter->bus_lock);
> +		i2c_mux_tree_unlock(adapter);
>  	} else
>  		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
>  					      command, protocol, data);

I'm worried that this approach is risky. We now use i2c_mux_tree_*lock
internally, but still expose the i2c_*lock_adapter() API externally.
This API is _not_ mux-aware, and will do the wrong thing if called on a
bus segment behind a mux.

I'd rather not have two APIs when we really only need one. Let's just
update the current public API to be mux-aware, and use that everywhere.

> diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
> index f4110aa..da5327f 100755
> --- a/drivers/i2c/i2c-dev.c
> +++ b/drivers/i2c/i2c-dev.c
> @@ -193,12 +193,56 @@ static int i2cdev_check(struct device *dev, void *addrp)
>  	return dev->driver ? -EBUSY : 0;
>  }
>  
> +static int i2cdev_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
> +{
> +	return adapter->dev.parent != NULL
> +		&& adapter->dev.parent->bus == &i2c_bus_type;
> +}

This is an exact duplicate of the same function in i2c-core. I'd rather
make it an inline function in <linux/i2c.h>, or export the one from
i2c-core.c. We have enough duplicate code in i2c-dev.c already :(

> +
> +/* walk up mux tree */
> +static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
> +{
> +	int result;
> +
> +	result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
> +
> +	if (!result && i2cdev_parent_is_i2c_adapter(adapter))
> +		result = i2cdev_check_mux_parents(
> +				    to_i2c_adapter(adapter->dev.parent), addr);
> +
> +	return result;
> +}
> +
> +/* recurse down mux tree */
> +static int i2cdev_check_mux_childs(struct i2c_adapter *adapter, int addr)

children

> +{
> +	int result = 0;
> +	struct i2c_adapter *child, *next;
> +
> +	list_for_each_entry_safe(child, next, &adapter->mux_list_head,
> +				 mux_list) {
> +		result = device_for_each_child(&child->dev, &addr,
> +					       i2cdev_check);
> +		if (result)
> +			break;
> +		result = i2cdev_check_mux_childs(child, addr);

Same as in the i2c-core variant, this value is ignored, I think this
isn't correct.

> +	}
> +	return result;
> +}
> +
>  /* This address checking function differs from the one in i2c-core
>     in that it considers an address with a registered device, but no
>     driver bound to it, as NOT busy. */
>  static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
>  {
> -	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
> +	int result;
> +
> +	result = i2cdev_check_mux_parents(adapter, addr);
> +
> +	if (!result)
> +		result = i2cdev_check_mux_childs(adapter, addr);
> +
> +	return result;
>  }
>  
>  static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
> new file mode 100755
> index 0000000..f88d29a
> --- /dev/null
> +++ b/drivers/i2c/i2c-mux.c
> @@ -0,0 +1,184 @@
> +/*
> + * Multiplexed I2C bus driver.
> + *
> + * Copyright (c) 2008-2009 Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
> + * Copyright (c) 2008-2009 Eurotech S.p.A. <info-ymFC7zkAqBI1GQ1Ptb7lUw@public.gmane.org>
> + *
> + * Simplifies access to complex multiplexed I2C bus topologies, by presenting
> + * each multiplexed bus segment as an additional I2C adapter.
> + * Supports multi-level mux'ing (mux behind a mux).
> + *
> + * Based on:
> + *	i2c-virt.c from Kumar Gala <galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
> + *	i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc.
> + *	i2c-virtual.c from Brian Kuschak <bkuschak-/E1597aS9LQAvxtiuMwx3w@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +/* Adapted to kernel 2.6.33 by Michael Lawnick <michael.lawnick.ext@nsn.com> */

I'd rather have you add your copyright with the other ones already
present above.

> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-mux.h>
> +
> +/* multiplexer per channel data */
> +struct i2c_mux_priv {
> +	struct i2c_adapter adap;
> +	struct i2c_algorithm algo;
> +
> +	struct i2c_adapter *parent;
> +	void *mux_dev;	/* the mux chip/device */
> +	u32  chan_id;	/* the channel id */
> +
> +	int (*select)(struct i2c_adapter *adap, void *mux_dev, u32 chan_id);
> +	int (*deselect)(struct i2c_adapter *adap, void *mux_dev, u32 chan_id);

The two "adap" can go away... I insisted on having parameter names for
the other two; for structures, it's usually pretty clear what we're
talking about.

> +};
> +
> +#define VIRT_TIMEOUT		(HZ/2)
> +#define VIRT_RETRIES		3

These two are no longer used and can thus be deleted.

> +
> +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;
> +	int ret;
> +
> +	/* Switch to the right mux port and perform the transfer.*/

Missing space at end of comment.

> +
> +	ret = priv->select(parent, priv->mux_dev, priv->chan_id);
> +	if (ret >= 0)
> +		ret = parent->algo->master_xfer(parent, msgs, num);
> +	if (priv->deselect)
> +		priv->deselect(parent, priv->mux_dev, 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,
> +			      int size, union i2c_smbus_data *data)
> +{
> +	struct i2c_mux_priv *priv = adap->algo_data;
> +	struct i2c_adapter *parent = priv->parent;
> +	int ret;
> +
> +	/* Select the right mux port and perform the transfer.*/

Ditto.

> +
> +	ret = priv->select(parent, priv->mux_dev, priv->chan_id);
> +	if (ret >= 0)
> +		ret = parent->algo->smbus_xfer(parent, addr, flags,
> +					   read_write, command, size, data);

Strange alignment.

> +	if (priv->deselect)
> +		priv->deselect(parent, priv->mux_dev, priv->chan_id);
> +
> +	return ret;
> +}
> +
> +/* Return the parent's functionality for the virtual adapter */

Please avoid referring to "virtual adapters". The fact here is that all
bus segments of a given tree share the same functionality, because it
is a characteristic of the controller - nothing virtual here.

> +static u32 i2c_mux_functionality(struct i2c_adapter *adap)
> +{
> +	struct i2c_mux_priv *priv = adap->algo_data;
> +	struct i2c_adapter *parent = priv->parent;
> +
> +	return parent->algo->functionality(parent);
> +}
> +
> +struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
> +				void *mux_dev, u32 force_nr, u32 chan_id,
> +				int (*select) (struct i2c_adapter *,
> +					       void *, u32),
> +				int (*deselect) (struct i2c_adapter *,
> +						 void *, u32))
> +{
> +	struct i2c_mux_priv *priv;
> +	int ret;
> +
> +	priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
> +	if (!priv)
> +		return NULL;
> +
> +	/* Set up private adapter data */
> +	priv->parent = parent;
> +	priv->mux_dev = mux_dev;
> +	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.
> +	 */
> +	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;
> +	priv->algo.functionality = i2c_mux_functionality;
> +
> +	/* Now fill out new adapter structure */
> +	snprintf(priv->adap.name, sizeof(priv->adap.name),
> +		 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);

I'm only half happy with this name. One problem is that it isn't
unique: if you have 2 mux chips on the same root segment, this will
lead to duplicate segments with the same name. Another problem is that
it completely hides the name of the controller (which, I admit, we may
recover by walking sysfs, but still...)

This isn't a blocker point, but something to keep in mind for further
improvements. It might even make sense to let the caller provide the
format for the segment names.

> +	priv->adap.owner = THIS_MODULE;
> +	priv->adap.id = parent->id;
> +	priv->adap.algo = &priv->algo;
> +	priv->adap.algo_data = priv;
> +	priv->adap.dev.parent = &parent->dev;
> +
> +	if (force_nr) {
> +		priv->adap.nr = force_nr;
> +		ret = i2c_add_numbered_adapter(&priv->adap);
> +	} else {
> +		ret = i2c_add_adapter(&priv->adap);
> +	}
> +	if (ret < 0) {
> +		dev_err(&parent->dev, "failed to add mux-adapter (error=%d)\n",
> +			ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	list_add_tail(&priv->adap.mux_list, &parent->mux_list_head);

The driver core maintains a device tree already, do you really need to
keep your own? We've tried hard to remove all redundancy between
i2c-core and the driver core in the last couple years, so I really would
like us to not add such redundancy back now.

If you have a good reason to have your own list, please explain. If
not, please get rid of it.

> +
> +	dev_info(&parent->dev, "i2c-mux-%d: Multiplexed I2C bus on "
> +		"parent bus i2c-%d, chan_id %d\n",
> +		i2c_adapter_id(&priv->adap), i2c_adapter_id(parent), chan_id);

Have you looked at the output? I expect some redundancy, as you use
dev_info() on the parent, i2c_adapter_id(parent) is already included. I
think I'd rather call dev_info() on the newly spawned child, so you can
get rid of the leading "i2c-mux-%d". BTW, please use dev_name() instead
of hard-coding i2c-%d for the parent.

> +
> +	return &priv->adap;
> +}
> +EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
> +
> +int i2c_del_mux_adapter(struct i2c_adapter *adap)
> +{
> +	struct i2c_mux_priv *priv = adap->algo_data;
> +	int ret;
> +	struct i2c_adapter *child, *next, *parent;

Would look nicer with all structs in front and ret last, IMHO.

> +
> +	if (adap->dev.parent != NULL
> +		&& adap->dev.parent->bus == &i2c_bus_type) {

This is a copy of i2c_parent_is_i2c_adapter(), isn't it? That's one
more reason to export it from i2c-core.

> +		parent = to_i2c_adapter(adap->dev.parent);

Note that we could have i2c_parent_is_i2c_adapter() return the parent
adapter, if it proves useful in practice.

> +		list_for_each_entry_safe(child, next, &parent->mux_list_head,
> +					 mux_list) {
> +			if (child == adap) {
> +				list_del(&child->mux_list);
> +				break;
> +			}
> +		}
> +	}

That being said... Using the driver core's list would save you the
hassle altogether.

> +
> +	ret = i2c_del_adapter(adap);
> +	if (ret < 0)
> +		return ret;
> +	kfree(priv);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
> +
> +MODULE_AUTHOR("Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>");
> +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
> new file mode 100755
> index 0000000..0d5d6c8
> --- /dev/null
> +++ b/include/linux/i2c-mux.h
> @@ -0,0 +1,46 @@
> +/*
> + *
> + * i2c-mux.h - functions for the i2c-bus mux support
> + *
> + * Copyright (c) 2008-2009 Rodolfo Giometti <giometti-k2GhghHVRtY@public.gmane.org>
> + * Copyright (c) 2008-2009 Eurotech S.p.A. <info-ymFC7zkAqBI1GQ1Ptb7lUw@public.gmane.org>
> + * Michael Lawnick <michael.lawnick.ext-OYasijW0DpE@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _LINUX_I2C_MUX_H
> +#define _LINUX_I2C_MUX_H
> +
> +#ifdef __KERNEL__
> +
> +/*
> + * 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,
> +				void *mux_dev, u32 force_nr, u32 chan_id,
> +				int (*select) (struct i2c_adapter *adap,
> +					       void *mux_dev, u32 chan_id),
> +				int (*deselect) (struct i2c_adapter *,
> +						 void *mux_dev, u32 chan_id));
> +
> +int i2c_del_mux_adapter(struct i2c_adapter *adap);
> +
> +#endif /* __KERNEL__ */
> +
> +#endif /* _LINUX_I2C_H */

You actually mean /* _LINUX_I2C_MUX_H */.

> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
> index 1fd7b12..898a8c1 100755
> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -349,6 +349,8 @@ struct i2c_adapter {
>  	struct completion dev_released;
>  
>  	struct list_head userspace_clients;
> +	struct list_head mux_list_head;
> +	struct list_head mux_list;

As said before, I would much prefer if we didn't have to introduce
these.

>  };
>  #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
>  
> @@ -380,6 +382,15 @@ static inline void i2c_unlock_adapter(struct i2c_adapter *adapter)
>  	rt_mutex_unlock(&adapter->bus_lock);
>  }
>  
> +/**
> + * i2c_trylock_adapter - Try to prevent access to an I2C bus segment
> + * @adapter: Target I2C bus segment
> + */
> +static inline int i2c_trylock_adapter(struct i2c_adapter *adapter)
> +{
> +	return rt_mutex_trylock(&adapter->bus_lock);
> +}
> +
>  /*flags for the client struct: */
>  #define I2C_CLIENT_PEC	0x04		/* Use Packet Error Checking */
>  #define I2C_CLIENT_TEN	0x10		/* we have a ten bit chip address */

Thanks,
-- 
Jean Delvare

  parent reply	other threads:[~2010-06-10 13:24 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-04 12:46 [PATCH v2 1/2] i2c: Multiplexed I2C bus core support Michael Lawnick
     [not found] ` <4BE01741.1010909-Mmb7MZpHnFY@public.gmane.org>
2010-05-04 12:48   ` [PATCH v2 2/2] i2c: Multiplexed I2C bus multiplexer driver pca954x Michael Lawnick
     [not found]     ` <4BE01795.1090605-Mmb7MZpHnFY@public.gmane.org>
2010-05-04 12:52       ` Rodolfo Giometti
2010-06-09 16:41       ` Jean Delvare
     [not found]         ` <20100609184143.06488f2f-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2010-06-10 10:15           ` Michael Lawnick
2010-06-13 12:11       ` Jean Delvare
     [not found]         ` <20100613141122.1d5b1423-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2010-06-14  9:09           ` Michael Lawnick
2010-05-04 12:52   ` [PATCH v2 1/2] i2c: Multiplexed I2C bus core support Rodolfo Giometti
2010-05-17  7:36   ` Michael Lawnick
     [not found]     ` <4BF0F200.5090604-Mmb7MZpHnFY@public.gmane.org>
2010-05-17  8:15       ` Jean Delvare
2010-06-10 13:24   ` Jean Delvare [this message]
     [not found]     ` <20100610152411.5497461c-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2010-06-11  6:31       ` Michael Lawnick
     [not found]         ` <4C11D85F.7010604-Mmb7MZpHnFY@public.gmane.org>
2010-06-11  9:40           ` Jean Delvare
     [not found]             ` <20100611114003.01c15f62-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2010-06-15  8:53               ` Michael Lawnick
2010-06-15  8:52       ` Michael Lawnick
     [not found]         ` <4C173F61.8000007-Mmb7MZpHnFY@public.gmane.org>
2010-06-15  9:00           ` Jean Delvare
  -- strict thread matches above, loose matches on Subject: below --
2010-05-04 12:29 Michael Lawnick
     [not found] ` <4BE01321.3060704-Mmb7MZpHnFY@public.gmane.org>
2010-05-04 12:33   ` Rodolfo Giometti
2010-05-04 12:37   ` Michael Lawnick
     [not found]     ` <4BE014ED.9070907-Mmb7MZpHnFY@public.gmane.org>
2010-05-04 15:19       ` Yegor Yefremov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100610152411.5497461c@hyperion.delvare \
    --to=khali-puyad+kwke1g9huczpvpmw@public.gmane.org \
    --cc=giometti-AVVDYK/kqiJWk0Htik3J/w@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=ml.lawnick-Mmb7MZpHnFY@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.