Skip to content

Commit

Permalink
[media] i2c: Export an unlocked flavor of i2c_transfer
Browse files Browse the repository at this point in the history
Some drivers (in particular for TV cards) need exclusive access to
their I2C buses for specific operations. Export an unlocked flavor
of i2c_transfer to give them full control.

The unlocked flavor has the following limitations:
* Obviously, caller must hold the i2c adapter lock.
* No debug messages are logged. We don't want to log messages while
  holding a rt_mutex.
* No check is done on the existence of adap->algo->master_xfer. It
  is thus the caller's responsibility to ensure that the function is
  OK to call.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Jean Delvare authored and Mauro Carvalho Chehab committed Jun 29, 2012
1 parent a99817c commit b37d2a3
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
44 changes: 33 additions & 11 deletions drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,37 @@ module_exit(i2c_exit);
* ----------------------------------------------------
*/

/**
* __i2c_transfer - unlocked flavor of i2c_transfer
* @adap: Handle to I2C bus
* @msgs: One or more messages to execute before STOP is issued to
* terminate the operation; each message begins with a START.
* @num: Number of messages to be executed.
*
* Returns negative errno, else the number of messages executed.
*
* Adapter lock must be held when calling this function. No debug logging
* takes place. adap->algo->master_xfer existence isn't checked.
*/
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;

/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}

return ret;
}
EXPORT_SYMBOL(__i2c_transfer);

/**
* i2c_transfer - execute a single or combined I2C message
* @adap: Handle to I2C bus
Expand All @@ -1308,8 +1339,7 @@ module_exit(i2c_exit);
*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
int ret;

/* REVISIT the fault reporting model here is weak:
*
Expand Down Expand Up @@ -1347,15 +1377,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
i2c_lock_adapter(adap);
}

/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_adapter(adap);

return ret;
Expand Down
3 changes: 3 additions & 0 deletions include/linux/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ extern int i2c_master_recv(const struct i2c_client *client, char *buf,
*/
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
/* Unlocked flavor */
extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);

/* This is the very generalized SMBus access routine. You probably do not
want to use this, though; one of the functions below may be much easier,
Expand Down

0 comments on commit b37d2a3

Please sign in to comment.