summaryrefslogtreecommitdiff
path: root/include/linux/i2c.h
diff options
context:
space:
mode:
authorPeter Rosin <peda@axentia.se>2016-05-04 23:15:27 +0300
committerWolfram Sang <wsa@the-dreams.de>2016-05-04 23:28:31 +0300
commit8320f495cf441d593f7cd4f30e6b63455be71a2c (patch)
tree6c82e3477b5de9200ef237d7a3ac807cf9adb52a /include/linux/i2c.h
parent8a350183010a5557287a10c2a13b1a4cbaa7b130 (diff)
downloadlinux-8320f495cf441d593f7cd4f30e6b63455be71a2c.tar.xz
i2c: allow adapter drivers to override the adapter locking
Add i2c_lock_bus() and i2c_unlock_bus(), which call the new lock_bus and unlock_bus ops in the adapter. These funcs/ops take an additional flags argument that indicates for what purpose the adapter is locked. There are two flags, I2C_LOCK_ROOT_ADAPTER and I2C_LOCK_SEGMENT, but they are both implemented the same. For now. Locking the root adapter means that the whole bus is locked, locking the segment means that only the current bus segment is locked (i.e. i2c traffic on the parent side of a mux is still allowed even if the child side of the mux is locked). Also support a trylock_bus op (but no function to call it, as it is not expected to be needed outside of the i2c core). Implement i2c_lock_adapter/i2c_unlock_adapter in terms of the new locking scheme (i.e. lock with the I2C_LOCK_ROOT_ADAPTER flag). Locking the root adapter and locking the segment is the same thing for all root adapters (e.g. in the normal case of a simple topology with no i2c muxes). The two locking variants are also the same for traditional muxes (aka parent-locked muxes). These muxes traverse the tree, locking each level as they go until they reach the root. This patch is preparatory for a later patch in the series introducing mux-locked muxes, which behave differently depending on the requested locking. Since all current users are using i2c_lock_adapter, which is a wrapper for I2C_LOCK_ROOT_ADAPTER, we only need to annotate the calls that will not need to lock the root adapter for mux-locked muxes. I.e. the instances that needs to use I2C_LOCK_SEGMENT instead of i2c_lock_adapter/I2C_LOCK_ROOT_ADAPTER. Those instances are in the i2c_transfer and i2c_smbus_xfer functions, so that mux-locked muxes can single out normal i2c accesses to its slave side and adjust the locking for those accesses. Signed-off-by: Peter Rosin <peda@axentia.se> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'include/linux/i2c.h')
-rw-r--r--include/linux/i2c.h44
1 files changed, 42 insertions, 2 deletions
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index c30833b7b073..50934d6e1050 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -538,6 +538,10 @@ struct i2c_adapter {
struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
+
+ void (*lock_bus)(struct i2c_adapter *, unsigned int flags);
+ int (*trylock_bus)(struct i2c_adapter *, unsigned int flags);
+ void (*unlock_bus)(struct i2c_adapter *, unsigned int flags);
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
@@ -567,8 +571,44 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
/* Adapter locking functions, exported for shared pin cases */
-void i2c_lock_adapter(struct i2c_adapter *);
-void i2c_unlock_adapter(struct i2c_adapter *);
+#define I2C_LOCK_ROOT_ADAPTER BIT(0)
+#define I2C_LOCK_SEGMENT BIT(1)
+
+/**
+ * i2c_lock_bus - Get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
+ * locks only this branch in the adapter tree
+ */
+static inline void
+i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+ adapter->lock_bus(adapter, flags);
+}
+
+/**
+ * i2c_unlock_bus - Release exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
+ * unlocks only this branch in the adapter tree
+ */
+static inline void
+i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+ adapter->unlock_bus(adapter, flags);
+}
+
+static inline void
+i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+ i2c_lock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
+}
+
+static inline void
+i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+ i2c_unlock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
+}
/*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */