Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: core: introduce callbacks for atomic transfers

We had the request to access devices very late when interrupts are not
available anymore multiple times now. Mostly to prepare shutdown or
reboot. Allow adapters to specify a specific callback for this case.
Note that we fall back to the generic {master|smbus}_xfer callback if
this new atomic one is not present. This is intentional to preserve the
previous behaviour and avoid regressions. Because there are drivers not
using interrupts or because it might have worked "accidently" before.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Stefan Lengfeld <contact@stefanchrist.eu>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Wolfram Sang and committed by
Wolfram Sang
63b96983 83c42212

+36 -10
+5 -1
drivers/i2c/i2c-core-base.c
··· 1890 1890 /* Retry automatically on arbitration loss */ 1891 1891 orig_jiffies = jiffies; 1892 1892 for (ret = 0, try = 0; try <= adap->retries; try++) { 1893 - ret = adap->algo->master_xfer(adap, msgs, num); 1893 + if (i2c_in_atomic_xfer_mode() && adap->algo->master_xfer_atomic) 1894 + ret = adap->algo->master_xfer_atomic(adap, msgs, num); 1895 + else 1896 + ret = adap->algo->master_xfer(adap, msgs, num); 1897 + 1894 1898 if (ret != -EAGAIN) 1895 1899 break; 1896 1900 if (time_after(jiffies, orig_jiffies + adap->timeout))
+14 -4
drivers/i2c/i2c-core-smbus.c
··· 548 548 unsigned short flags, char read_write, 549 549 u8 command, int protocol, union i2c_smbus_data *data) 550 550 { 551 + int (*xfer_func)(struct i2c_adapter *adap, u16 addr, 552 + unsigned short flags, char read_write, 553 + u8 command, int size, union i2c_smbus_data *data); 551 554 unsigned long orig_jiffies; 552 555 int try; 553 556 s32 res; ··· 565 562 566 563 flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; 567 564 568 - if (adapter->algo->smbus_xfer) { 565 + xfer_func = adapter->algo->smbus_xfer; 566 + if (i2c_in_atomic_xfer_mode()) { 567 + if (adapter->algo->smbus_xfer_atomic) 568 + xfer_func = adapter->algo->smbus_xfer_atomic; 569 + else if (adapter->algo->master_xfer_atomic) 570 + xfer_func = NULL; /* fallback to I2C emulation */ 571 + } 572 + 573 + if (xfer_func) { 569 574 /* Retry automatically on arbitration loss */ 570 575 orig_jiffies = jiffies; 571 576 for (res = 0, try = 0; try <= adapter->retries; try++) { 572 - res = adapter->algo->smbus_xfer(adapter, addr, flags, 573 - read_write, command, 574 - protocol, data); 577 + res = xfer_func(adapter, addr, flags, read_write, 578 + command, protocol, data); 575 579 if (res != -EAGAIN) 576 580 break; 577 581 if (time_after(jiffies,
+5 -2
drivers/i2c/i2c-core.h
··· 43 43 { 44 44 int ret = 0; 45 45 46 - if (i2c_in_atomic_xfer_mode()) 46 + if (i2c_in_atomic_xfer_mode()) { 47 + WARN(!adap->algo->master_xfer_atomic && !adap->algo->smbus_xfer_atomic, 48 + "No atomic I2C transfer handler for '%s'\n", dev_name(&adap->dev)); 47 49 ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT) ? 0 : -EAGAIN; 48 - else 50 + } else { 49 51 i2c_lock_bus(adap, I2C_LOCK_SEGMENT); 52 + } 50 53 51 54 return ret; 52 55 }
+12 -3
include/linux/i2c.h
··· 499 499 * @master_xfer: Issue a set of i2c transactions to the given I2C adapter 500 500 * defined by the msgs array, with num messages available to transfer via 501 501 * the adapter specified by adap. 502 + * @master_xfer_atomic: same as @master_xfer. Yet, only using atomic context 503 + * so e.g. PMICs can be accessed very late before shutdown. Optional. 502 504 * @smbus_xfer: Issue smbus transactions to the given I2C adapter. If this 503 505 * is not present, then the bus layer will try and convert the SMBus calls 504 506 * into I2C transfers instead. 507 + * @smbus_xfer_atomic: same as @smbus_xfer. Yet, only using atomic context 508 + * so e.g. PMICs can be accessed very late before shutdown. Optional. 505 509 * @functionality: Return the flags that this algorithm/adapter pair supports 506 510 * from the I2C_FUNC_* flags. 507 511 * @reg_slave: Register given client to I2C slave mode of this adapter ··· 516 512 * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 517 513 * to name two of the most common. 518 514 * 519 - * The return codes from the @master_xfer field should indicate the type of 520 - * error code that occurred during the transfer, as documented in the kernel 521 - * Documentation file Documentation/i2c/fault-codes. 515 + * The return codes from the @master_xfer{_atomic} fields should indicate the 516 + * type of error code that occurred during the transfer, as documented in the 517 + * Kernel Documentation file Documentation/i2c/fault-codes. 522 518 */ 523 519 struct i2c_algorithm { 524 520 /* ··· 532 528 */ 533 529 int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, 534 530 int num); 531 + int (*master_xfer_atomic)(struct i2c_adapter *adap, 532 + struct i2c_msg *msgs, int num); 535 533 int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, 536 534 unsigned short flags, char read_write, 537 535 u8 command, int size, union i2c_smbus_data *data); 536 + int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr, 537 + unsigned short flags, char read_write, 538 + u8 command, int size, union i2c_smbus_data *data); 538 539 539 540 /* To determine what the adapter supports */ 540 541 u32 (*functionality)(struct i2c_adapter *adap);