summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAniket Randive <aniket.randive@oss.qualcomm.com>2026-09-11 12:29:51 +0530
committerAndi Shyti <andi.shyti@kernel.org>2026-09-24 23:37:10 +0200
commit3c014d22dfd1764ce6be9a8aeccee483752e3100 (patch)
treedbcc2f1f8e5490cadff379ed1c2e7b0e5b75b1b6 /include/linux
parentcb97bf3d4f91453b881acaf8e9f0cc47bb40b604 (diff)
downloadlinux-next-3c014d22dfd1764ce6be9a8aeccee483752e3100.tar.gz
linux-next-3c014d22dfd1764ce6be9a8aeccee483752e3100.zip
i2c: core: Add i2c_update_timeout() helper for dynamic transfer timeouts
The transfer timeout for an I2C controller should reflect the actual message length and bus frequency rather than a static 1-second value. A static timeout causes unnecessary delays on error paths for short messages, and may be insufficient for very long transfers. Add i2c_update_timeout() to i2c-core which computes a transfer-specific timeout and stores it directly in the standard adap->timeout field. The formula accounts for 9 bits per byte (8 data + 1 ACK) at the configured bus frequency. The caller supplies a safety multiplier and a minimum floor so that each driver retains full control over its timing policy without those values becoming public API. Storing the result in adap->timeout makes it visible to all consumers of that field, including the arbitration-loss retry loop in __i2c_transfer(). The function is gated by CONFIG_I2C_DYNAMIC_TIMEOUT. When the config is disabled, i2c_update_timeout() compiles to a no-op inline stub so drivers that call it build cleanly and the existing static 1-second default is preserved unchanged. A timeout explicitly configured by userspace via the I2C_TIMEOUT ioctl is stored in a new adap->user_timeout field and always takes precedence over the kernel-computed value. When userspace has not configured a timeout, the computed value is used. The ioctl keeps writing adap->timeout as well, so adapters that never call i2c_update_timeout() continue to honour it exactly as before. As i2c_update_timeout() is an exported helper, guard against a zero bus frequency from a misbehaving caller with WARN_ON_ONCE() and return early, leaving the existing timeout untouched as a safe fallback rather than dividing by zero. Signed-off-by: Aniket Randive <aniket.randive@oss.qualcomm.com> Reviewed-by: Mukesh Kumar Savaliya <mukesh.savaliya@oss.qualcomm.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Link: https://patch.msgid.link/20260911-master-v9-1-77ac458344e2@oss.qualcomm.com
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/i2c.h13
1 files changed, 13 insertions, 0 deletions
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 14ab4d3055af..e4302a1bd8ea 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -742,6 +742,9 @@ struct i2c_adapter {
struct rt_mutex mux_lock;
int timeout; /* in jiffies */
+#ifdef CONFIG_I2C_DYNAMIC_TIMEOUT
+ int user_timeout; /* I2C_TIMEOUT ioctl value in jiffies */
+#endif
int retries;
struct device dev; /* the adapter device */
unsigned long locked_flags; /* owned by the I2C core */
@@ -913,6 +916,16 @@ unsigned int i2c_adapter_depth(struct i2c_adapter *adapter);
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults);
+#ifdef CONFIG_I2C_DYNAMIC_TIMEOUT
+void i2c_update_timeout(struct i2c_adapter *adap, u32 bus_freq_hz,
+ size_t len, unsigned int safety_coeff,
+ unsigned int min_usec);
+#else
+static inline void i2c_update_timeout(struct i2c_adapter *adap, u32 bus_freq_hz,
+ size_t len, unsigned int safety_coeff,
+ unsigned int min_usec) {}
+#endif
+
/* Return the functionality mask */
static inline u32 i2c_get_functionality(struct i2c_adapter *adap)
{