Browse Source

i2c: core: use I2C locking behaviour also for SMBUS

commit 83c42212d2544625b85f44a07d0ad96323e69250 upstream

If I2C transfers are executed in atomic contexts, trylock is used
instead of lock. This behaviour was missing for SMBUS, although a lot of
transfers are of SMBUS type, either emulated or direct. So, factor out
the locking routine into a helper and use it for I2C and SMBUS.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Wolfram Sang 6 years ago
parent
commit
316cec46ab
3 changed files with 21 additions and 10 deletions
  1. 3 9
      drivers/i2c/i2c-core-base.c
  2. 6 1
      drivers/i2c/i2c-core-smbus.c
  3. 12 0
      drivers/i2c/i2c-core.h

+ 3 - 9
drivers/i2c/i2c-core-base.c

@@ -1953,15 +1953,9 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
 		}
 #endif
-
-		if (i2c_in_atomic_xfer_mode()) {
-			ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
-			if (!ret)
-				/* I2C activity is ongoing. */
-				return -EAGAIN;
-		} else {
-			i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
-		}
+		ret = __i2c_lock_bus_helper(adap);
+		if (ret)
+			return ret;
 
 		ret = __i2c_transfer(adap, msgs, num);
 		i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);

+ 6 - 1
drivers/i2c/i2c-core-smbus.c

@@ -23,6 +23,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/smbus.h>
 
+#include "i2c-core.h"
+
 
 /* The SMBus parts */
 
@@ -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);

+ 12 - 0
drivers/i2c/i2c-core.h

@@ -39,6 +39,18 @@ static inline bool i2c_in_atomic_xfer_mode(void)
 	return system_state > SYSTEM_RUNNING && irqs_disabled();
 }
 
+static inline int __i2c_lock_bus_helper(struct i2c_adapter *adap)
+{
+	int ret = 0;
+
+	if (i2c_in_atomic_xfer_mode())
+		ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT) ? 0 : -EAGAIN;
+	else
+		i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
+
+	return ret;
+}
+
 #ifdef CONFIG_ACPI
 const struct acpi_device_id *
 i2c_acpi_match_device(const struct acpi_device_id *matches,