diff mbox series

i2c: qcom-geni: Restore the source-clock selection policy

Message ID 20260928-b4-i2c-qcom-geni-preserve-source-clock-v1-1-9aded7552a76@oss.qualcomm.com
State New
Headers show
Series i2c: qcom-geni: Restore the source-clock selection policy | expand

Commit Message

Abel Vesa Sept. 28, 2026, 1:58 p.m. UTC
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@oss.qualcomm.com>
---
 drivers/i2c/busses/i2c-qcom-geni.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)


---
base-commit: f5f84daefcd92d7a630066635ecea1433ed5eac7
change-id: 20260928-b4-i2c-qcom-geni-preserve-source-clock-d983fbb7888a

Best regards,
--  
Abel Vesa <abel.vesa@oss.qualcomm.com>

Comments

Hasty Heat Oct. 6, 2026, 2:55 p.m. UTC | #1
On Mon, Sep 28, 2026, Abel Vesa wrote:
> 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.

Same issue here on a Lenovo Yoga Slim 7x (X1E80100) running v7.2.9, which
carries cb97bf3d4f91 ("i2c: qcom-geni: Fix hardcoded clock index in
SE_GENI_CLK_SEL"). The ITE 048D:8987 keyboard on the touchpad's bus
(b80000) came up as 0018:FFFF:FFFF with a report descriptor of
0x00 0xff 0xff..., after "did not ack reset within 1000 ms". After a warm
reboot the same bus also hit "Bus arbitration lost, clock line
undriveable", and both the keyboard and touchpad failed.

With this patch applied to v7.2.9, the SE clock stays at 19.2 MHz. The
keyboard (hid-lenovo) and touchpad (hid-multitouch) probe cleanly, with
no arbitration or reset errors, on a warm reboot, a cold boot, and a
warm reboot from another kernel.

Tested-by: Hasty Heat <hastyheat@gmail.com>

It would be good to get this into stable as well, since cb97bf3d4f91 is
already in 7.2.y.
Mitchell Augustin Oct. 6, 2026, 9:48 p.m. UTC | #2
From: Mitchell Augustin <mitchell.augustin@canonical.com>

Same issue on my machine. This patch fixes it for me as well. Thanks!

Tested-by: Mitchell Augustin <mitchell.augustin@canonical.com>
Reviewed-by: Mitchell Augustin <mitchell.augustin@canonical.com>
diff mbox series

Patch

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;
 	}