[i2c] [PATCH] Add polling transfer for i2c-pxa
Jean Delvare
khali at linux-fr.org
Wed Dec 5 17:58:34 CET 2007
Hi Mike,
On Tue, 04 Dec 2007 11:24:06 +0200, Mike Rapoport wrote:
> I've added per-adapter 'use_pio' flag, and a method allowing platform code
> to enable this flag.
>
> Signed-off-by: Mike Rapoport <mike at compulab.co.il>
>
> arch/arm/mach-pxa/pxa27x.c | 6 ++
> drivers/i2c/busses/i2c-pxa.c | 123 ++++++++++++++++++++++++++++++++++++----
> drivers/i2c/i2c-core.c | 47 ++++++++++-----
> include/asm-arm/arch-pxa/i2c.h | 6 ++
> include/linux/i2c.h | 5 ++
> 5 files changed, 161 insertions(+), 26 deletions(-)
For proper submission, this needs to be split into two parts: the
i2c-core changes in one patch and the i2c-pxa implementation in another.
I can only comment on the i2c-core part:
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index b5e13e4..5c21035 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -864,30 +864,47 @@ module_exit(i2c_exit);
> * the functional interface to the i2c busses.
> * ----------------------------------------------------
> */
> -
Please revert this whitespace change.
> int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
> {
> int ret;
> + int (*xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
>
> - if (adap->algo->master_xfer) {
> -#ifdef DEBUG
> - for (ret = 0; ret < num; ret++) {
> - dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
> - "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
> - ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
> - (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
> + if (in_atomic() || irqs_disabled()) {
You need to include <linux/hardirq.h> for in_atomic() to be defined,
and <linux/irqflags.h> for irqs_disabled().
> + if (adap->algo->pio_xfer == NULL) {
if (!adap->algo->pio_xfer) {
> + pr_debug("%s: algo has no poll xfer", __FUNCTION__);
Please use dev_dbg() instead.
> + return -EINVAL;
> }
> -#endif
> -
> - mutex_lock_nested(&adap->bus_lock, adap->level);
> - ret = adap->algo->master_xfer(adap,msgs,num);
> - mutex_unlock(&adap->bus_lock);
> -
> - return ret;
> + ret = mutex_trylock(&adap->bus_lock);
You don't pass the nesting level here. I guess that lockdep will
complain? OTOH there doesn't appear to be a mutex_trylock_nested()
defined anywhere...
> + if (ret) { /* We get bus_lock, no ongoing I2C activity */
Just to make things clear: no ongoing I2C activity _on the Linux side_.
The bus might still be busy if there are other masters; then you'll
find out later.
> + ret = adap->algo->pio_xfer(adap, msgs, num);
> + mutex_unlock(&adap->bus_lock);
> + return ret;
> + } else {
> + /* I2C activity is ongoing. */
> + return -EBUSY;
-EAGAIN seems more suited.
> + }
> + } else if (adap->use_pio && adap->algo->pio_xfer != NULL) {
The "else" isn't needed, as all code paths above have already returned.
Drop "!= NULL".
> + xfer = adap->algo->pio_xfer;
> + } else if (adap->algo->master_xfer) {
> + xfer = adap->algo->master_xfer;
> } else {
> dev_dbg(&adap->dev, "I2C level transfers not supported\n");
> return -ENOSYS;
> }
> +
> +#ifdef DEBUG
> + for (ret = 0; ret < num; ret++)
> + dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
> + "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
> + ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
> + (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
> +#endif
> +
> + mutex_lock_nested(&adap->bus_lock, adap->level);
> + ret = xfer(adap, msgs, num);
> + mutex_unlock(&adap->bus_lock);
> +
> + return ret;
> }
> EXPORT_SYMBOL(i2c_transfer);
>
> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
> index a100c9f..2976c15 100644
> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -290,6 +290,10 @@ struct i2c_algorithm {
> unsigned short flags, char read_write,
> u8 command, int size, union i2c_smbus_data * data);
>
> + /* PIO xfer can be used in no-interrupts context */
> + int (*pio_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
> + int num);
> +
I don't like the name "pio_xfer", for two reasons.
First reason is that we currently have two possible transfer methods,
smbus_xfer and master_xfer. "pio_xfer" doesn't make it clear what
transfer method is being "replaced". The name should include "master"
to make it clear that it is a replacement for master_xfer, not
smbus_xfer. We might want a similar mechanism to "replace" smbus_xfer
in the future.
Second reason is that many drivers _already_ do polled I/O in
master_xfer and/or smbus_xfer. What makes pio_xfer different is more
than just "can't use interrupts", if I understand correctly it also
means that we can't sleep, right? And maybe other limitations. So I'd
like a more generic name that doesn't focus on polled I/O.
> /* To determine what the adapter supports */
> u32 (*functionality) (struct i2c_adapter *);
> };
> @@ -304,6 +308,7 @@ struct i2c_adapter {
> unsigned int class;
> const struct i2c_algorithm *algo; /* the algorithm to access the bus */
> void *algo_data;
> + int use_pio;
I'm curious how many drivers will need this; I'm not sure I see the
value. This could be implemented at the driver-level as well, and I
think I'd prefer it that way, unless you have reasons to believe that
many drivers will want this.
>
> /* --- administration stuff. */
> int (*client_register)(struct i2c_client *);
>
--
Jean Delvare
More information about the i2c
mailing list