[PATCH] i2c: qcom-geni: Restore the source-clock selection policy
From: Abel Vesa
Date: Mon Sep 28 2026 - 10:19:22 EST
Currently, the source clock lookup prefers 32 MHz whenever that rate is
available, regardless of the rate configured by the platform. Before the
switch to looking up the clock index, the driver used the 32 MHz timing
table only if the current source clock rate was 32 MHz, and the 19.2 MHz
table otherwise.
On X1E80100 CRD, this results in switching the source clock from 19.2 MHz
to 32 MHz, which causes intermittent failures when probing the I2C HID
keyboard. These range from corrupted HID descriptors to failed resets
and transfer timeouts, which also affect the touchpad on the same bus.
Restore the original selection policy: use 32 MHz if already selected,
otherwise request 19.2 MHz. Look up the index for the selected rate and
keep the check that rejects higher-frequency multiples. This retains
the dynamic clock index lookup without preferring 32 MHz on platforms
that previously used 19.2 MHz. Report the requested rate if the lookup
fails.
Fixes: cb97bf3d4f91 ("i2c: qcom-geni: Fix hardcoded clock index in SE_GENI_CLK_SEL")
Assisted-by: LLM
Signed-off-by: Abel Vesa <abel.vesa@xxxxxxxxxxxxxxxx>
---
drivers/i2c/busses/i2c-qcom-geni.c | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index f842e7ec56bd..9273d84d2f34 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -206,28 +206,31 @@ static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = {
static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
{
const struct geni_i2c_clk_fld *itr;
- unsigned long res_freq;
+ unsigned long req_freq, res_freq;
+ int ret;
/*
- * Frequency counter tables are calibrated for a specific source
- * clock frequency and are not valid for any multiple of it
- * (e.g. 64 MHz, 128 MHz).
- * Use exact=true and verify res_freq matches req_freq literally
- * to reject harmonics: a 64 MHz clock that divides evenly to
- * 32 MHz would pass exact matching but produce double the intended
- * I2C frequency with these counter values.
+ * Use 32 MHz only if already selected, otherwise use 19.2 MHz.
+ * Preferring 32 MHz merely because DFS supports it breaks I2C
+ * transfers on X1E80100 CRD.
*/
- if (!geni_se_clk_freq_match(&gi2c->se, GENI_SE_CLK_32MHZ,
- &gi2c->clk_idx, &res_freq, true) &&
- res_freq == GENI_SE_CLK_32MHZ) {
+ if (clk_get_rate(gi2c->se.clk) == GENI_SE_CLK_32MHZ) {
+ req_freq = GENI_SE_CLK_32MHZ;
itr = geni_i2c_clk_map_32mhz;
- } else if (!geni_se_clk_freq_match(&gi2c->se, GENI_SE_CLK_19P2MHZ,
- &gi2c->clk_idx, &res_freq, true) &&
- res_freq == GENI_SE_CLK_19P2MHZ) {
+ } else {
+ req_freq = GENI_SE_CLK_19P2MHZ;
itr = geni_i2c_clk_map_19p2mhz;
- } else {
- dev_err(gi2c->se.dev,
- "Unsupported SE source clock: must be exactly 32 MHz or 19.2 MHz\n");
+ }
+
+ ret = geni_se_clk_freq_match(&gi2c->se, req_freq, &gi2c->clk_idx,
+ &res_freq, true);
+ if (ret)
+ return dev_err_probe(gi2c->se.dev, ret,
+ "Failed to find SE source clock %lu Hz\n",
+ req_freq);
+ if (res_freq != req_freq) {
+ dev_err(gi2c->se.dev, "Unsupported SE source clock %lu Hz\n",
+ res_freq);
return -EINVAL;
}
---
base-commit: f5f84daefcd92d7a630066635ecea1433ed5eac7
change-id: 20260928-b4-i2c-qcom-geni-preserve-source-clock-d983fbb7888a
Best regards,
--
Abel Vesa <abel.vesa@xxxxxxxxxxxxxxxx>