diff options
| author | Aniket Randive <aniket.randive@oss.qualcomm.com> | 2026-09-11 12:29:51 +0530 |
|---|---|---|
| committer | Andi Shyti <andi.shyti@kernel.org> | 2026-09-24 23:37:10 +0200 |
| commit | 3c014d22dfd1764ce6be9a8aeccee483752e3100 (patch) | |
| tree | dbcc2f1f8e5490cadff379ed1c2e7b0e5b75b1b6 /include/linux | |
| parent | cb97bf3d4f91453b881acaf8e9f0cc47bb40b604 (diff) | |
| download | linux-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.h | 13 |
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) { |
