diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-09 14:41:55 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-09 14:41:55 -0700 |
commit | 45182e4e1f8ac04708ca7508c51d9103f07d81ab (patch) | |
tree | ec8e7131c686bfec6cdd8a7ba6757d5b8fef22bb /drivers/i2c/i2c-core-smbus.c | |
parent | 06cbd26d312edfe4a83ff541c23f8f866265eb24 (diff) | |
parent | e6ae3ca27477226eae77cc00d5fad89d7ce64aea (diff) |
Merge branch 'i2c/for-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
- API for late atomic transfers (e.g. to shut down via PMIC). We have a
seperate callback now which is called under clearly defined
conditions. In-kernel users are converted, too.
- new driver for the AMD PCIe MP2 I2C controller
- large refactoring for at91 and bcm-iproc (both gain slave support due
to this)
- and a good share of various driver improvements anf fixes
* 'i2c/for-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (57 commits)
dt-bindings: i2c: riic: document r7s9210 support
i2c: imx-lpi2c: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
i2c-piix4: Add Hygon Dhyana SMBus support
i2c: core: apply 'is_suspended' check for SMBus, too
i2c: core: ratelimit 'transfer when suspended' errors
i2c: iproc: Change driver to use 'BIT' macro
i2c: riic: Add Runtime PM support
i2c: mux: demux-pinctrl: use struct_size() in devm_kzalloc()
i2c: mux: pca954x: allow management of device idle state via sysfs
i2c: mux: pca9541: remove support for unused platform data
i2c: mux: pca954x: remove support for unused platform data
dt-bindings: i2c: i2c-mtk: add support for MT8516
i2c: axxia: use auto cmd for last message
i2c: gpio: flag atomic capability if possible
i2c: algo: bit: add flag to whitelist atomic transfers
i2c: stu300: use xfer_atomic callback to bail out early
i2c: ocores: enable atomic xfers
i2c: ocores: refactor setup for polling
i2c: tegra-bpmp: convert to use new atomic callbacks
i2c: omap: Add the master_xfer_atomic hook
...
Diffstat (limited to 'drivers/i2c/i2c-core-smbus.c')
-rw-r--r-- | drivers/i2c/i2c-core-smbus.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 132119112596..788d42f2aad9 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -20,6 +20,8 @@ #include <linux/i2c-smbus.h> #include <linux/slab.h> +#include "i2c-core.h" + #define CREATE_TRACE_POINTS #include <trace/events/smbus.h> @@ -530,7 +532,10 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, { s32 res; - i2c_lock_bus(adapter, I2C_LOCK_SEGMENT); + res = __i2c_lock_bus_helper(adapter); + if (res) + return res; + res = __i2c_smbus_xfer(adapter, addr, flags, read_write, command, protocol, data); i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); @@ -543,10 +548,17 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { + int (*xfer_func)(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); unsigned long orig_jiffies; int try; s32 res; + res = __i2c_check_suspended(adapter); + if (res) + return res; + /* If enabled, the following two tracepoints are conditional on * read_write and protocol. */ @@ -557,13 +569,20 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; - if (adapter->algo->smbus_xfer) { + xfer_func = adapter->algo->smbus_xfer; + if (i2c_in_atomic_xfer_mode()) { + if (adapter->algo->smbus_xfer_atomic) + xfer_func = adapter->algo->smbus_xfer_atomic; + else if (adapter->algo->master_xfer_atomic) + xfer_func = NULL; /* fallback to I2C emulation */ + } + + if (xfer_func) { /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; for (res = 0, try = 0; try <= adapter->retries; try++) { - res = adapter->algo->smbus_xfer(adapter, addr, flags, - read_write, command, - protocol, data); + res = xfer_func(adapter, addr, flags, read_write, + command, protocol, data); if (res != -EAGAIN) break; if (time_after(jiffies, |