[i2c] [PATCH] Add polling transfer for i2c-pxa
Mike Rapoport
mike at compulab.co.il
Tue Nov 20 08:41:51 CET 2007
Russell King - ARM Linux wrote:
> On Mon, Nov 19, 2007 at 05:24:23PM +0200, Mike Rapoport wrote:
>> Russell King - ARM Linux wrote:
>>> A couple of other points...
>>>
>>> On Wed, Nov 14, 2007 at 09:21:59AM +0200, Mike Rapoport wrote:
>>>> #include "i2c-core.h"
>>>> @@ -870,7 +871,24 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
>>>> {
>>>> int ret;
>>>>
>>>> - if (adap->algo->master_xfer) {
>>>> + if (in_atomic() || irqs_disabled()) {
>>> I wonder if it'd make more sense for this to be a per-adapter flag?
>>> Eg, so you could switch the bus with the PMIC on to always use PIO
>>> transfers.
>> I'm not sure that making the bus with the PMIC on to always use PIO
>> transfers is good idea. As Eric pointed there may be other devices
>> on the same bus.
>
> That's exactly why I'm suggesting it - so that the bus is driven in the
> same way all the time.
>
> Normal devices shouldn't care that it's being driven in PIO mode - they
> don't know that it is.
The test for irqs_disabled() is needed to avoid mutex_lock in interrupts-off
contexts. So, probably we should have both per-adapter flag and this test. Then
we can use PIO transfers in interrupts-off contexts for any bus that supports
it, and we can always use PIO for bus that has appropriate flag set. It can be,
for instance, something like:
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 (in_atomic() || irqs_disabled()) {
int retries = 1;
if (adap->algo->pio_xfer == NULL) {
pr_debug("%s: algo has no poll xfer", __FUNCTION__);
return -EINVAL;
}
ret = mutex_trylock(&adap->bus_lock);
if (ret) { /* We get bus_lock, no ongoing I2C activity */
ret = adap->algo->pio_xfer(adap, msgs, num);
mutex_unlock(&adap->bus_lock);
return ret;
} else {
/* I2C activity is ongoing. */
/* FIXME: may be we should take the lock and
abandon ongoing transfer */
return -EBUSY;
}
} else if (adap->use_pio && adap->algo->pio_xfer != 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;
}
--
Sincerely yours,
Mike.
More information about the i2c
mailing list