summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorJae Hyun Yoo <jae.hyun.yoo@intel.com>2019-02-16 03:05:09 +0300
committerJae Hyun Yoo <jae.hyun.yoo@linux.intel.com>2021-11-05 10:22:07 +0300
commit5652a04f2654d8b0c6883a254d01fbf22260e701 (patch)
tree2755fbf9e90e806abd421f9ee4b64f3795676471 /include/linux
parentf5b63d083feb8183c81a9db6ef5152401797a60a (diff)
downloadlinux-5652a04f2654d8b0c6883a254d01fbf22260e701.tar.xz
i2c: Add mux hold/unhold msg types
This commit adds mux hold/unhold message types to support extended mux control for IPMB and MCTP devices. A hold or an unhold message can be added at the end of I2C message stream wrapped by repeated-start, also can be used as a single message independantly. This mux hold/unhold message will be delivered throughout all mux levels in the path. Means that if it goes to multi-level mux path, all muxes will be held/unheld by this message. 1. Hold message struct i2c_msg msg; uint16_t timeout = 5000; // timeout in ms. 5 secs in this example. msg.addr = 0x0; // any value can be used. addr will be ignored in this packet. msg.flags = I2C_M_HOLD; // set this flag to indicate it's a hold message. msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer. msg.buf = (uint8_t *)&timeout; // set timeout value. 2. Unhold message struct i2c_msg msg; uint16_t timeout = 0; // set 0 for an unhold message. msg.addr = 0x0; // any value can be used. addr will be ignored in this packet. msg.flags = I2C_M_HOLD; // set this flag to indicate it's an unhold message. msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer. msg.buf = (uint8_t *)&timeout; // set timeout value. This unhold message can be delivered to a mux adapter even when a bus is locked so that any holding state can be unheld immediately by invoking this unhold message. This patch would not be welcomed from upstream so it should be kept in downstream only. Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/i2c-mux.h4
-rw-r--r--include/linux/i2c.h26
2 files changed, 30 insertions, 0 deletions
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index 98ef73b7c8fd..43c40680d8c5 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -14,6 +14,7 @@
#ifdef __KERNEL__
#include <linux/bitops.h>
+#include <linux/workqueue.h>
struct i2c_mux_core {
struct i2c_adapter *parent;
@@ -27,6 +28,9 @@ struct i2c_mux_core {
int (*select)(struct i2c_mux_core *, u32 chan_id);
int (*deselect)(struct i2c_mux_core *, u32 chan_id);
+ struct mutex hold_lock; /* mutex for channel holding */
+ struct delayed_work unhold_work;
+
int num_adapters;
int max_adapters;
struct i2c_adapter *adapter[];
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 2ce3efbe9198..dc681a7196f7 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -20,6 +20,7 @@
#include <linux/irqdomain.h> /* for Host Notify IRQ */
#include <linux/of.h> /* for struct device_node */
#include <linux/swab.h> /* for swab16 */
+#include <linux/workqueue.h>
#include <uapi/linux/i2c.h>
extern struct bus_type i2c_bus_type;
@@ -738,6 +739,13 @@ struct i2c_adapter {
struct irq_domain *host_notify_domain;
struct regulator *bus_regulator;
+
+ /*
+ * These will be used by root adpaters only. For muxes, each mux core
+ * has these individually.
+ */
+ struct mutex hold_lock; /* mutex for bus holding */
+ struct delayed_work unhold_work;
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
@@ -1040,4 +1048,22 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha
}
#endif /* CONFIG_ACPI */
+enum i2c_hold_msg_type {
+ I2C_HOLD_MSG_NONE,
+ I2C_HOLD_MSG_SET,
+ I2C_HOLD_MSG_RESET
+};
+
+static inline enum i2c_hold_msg_type i2c_check_hold_msg(u16 flags, u16 len, u16 *buf)
+{
+ if (flags & I2C_M_HOLD && len == sizeof(u16)) {
+ if (*buf)
+ return I2C_HOLD_MSG_SET;
+
+ return I2C_HOLD_MSG_RESET;
+ }
+
+ return I2C_HOLD_MSG_NONE;
+}
+
#endif /* _LINUX_I2C_H */