diff options
| author | Jean Delvare <khali@linux-fr.org> | 2012-06-29 06:47:19 -0400 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-29 18:03:25 -0400 |
| commit | b37d2a3a75cb0e72e18c29336cb2095b63dabfc8 (patch) | |
| tree | 212e01d73f40881626b54ef4811de3a061788989 | |
| parent | a99817ca60d206be3645d156f755cf065e949c58 (diff) | |
[media] i2c: Export an unlocked flavor of i2c_transfer
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>
| -rw-r--r-- | drivers/i2c/i2c-core.c | 44 | ||||
| -rw-r--r-- | include/linux/i2c.h | 3 |
2 files changed, 36 insertions, 11 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index feb7dc359186..ccc6445979c4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
| @@ -1295,6 +1295,37 @@ module_exit(i2c_exit); | |||
| 1295 | */ | 1295 | */ |
| 1296 | 1296 | ||
| 1297 | /** | 1297 | /** |
| 1298 | * __i2c_transfer - unlocked flavor of i2c_transfer | ||
| 1299 | * @adap: Handle to I2C bus | ||
| 1300 | * @msgs: One or more messages to execute before STOP is issued to | ||
| 1301 | * terminate the operation; each message begins with a START. | ||
| 1302 | * @num: Number of messages to be executed. | ||
| 1303 | * | ||
| 1304 | * Returns negative errno, else the number of messages executed. | ||
| 1305 | * | ||
| 1306 | * Adapter lock must be held when calling this function. No debug logging | ||
| 1307 | * takes place. adap->algo->master_xfer existence isn't checked. | ||
| 1308 | */ | ||
| 1309 | int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
| 1310 | { | ||
| 1311 | unsigned long orig_jiffies; | ||
| 1312 | int ret, try; | ||
| 1313 | |||
| 1314 | /* Retry automatically on arbitration loss */ | ||
| 1315 | orig_jiffies = jiffies; | ||
| 1316 | for (ret = 0, try = 0; try <= adap->retries; try++) { | ||
| 1317 | ret = adap->algo->master_xfer(adap, msgs, num); | ||
| 1318 | if (ret != -EAGAIN) | ||
| 1319 | break; | ||
| 1320 | if (time_after(jiffies, orig_jiffies + adap->timeout)) | ||
| 1321 | break; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | return ret; | ||
| 1325 | } | ||
| 1326 | EXPORT_SYMBOL(__i2c_transfer); | ||
| 1327 | |||
| 1328 | /** | ||
| 1298 | * i2c_transfer - execute a single or combined I2C message | 1329 | * i2c_transfer - execute a single or combined I2C message |
| 1299 | * @adap: Handle to I2C bus | 1330 | * @adap: Handle to I2C bus |
| 1300 | * @msgs: One or more messages to execute before STOP is issued to | 1331 | * @msgs: One or more messages to execute before STOP is issued to |
| @@ -1308,8 +1339,7 @@ module_exit(i2c_exit); | |||
| 1308 | */ | 1339 | */ |
| 1309 | int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | 1340 | int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) |
| 1310 | { | 1341 | { |
| 1311 | unsigned long orig_jiffies; | 1342 | int ret; |
| 1312 | int ret, try; | ||
| 1313 | 1343 | ||
| 1314 | /* REVISIT the fault reporting model here is weak: | 1344 | /* REVISIT the fault reporting model here is weak: |
| 1315 | * | 1345 | * |
| @@ -1347,15 +1377,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
| 1347 | i2c_lock_adapter(adap); | 1377 | i2c_lock_adapter(adap); |
| 1348 | } | 1378 | } |
| 1349 | 1379 | ||
| 1350 | /* Retry automatically on arbitration loss */ | 1380 | ret = __i2c_transfer(adap, msgs, num); |
| 1351 | orig_jiffies = jiffies; | ||
| 1352 | for (ret = 0, try = 0; try <= adap->retries; try++) { | ||
| 1353 | ret = adap->algo->master_xfer(adap, msgs, num); | ||
| 1354 | if (ret != -EAGAIN) | ||
| 1355 | break; | ||
| 1356 | if (time_after(jiffies, orig_jiffies + adap->timeout)) | ||
| 1357 | break; | ||
| 1358 | } | ||
| 1359 | i2c_unlock_adapter(adap); | 1381 | i2c_unlock_adapter(adap); |
| 1360 | 1382 | ||
| 1361 | return ret; | 1383 | return ret; |
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 195d8b3d9cfb..a121c012309a 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
| @@ -68,6 +68,9 @@ extern int i2c_master_recv(const struct i2c_client *client, char *buf, | |||
| 68 | */ | 68 | */ |
| 69 | extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | 69 | extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| 70 | int num); | 70 | int num); |
| 71 | /* Unlocked flavor */ | ||
| 72 | extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||
| 73 | int num); | ||
| 71 | 74 | ||
| 72 | /* This is the very generalized SMBus access routine. You probably do not | 75 | /* This is the very generalized SMBus access routine. You probably do not |
| 73 | want to use this, though; one of the functions below may be much easier, | 76 | want to use this, though; one of the functions below may be much easier, |
