Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH 10/10] arm64: dts: qcom: sdm845-google: Add STM FTS touchscreen support
From: David Heidelberg @ 2026-03-15 15:52 UTC (permalink / raw)
  To: Konrad Dybcio, Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel
In-Reply-To: <b747b545-12c7-4e33-95ae-ffa114fa13ec@oss.qualcomm.com>



On 02/03/2026 12:06, Konrad Dybcio wrote:
> On 3/1/26 6:51 PM, David Heidelberg via B4 Relay wrote:
>> From: Petr Hodina <petr.hodina@protonmail.com>
>>
>> Basic touchscreen connected to second i2c bus.
>>
>> Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
>> Co-developed-by: David Heidelberg <david@ixit.cz>
>> Signed-off-by: David Heidelberg <david@ixit.cz>
>> ---
>>   arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts | 21 ++++++++++++++++++++-
>>   1 file changed, 20 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts b/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts
>> index fa89be500fb85..2501104b06e1b 100644
>> --- a/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts
>> +++ b/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts
>> @@ -26,7 +26,26 @@ &i2c2 {
>>   
>>   	status = "okay";
>>   
>> -	/* ST,FTS @ 49 */
>> +	touchscreen@49 {
>> +		compatible = "st,stmfts5";
>> +		reg = <0x49>;
>> +
>> +		pinctrl-0 = <&touchscreen_pins &touchscreen_reset>;
>> +		pinctrl-names = "default";
>> +
>> +		interrupt-parent = <&tlmm>;
>> +		interrupts = <125 IRQ_TYPE_LEVEL_LOW>;
>> +
>> +		irq-gpios = <&tlmm 125 GPIO_ACTIVE_HIGH>;
> 
> This is an anti-pattern - you can translate the GPIO handle to an
> IRQ handle, but unless the hardware is spectacularly odd, an interrupt
> reference is usually what you're after

Thanks, dropped in follow-up version.

> 
>> +		switch-gpios = <&tlmm 136 GPIO_ACTIVE_HIGH>;
>> +		reset-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
>> +
>> +		avdd-supply = <&vreg_l14a_1p8>;
>> +		vdd-supply = <&vreg_l19a_3p3>;
>> +
>> +		touchscreen-size-x = <1079>;
>> +		touchscreen-size-y = <2159>;
> 
> Are you sure about these off-by-ones?

These we're extracted from st,maxcoords and yet, it should be 1080, 2160. Fixed 
in follow-up version.

Thanks
David

> 
> FWIW
> 
> input/touchscreen.c:
> 
> touchscreen_get_prop_u32(dev, "touchscreen-size-x",
>                           input_abs_get_max(input,
>                                             axis_x) + 1,
> 
> 				            notice ^
> 
> Konrad

-- 
David Heidelberg


^ permalink raw reply

* Re: [PATCH 08/10] dt-bindings: input: touchscreen: st,stmfts: Introduce STM FTS5
From: David Heidelberg @ 2026-03-15 17:09 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio, Petr Hodina, linux-input,
	linux-stm32, linux-arm-kernel, linux-kernel, Krzysztof Kozlowski,
	devicetree, linux-arm-msm, phone-devel
In-Reply-To: <qibmsgfttxo6kiaqyjljj6otamqp7okfr4abwpmuo7daanl6qu@ka33zvoz7lte>

On 01/03/2026 23:40, Dmitry Baryshkov wrote:

[...]

>> +    then:
>> +      properties:
>> +        switch-gpio:
>> +          description: Switch between SLPI and AP mode.
> 
> This doesn't sounds like the GPIO on the touchscreen, more like the
> external schematic component. If it need sto be turned to one position,
> it might be better to use GPIO hog for that.

Right now yes, but the GPIO serves to switching between SLPI and AP mode at 
runtime, see [1]

The driver lack supports for SLPI, but at moment when SLPI support lands, we 
should be able do something like:

-> device starts, touchscreen works
-> screen goes to sleep, but instead of powering off touchscreen, it switches to 
SLPI mode
-> user taps at touchscreen, device wakes up

Thus I think we need to support this GPIO in the driver.

David

> 
>> +
>> +      required:
>> +        - switch-gpio
>> +
>>   examples:
>>     - |
>>       #include <dt-bindings/interrupt-controller/irq.h>
>>
>> -- 
>> 2.51.0
>>
>>
> 

-- 
David Heidelberg


^ permalink raw reply

* [PATCH WIP v2 00/11] Input: support for STM FTS5
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg

Used on various phones. Minimal basic support.

Includes device-tree enabling touchscreen on Pixel 3.

Sending as WIP, as not all comments we're addressed, but please to apply
any patch which does look ready for inclusion.

What is missing:
 - firmware loading
 - switching between AP and SLPI mode (to wake up phone by touch)
 - anything above basic touch

Signed-off-by: David Heidelberg <david@ixit.cz>
---
TODO for v3:
- wrap everything below enabling the supplies into stmfts_configure()
  to avoid bunch of gotos to power off on error? (Dmitry T.)
- finish chip specific ops and potentinally remove is_fts5. (Dmitry T.)
Changes in v2:
- Fix typo in the binding s/switch-gpio/switch-gpios/.
- Deduplacate allOf. (Rob yamllint)
- Add missing S-off-by. (Dmitry B.)
- Dropped irq-gpios as it's not needed. (Konrad)
- Correct x and y touchscreen area size. (Konrad)
- Correct reset introduction commit description. (Krzysztof)
- Partially implemented chip specific ops. (Dmitry T.)
- Separeted license naming cleanup into separate commit (Dmitry T.)
- Link to v1: https://lore.kernel.org/r/20260301-stmfts5-v1-0-22c458b9ac68@ixit.cz

---
David Heidelberg (7):
      Input: stmfts - Fix the MODULE_LICENSE() string
      Input: stmfts - Use dev struct directly
      Input: stmfts - Switch to devm_regulator_bulk_get_const
      Input: stmfts - abstract reading information from the firmware
      Input: stmfts - disable regulators when power on fails
      dt-bindings: input: touchscreen: st,stmfts: Introduce reset GPIO
      dt-bindings: input: touchscreen: st,stmfts: Introduce STM FTS5

Petr Hodina (4):
      Input: stmfts - use client to make future code cleaner
      Input: stmfts - add optional reset GPIO support
      Input: stmfts - support FTS5
      arm64: dts: qcom: sdm845-google: Add STM FTS touchscreen support

 .../bindings/input/touchscreen/st,stmfts.yaml      |  19 +-
 .../arm64/boot/dts/qcom/sdm845-google-blueline.dts |  20 +-
 drivers/input/touchscreen/stmfts.c                 | 593 +++++++++++++++++++--
 3 files changed, 573 insertions(+), 59 deletions(-)
---
base-commit: 9cdfeb2399709fcc7e5ec0e6a29e283d0d9a9902
change-id: 20260214-stmfts5-b47311fbd732

Best regards,
-- 
David Heidelberg <david@ixit.cz>



^ permalink raw reply

* [PATCH WIP v2 01/11] Input: stmfts - Fix the MODULE_LICENSE() string
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

Replace the bogus "GPL v2" with "GPL" as MODULE_LICNSE() string. The
value does not declare the module's exact license, but only lets the
module loader test whether the module is Free Software or not.

See commit bf7fbeeae6db ("module: Cure the MODULE_LICENSE "GPL" vs.
"GPL v2" bogosity") in the details of the issue. The fix is to use
"GPL" for all modules under any variant of the GPL.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 4b166b0a9a5a6..d93ce68feca51 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -808,4 +808,4 @@ module_i2c_driver(stmfts_driver);
 
 MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
 MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 02/11] Input: stmfts - Use dev struct directly
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

Makes the code better readable and noticably shorter.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index d93ce68feca51..1d63f63e43d48 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -620,6 +620,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata)
 
 static int stmfts_probe(struct i2c_client *client)
 {
+	struct device *dev = &client->dev;
 	int err;
 	struct stmfts_data *sdata;
 
@@ -628,7 +629,7 @@ static int stmfts_probe(struct i2c_client *client)
 						I2C_FUNC_SMBUS_I2C_BLOCK))
 		return -ENODEV;
 
-	sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
+	sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL);
 	if (!sdata)
 		return -ENOMEM;
 
@@ -640,13 +641,13 @@ static int stmfts_probe(struct i2c_client *client)
 
 	sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
 	sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
-	err = devm_regulator_bulk_get(&client->dev,
+	err = devm_regulator_bulk_get(dev,
 				      ARRAY_SIZE(sdata->regulators),
 				      sdata->regulators);
 	if (err)
 		return err;
 
-	sdata->input = devm_input_allocate_device(&client->dev);
+	sdata->input = devm_input_allocate_device(dev);
 	if (!sdata->input)
 		return -ENOMEM;
 
@@ -665,7 +666,7 @@ static int stmfts_probe(struct i2c_client *client)
 	input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
 	input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
 
-	sdata->use_key = device_property_read_bool(&client->dev,
+	sdata->use_key = device_property_read_bool(dev,
 						   "touch-key-connected");
 	if (sdata->use_key) {
 		input_set_capability(sdata->input, EV_KEY, KEY_MENU);
@@ -686,20 +687,20 @@ static int stmfts_probe(struct i2c_client *client)
 	 * interrupts. To be on the safe side it's better to not enable
 	 * the interrupts during their request.
 	 */
-	err = devm_request_threaded_irq(&client->dev, client->irq,
+	err = devm_request_threaded_irq(dev, client->irq,
 					NULL, stmfts_irq_handler,
 					IRQF_ONESHOT | IRQF_NO_AUTOEN,
 					"stmfts_irq", sdata);
 	if (err)
 		return err;
 
-	dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
+	dev_dbg(dev, "initializing ST-Microelectronics FTS...\n");
 
 	err = stmfts_power_on(sdata);
 	if (err)
 		return err;
 
-	err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
+	err = devm_add_action_or_reset(dev, stmfts_power_off, sdata);
 	if (err)
 		return err;
 
@@ -716,13 +717,13 @@ static int stmfts_probe(struct i2c_client *client)
 			 * without LEDs. The ledvdd regulator pointer will be
 			 * used as a flag.
 			 */
-			dev_warn(&client->dev, "unable to use touchkey leds\n");
+			dev_warn(dev, "unable to use touchkey leds\n");
 			sdata->ledvdd = NULL;
 		}
 	}
 
-	pm_runtime_enable(&client->dev);
-	device_enable_async_suspend(&client->dev);
+	pm_runtime_enable(dev);
+	device_enable_async_suspend(dev);
 
 	return 0;
 }

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 03/11] Input: stmfts - Switch to devm_regulator_bulk_get_const
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

Switch to devm_regulator_bulk_get_const() to stop setting the supplies
list in probe(), and move the regulator_bulk_data struct in static const.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 1d63f63e43d48..a9f240bac201e 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -69,9 +69,9 @@
 #define STMFTS_MAX_FINGERS	10
 #define STMFTS_DEV_NAME		"stmfts"
 
-enum stmfts_regulators {
-	STMFTS_REGULATOR_VDD,
-	STMFTS_REGULATOR_AVDD,
+static const struct regulator_bulk_data stmfts_supplies[] = {
+	{ .supply = "vdd" },
+	{ .supply = "avdd" },
 };
 
 struct stmfts_data {
@@ -82,7 +82,7 @@ struct stmfts_data {
 
 	struct touchscreen_properties prop;
 
-	struct regulator_bulk_data regulators[2];
+	struct regulator_bulk_data *supplies;
 
 	/*
 	 * Presence of ledvdd will be used also to check
@@ -524,8 +524,8 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 	int err;
 	u8 reg[8];
 
-	err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
-				    sdata->regulators);
+	err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies),
+				    sdata->supplies);
 	if (err)
 		return err;
 
@@ -590,8 +590,8 @@ static void stmfts_power_off(void *data)
 	struct stmfts_data *sdata = data;
 
 	disable_irq(sdata->client->irq);
-	regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
-						sdata->regulators);
+	regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies),
+			       sdata->supplies);
 }
 
 static int stmfts_enable_led(struct stmfts_data *sdata)
@@ -639,11 +639,10 @@ static int stmfts_probe(struct i2c_client *client)
 	mutex_init(&sdata->mutex);
 	init_completion(&sdata->cmd_done);
 
-	sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
-	sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
-	err = devm_regulator_bulk_get(dev,
-				      ARRAY_SIZE(sdata->regulators),
-				      sdata->regulators);
+	err = devm_regulator_bulk_get_const(dev,
+					    ARRAY_SIZE(stmfts_supplies),
+					    stmfts_supplies,
+					    &sdata->supplies);
 	if (err)
 		return err;
 

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 04/11] Input: stmfts - abstract reading information from the firmware
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

Improves readability and makes splitting power on function in following
commit easier.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index a9f240bac201e..c1c9570ddea2d 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -519,22 +519,11 @@ static struct attribute *stmfts_sysfs_attrs[] = {
 };
 ATTRIBUTE_GROUPS(stmfts_sysfs);
 
-static int stmfts_power_on(struct stmfts_data *sdata)
+static int stmfts_read_system_info(struct stmfts_data *sdata)
 {
 	int err;
 	u8 reg[8];
 
-	err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies),
-				    sdata->supplies);
-	if (err)
-		return err;
-
-	/*
-	 * The datasheet does not specify the power on time, but considering
-	 * that the reset time is < 10ms, I sleep 20ms to be sure
-	 */
-	msleep(20);
-
 	err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO,
 					    sizeof(reg), reg);
 	if (err < 0)
@@ -548,6 +537,29 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 	sdata->config_id = reg[4];
 	sdata->config_ver = reg[5];
 
+	return 0;
+}
+
+static int stmfts_power_on(struct stmfts_data *sdata)
+{
+	int err;
+
+	err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies),
+				    sdata->supplies);
+	if (err)
+		return err;
+
+	/*
+	 * The datasheet does not specify the power on time, but considering
+	 * that the reset time is < 10ms, I sleep 20ms to be sure
+	 */
+	msleep(20);
+
+
+	err = stmfts_read_system_info(sdata);
+	if (err)
+		return err;
+
 	enable_irq(sdata->client->irq);
 
 	msleep(50);

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 05/11] Input: stmfts - disable regulators when power on fails
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

We must power off regulators after failing at power on phase.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index c1c9570ddea2d..bf176907177d0 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -558,7 +558,7 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 
 	err = stmfts_read_system_info(sdata);
 	if (err)
-		return err;
+		goto power_off;
 
 	enable_irq(sdata->client->irq);
 
@@ -566,11 +566,11 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 
 	err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
 	if (err)
-		return err;
+		goto power_off;
 
 	err = stmfts_command(sdata, STMFTS_SLEEP_OUT);
 	if (err)
-		return err;
+		goto power_off;
 
 	/* optional tuning */
 	err = stmfts_command(sdata, STMFTS_MS_CX_TUNING);
@@ -586,7 +586,7 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 
 	err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION);
 	if (err)
-		return err;
+		goto power_off;
 
 	/*
 	 * At this point no one is using the touchscreen
@@ -595,6 +595,11 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 	(void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
 
 	return 0;
+
+power_off:
+	regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies),
+			       sdata->supplies);
+	return err;
 }
 
 static void stmfts_power_off(void *data)

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 06/11] Input: stmfts - use client to make future code cleaner
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: Petr Hodina <petr.hodina@protonmail.com>

Make code cleaner, compiler will optimize it away anyway.

Preparation for FTM5 support, where more steps are needed.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index bf176907177d0..4dfaf3a6077d9 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -764,9 +764,10 @@ static int stmfts_runtime_suspend(struct device *dev)
 static int stmfts_runtime_resume(struct device *dev)
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
+	struct i2c_client *client = sdata->client;
 	int ret;
 
-	ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
+	ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT);
 	if (ret)
 		dev_err(dev, "failed to resume device: %d\n", ret);
 

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 07/11] dt-bindings: input: touchscreen: st,stmfts: Introduce reset GPIO
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

FTS has associated reset GPIO, document it.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml
index 12256ae7df90d..64c4f24ea3dd0 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml
@@ -40,6 +40,10 @@ properties:
   vdd-supply:
     description: Power supply
 
+  reset-gpios:
+    description: Reset GPIO (active-low)
+    maxItems: 1
+
 required:
   - compatible
   - reg

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 08/11] Input: stmfts - add optional reset GPIO support
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: Petr Hodina <petr.hodina@protonmail.com>

Add support for an optional "reset-gpios" property. If present, the
driver drives the reset line high at probe time and releases it during
power-on, after the regulators have been enabled.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 4dfaf3a6077d9..2c10256e09c5e 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -77,6 +77,7 @@ static const struct regulator_bulk_data stmfts_supplies[] = {
 struct stmfts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
+	struct gpio_desc *reset_gpio;
 	struct led_classdev led_cdev;
 	struct mutex mutex;
 
@@ -540,6 +541,15 @@ static int stmfts_read_system_info(struct stmfts_data *sdata)
 	return 0;
 }
 
+static void stmfts_reset(struct stmfts_data *sdata)
+{
+	gpiod_set_value_cansleep(sdata->reset_gpio, 1);
+	msleep(20);
+
+	gpiod_set_value_cansleep(sdata->reset_gpio, 0);
+	msleep(50);
+}
+
 static int stmfts_power_on(struct stmfts_data *sdata)
 {
 	int err;
@@ -549,6 +559,9 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 	if (err)
 		return err;
 
+	if (sdata->reset_gpio)
+		stmfts_reset(sdata);
+
 	/*
 	 * The datasheet does not specify the power on time, but considering
 	 * that the reset time is < 10ms, I sleep 20ms to be sure
@@ -607,6 +620,10 @@ static void stmfts_power_off(void *data)
 	struct stmfts_data *sdata = data;
 
 	disable_irq(sdata->client->irq);
+
+	if (sdata->reset_gpio)
+		gpiod_set_value_cansleep(sdata->reset_gpio, 1);
+
 	regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies),
 			       sdata->supplies);
 }
@@ -663,6 +680,12 @@ static int stmfts_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
+	sdata->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						    GPIOD_OUT_HIGH);
+	if (IS_ERR(sdata->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(sdata->reset_gpio),
+				     "Failed to get GPIO 'reset'\n");
+
 	sdata->input = devm_input_allocate_device(dev);
 	if (!sdata->input)
 		return -ENOMEM;

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 09/11] dt-bindings: input: touchscreen: st,stmfts: Introduce STM FTS5
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: David Heidelberg <david@ixit.cz>

Introduce more recent STM FTS5 touchscreen support.

Signed-off-by: David Heidelberg <david@ixit.cz>
---
 .../devicetree/bindings/input/touchscreen/st,stmfts.yaml  | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml
index 64c4f24ea3dd0..66255893a99fb 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml
@@ -16,10 +16,23 @@ description:
 
 allOf:
   - $ref: touchscreen.yaml#
+  - if:
+      properties:
+        compatible:
+          const: st,stmfts5
+    then:
+      properties:
+        switch-gpios:
+          description: Switch between SLPI and AP mode.
+
+      required:
+        - switch-gpios
 
 properties:
   compatible:
-    const: st,stmfts
+    enum:
+      - st,stmfts
+      - st,stmfts5
 
   reg:
     maxItems: 1

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 10/11] Input: stmfts - support FTS5
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: Petr Hodina <petr.hodina@protonmail.com>

Introduce basic FTS5 support.

FTS support SLPI and AP mode, introduce switch GPIO to switch between
those two. Currently we can handle only full power AP mode, so we just
switch to it.

Useful for devices like Pixel 3 (blueline) and many others.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
 drivers/input/touchscreen/stmfts.c | 480 +++++++++++++++++++++++++++++++++++--
 1 file changed, 459 insertions(+), 21 deletions(-)

diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 2c10256e09c5e..1da80b6880c08 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -1,8 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
-// STMicroelectronics FTS Touchscreen device driver
-//
-// Copyright (c) 2017 Samsung Electronics Co., Ltd.
-// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
+/* STMicroelectronics FTS Touchscreen device driver
+ *
+ * Copyright 2017 Samsung Electronics Co., Ltd.
+ * Copyright 2017 Andi Shyti <andi@etezian.org>
+ * Copyright David Heidelberg <david@ixit.cz>
+ * Copyright Petr Hodina <petr.hodina@protonmail.com>
+ */
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -12,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 
@@ -34,6 +38,7 @@
 #define STMFTS_FULL_FORCE_CALIBRATION		0xa2
 #define STMFTS_MS_CX_TUNING			0xa3
 #define STMFTS_SS_CX_TUNING			0xa4
+#define STMFTS5_SET_SCAN_MODE			0xa0
 
 /* events */
 #define STMFTS_EV_NO_EVENT			0x00
@@ -51,12 +56,32 @@
 #define STMFTS_EV_STATUS			0x16
 #define STMFTS_EV_DEBUG				0xdb
 
+/* events FTS5 */
+#define STMFTS5_EV_CONTROLLER_READY		0x03
+/* FTM5 event IDs (full byte, not masked) */
+#define STMFTS5_EV_MULTI_TOUCH_ENTER		0x13
+#define STMFTS5_EV_MULTI_TOUCH_MOTION		0x23
+#define STMFTS5_EV_MULTI_TOUCH_LEAVE		0x33
+#define STMFTS5_EV_STATUS_UPDATE		0x43
+#define STMFTS5_EV_USER_REPORT			0x53
+#define STMFTS5_EV_DEBUG			0xe3
+#define STMFTS5_EV_ERROR			0xf3
+
 /* multi touch related event masks */
 #define STMFTS_MASK_EVENT_ID			0x0f
 #define STMFTS_MASK_TOUCH_ID			0xf0
 #define STMFTS_MASK_LEFT_EVENT			0x0f
 #define STMFTS_MASK_X_MSB			0x0f
 #define STMFTS_MASK_Y_LSB			0xf0
+#define STMFTS5_MASK_TOUCH_TYPE			0x0f
+
+/* touch type classifications */
+#define STMFTS_TOUCH_TYPE_INVALID		0x00
+#define STMFTS_TOUCH_TYPE_FINGER		0x01
+#define STMFTS_TOUCH_TYPE_GLOVE			0x02
+#define STMFTS_TOUCH_TYPE_STYLUS		0x03
+#define STMFTS_TOUCH_TYPE_PALM			0x04
+#define STMFTS_TOUCH_TYPE_HOVER			0x05
 
 /* key related event masks */
 #define STMFTS_MASK_KEY_NO_TOUCH		0x00
@@ -75,9 +100,12 @@ static const struct regulator_bulk_data stmfts_supplies[] = {
 };
 
 struct stmfts_data {
+	const struct stmfts_chip_ops *ops;
+
 	struct i2c_client *client;
 	struct input_dev *input;
 	struct gpio_desc *reset_gpio;
+	struct gpio_desc *switch_gpio;
 	struct led_classdev led_cdev;
 	struct mutex mutex;
 
@@ -101,12 +129,24 @@ struct stmfts_data {
 
 	struct completion cmd_done;
 
+	unsigned long touch_id;
+	unsigned long stylus_id;
+
+	bool is_fts5;
 	bool use_key;
 	bool led_status;
 	bool hover_enabled;
+	bool stylus_enabled;
 	bool running;
 };
 
+struct stmfts_chip_ops {
+	int  (*power_on)(struct stmfts_data *sdata);
+	int  (*input_open)(struct input_dev *dev);
+	void (*input_close)(struct input_dev *dev);
+	void (*parse_events)(struct stmfts_data *sdata);
+};
+
 static int stmfts_brightness_set(struct led_classdev *led_cdev,
 					enum led_brightness value)
 {
@@ -169,6 +209,7 @@ static int stmfts_read_events(struct stmfts_data *sdata)
 	return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
 }
 
+/* FTS4 event handling functions */
 static void stmfts_report_contact_event(struct stmfts_data *sdata,
 					const u8 event[])
 {
@@ -204,6 +245,157 @@ static void stmfts_report_contact_release(struct stmfts_data *sdata,
 	input_sync(sdata->input);
 }
 
+/* FTS5 event handling functions */
+static void stmfts5_report_contact_event(struct stmfts_data *sdata,
+					 const u8 event[])
+{
+	u8 area;
+	u8 maj;
+	u8 min;
+	/* FTM5 event format:
+	 * event[0] = event ID (0x13/0x23)
+	 * event[1] = touch type (low 4 bits) | touch ID (high 4 bits)
+	 * event[2] = X LSB
+	 * event[3] = X MSB (low 4 bits) | Y MSB (high 4 bits)
+	 * event[4] = Y LSB
+	 * event[5] = pressure
+	 * event[6] = major (low 4 bits) | minor (high 4 bits)
+	 * event[7] = minor (high 2 bits)
+	 */
+	u8 touch_id = (event[1] & STMFTS_MASK_TOUCH_ID) >> 4;
+	u8 touch_type = event[1] & STMFTS5_MASK_TOUCH_TYPE;
+	int x, y, distance;
+	unsigned int tool = MT_TOOL_FINGER;
+	bool touch_condition = true;
+
+	/* Parse coordinates with better precision */
+	x = (((int)event[3] & STMFTS_MASK_X_MSB) << 8) | event[2];
+	y = ((int)event[4] << 4) | ((event[3] & STMFTS_MASK_Y_LSB) >> 4);
+
+	/* Parse pressure - ensure non-zero for active touch */
+	area = event[5];
+	if (area <= 0 && touch_type != STMFTS_TOUCH_TYPE_HOVER) {
+		/* Should not happen for contact events. Set minimum pressure
+		 * to prevent touch from being dropped
+		 */
+		dev_warn_once(&sdata->client->dev,
+			      "zero pressure on contact event, slot %d\n", touch_id);
+		area = 1;
+	}
+
+	/* Parse touch area with improved bit extraction */
+	maj = (((event[0] & 0x0C) << 2) | ((event[6] & 0xF0) >> 4));
+	min = (((event[7] & 0xC0) >> 2) | (event[6] & 0x0F));
+
+	/* Distance is 0 for touching, max for hovering */
+	distance = 0;
+
+	/* Classify touch type and set appropriate tool and parameters */
+	switch (touch_type) {
+	case STMFTS_TOUCH_TYPE_STYLUS:
+		if (sdata->stylus_enabled) {
+			tool = MT_TOOL_PEN;
+			__set_bit(touch_id, &sdata->stylus_id);
+			__clear_bit(touch_id, &sdata->touch_id);
+			break;
+		}
+		fallthrough; /* Report as finger if stylus not enabled */
+
+	case STMFTS_TOUCH_TYPE_FINGER:
+	case STMFTS_TOUCH_TYPE_GLOVE:
+		tool = MT_TOOL_FINGER;
+		__set_bit(touch_id, &sdata->touch_id);
+		__clear_bit(touch_id, &sdata->stylus_id);
+		break;
+
+	case STMFTS_TOUCH_TYPE_PALM:
+		/* Palm touch - report but can be filtered by userspace */
+		tool = MT_TOOL_PALM;
+		__set_bit(touch_id, &sdata->touch_id);
+		__clear_bit(touch_id, &sdata->stylus_id);
+		break;
+
+	case STMFTS_TOUCH_TYPE_HOVER:
+		tool = MT_TOOL_FINGER;
+		touch_condition = false;
+		area = 0;
+		distance = 255;
+		__set_bit(touch_id, &sdata->touch_id);
+		__clear_bit(touch_id, &sdata->stylus_id);
+		break;
+
+	case STMFTS_TOUCH_TYPE_INVALID:
+	default:
+		dev_warn(&sdata->client->dev,
+			 "invalid touch type %d for slot %d\n",
+			 touch_type, touch_id);
+		return;
+	}
+
+	/* Boundary check - some devices report max value, adjust */
+	if (x >= sdata->prop.max_x)
+		x = sdata->prop.max_x - 1;
+	if (y >= sdata->prop.max_y)
+		y = sdata->prop.max_y - 1;
+
+	input_mt_slot(sdata->input, touch_id);
+	input_report_key(sdata->input, BTN_TOUCH, touch_condition);
+	input_mt_report_slot_state(sdata->input, tool, true);
+
+	input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
+	input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
+	input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, maj);
+	input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, min);
+	input_report_abs(sdata->input, ABS_MT_PRESSURE, area);
+	input_report_abs(sdata->input, ABS_MT_DISTANCE, distance);
+
+	input_sync(sdata->input);
+}
+
+static void stmfts5_report_contact_release(struct stmfts_data *sdata,
+					   const u8 event[])
+{
+	/* FTM5 format: touch ID is in high 4 bits of event[1] */
+	u8 touch_id = (event[1] & STMFTS_MASK_TOUCH_ID) >> 4;
+	u8 touch_type = event[1] & STMFTS5_MASK_TOUCH_TYPE;
+	unsigned int tool = MT_TOOL_FINGER;
+
+	/* Determine tool type based on touch classification */
+	switch (touch_type) {
+	case STMFTS_TOUCH_TYPE_STYLUS:
+		if (sdata->stylus_enabled) {
+			tool = MT_TOOL_PEN;
+			__clear_bit(touch_id, &sdata->stylus_id);
+		} else {
+			__clear_bit(touch_id, &sdata->touch_id);
+		}
+		break;
+
+	case STMFTS_TOUCH_TYPE_PALM:
+		tool = MT_TOOL_PALM;
+		__clear_bit(touch_id, &sdata->touch_id);
+		break;
+
+	case STMFTS_TOUCH_TYPE_FINGER:
+	case STMFTS_TOUCH_TYPE_GLOVE:
+	case STMFTS_TOUCH_TYPE_HOVER:
+	default:
+		tool = MT_TOOL_FINGER;
+		__clear_bit(touch_id, &sdata->touch_id);
+		break;
+	}
+
+	input_mt_slot(sdata->input, touch_id);
+	input_report_abs(sdata->input, ABS_MT_PRESSURE, 0);
+	input_mt_report_slot_state(sdata->input, tool, false);
+
+	/* Report BTN_TOUCH only if no touches remain */
+	if (!sdata->touch_id && !sdata->stylus_id)
+		input_report_key(sdata->input, BTN_TOUCH, 0);
+
+	input_sync(sdata->input);
+}
+
 static void stmfts_report_hover_event(struct stmfts_data *sdata,
 				      const u8 event[])
 {
@@ -251,7 +443,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
 		u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE];
 
 		switch (event[0]) {
-
 		case STMFTS_EV_CONTROLLER_READY:
 		case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
 		case STMFTS_EV_STATUS:
@@ -264,7 +455,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
 		}
 
 		switch (event[0] & STMFTS_MASK_EVENT_ID) {
-
 		case STMFTS_EV_MULTI_TOUCH_ENTER:
 		case STMFTS_EV_MULTI_TOUCH_MOTION:
 			stmfts_report_contact_event(sdata, event);
@@ -298,6 +488,45 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
 	}
 }
 
+static void stmfts5_parse_events(struct stmfts_data *sdata)
+{
+	for (int i = 0; i < STMFTS_STACK_DEPTH; i++) {
+		u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE];
+
+		switch (event[0]) {
+		case STMFTS5_EV_CONTROLLER_READY:
+			complete(&sdata->cmd_done);
+			fallthrough;
+
+		case STMFTS_EV_NO_EVENT:
+		case STMFTS5_EV_STATUS_UPDATE:
+		case STMFTS5_EV_USER_REPORT:
+		case STMFTS5_EV_DEBUG:
+			return;
+
+		case STMFTS5_EV_MULTI_TOUCH_ENTER:
+		case STMFTS5_EV_MULTI_TOUCH_MOTION:
+			stmfts5_report_contact_event(sdata, event);
+			break;
+
+		case STMFTS5_EV_MULTI_TOUCH_LEAVE:
+			stmfts5_report_contact_release(sdata, event);
+			break;
+
+		case STMFTS5_EV_ERROR:
+			dev_warn(&sdata->client->dev,
+				 "error code: 0x%x%x%x%x%x%x",
+				 event[6], event[5], event[4],
+				 event[3], event[2], event[1]);
+			break;
+
+		default:
+			dev_err(&sdata->client->dev,
+				"unknown FTS5 event %#02x\n", event[0]);
+		}
+	}
+}
+
 static irqreturn_t stmfts_irq_handler(int irq, void *dev)
 {
 	struct stmfts_data *sdata = dev;
@@ -310,7 +539,7 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev)
 		dev_err(&sdata->client->dev,
 			"failed to read events: %d\n", err);
 	else
-		stmfts_parse_events(sdata);
+		sdata->ops->parse_events(sdata);
 
 	mutex_unlock(&sdata->mutex);
 	return IRQ_HANDLED;
@@ -333,6 +562,25 @@ static int stmfts_command(struct stmfts_data *sdata, const u8 cmd)
 	return 0;
 }
 
+static int stmfts5_set_scan_mode(struct stmfts_data *sdata, const u8 val)
+{
+	int err;
+
+	u8 scan_mode_cmd[3] = { STMFTS5_SET_SCAN_MODE, 0x00, val };
+	struct i2c_msg msg = {
+		.addr = sdata->client->addr,
+		.len = sizeof(scan_mode_cmd),
+		.buf = scan_mode_cmd,
+	};
+
+	err = i2c_transfer(sdata->client->adapter, &msg, 1);
+	if (err != 1)
+		return err < 0 ? err : -EIO;
+
+	return 0;
+
+}
+
 static int stmfts_input_open(struct input_dev *dev)
 {
 	struct stmfts_data *sdata = input_get_drvdata(dev);
@@ -372,6 +620,28 @@ static int stmfts_input_open(struct input_dev *dev)
 	return 0;
 }
 
+static int stmfts5_input_open(struct input_dev *dev)
+{
+	struct stmfts_data *sdata = input_get_drvdata(dev);
+	int err;
+
+	err = pm_runtime_resume_and_get(&sdata->client->dev);
+	if (err)
+		return err;
+
+	mutex_lock(&sdata->mutex);
+	sdata->running = true;
+	mutex_unlock(&sdata->mutex);
+
+	err = stmfts5_set_scan_mode(sdata, 0xff);
+	if (err) {
+		pm_runtime_put_sync(&sdata->client->dev);
+		return err;
+	}
+
+	return 0;
+}
+
 static void stmfts_input_close(struct input_dev *dev)
 {
 	struct stmfts_data *sdata = input_get_drvdata(dev);
@@ -406,6 +676,23 @@ static void stmfts_input_close(struct input_dev *dev)
 	pm_runtime_put_sync(&sdata->client->dev);
 }
 
+static void stmfts5_input_close(struct input_dev *dev)
+{
+	struct stmfts_data *sdata = input_get_drvdata(dev);
+	int err;
+
+	err = stmfts5_set_scan_mode(sdata, 0x00);
+	if (err)
+		dev_warn(&sdata->client->dev,
+			 "failed to disable touchscreen: %d\n", err);
+
+	mutex_lock(&sdata->mutex);
+	sdata->running = false;
+	mutex_unlock(&sdata->mutex);
+
+	pm_runtime_put_sync(&sdata->client->dev);
+}
+
 static ssize_t stmfts_sysfs_chip_id(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
@@ -485,7 +772,7 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
 	if (value && sdata->hover_enabled)
 		goto out;
 
-	if (sdata->running)
+	if (sdata->running && !sdata->is_fts5)
 		err = i2c_smbus_write_byte(sdata->client,
 					   value ? STMFTS_SS_HOVER_SENSE_ON :
 						   STMFTS_SS_HOVER_SENSE_OFF);
@@ -615,6 +902,41 @@ static int stmfts_power_on(struct stmfts_data *sdata)
 	return err;
 }
 
+static int stmfts5_power_on(struct stmfts_data *sdata)
+{
+	int err, ret;
+	u8 event[STMFTS_EVENT_SIZE];
+
+	err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies),
+				    sdata->supplies);
+	if (err)
+		return err;
+
+	/* Power stabilization delay */
+	msleep(20);
+
+	if (sdata->reset_gpio)
+		stmfts_reset(sdata);
+
+	/* Verify I2C communication */
+	ret = i2c_smbus_read_i2c_block_data(sdata->client,
+					    STMFTS_READ_ALL_EVENT,
+					    sizeof(event), event);
+	if (ret < 0) {
+		err = ret;
+		goto power_off;
+	}
+
+	enable_irq(sdata->client->irq);
+
+	return 0;
+
+power_off:
+	regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies),
+			       sdata->supplies);
+	return err;
+}
+
 static void stmfts_power_off(void *data)
 {
 	struct stmfts_data *sdata = data;
@@ -624,6 +946,11 @@ static void stmfts_power_off(void *data)
 	if (sdata->reset_gpio)
 		gpiod_set_value_cansleep(sdata->reset_gpio, 1);
 
+	if (sdata->is_fts5) {
+		i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
+		msleep(20);
+	}
+
 	regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies),
 			       sdata->supplies);
 }
@@ -657,6 +984,7 @@ static int stmfts_probe(struct i2c_client *client)
 	struct device *dev = &client->dev;
 	int err;
 	struct stmfts_data *sdata;
+	const struct of_device_id *match;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
 						I2C_FUNC_SMBUS_BYTE_DATA |
@@ -673,6 +1001,13 @@ static int stmfts_probe(struct i2c_client *client)
 	mutex_init(&sdata->mutex);
 	init_completion(&sdata->cmd_done);
 
+	match = of_match_device(dev->driver->of_match_table, dev);
+	sdata->ops = of_device_get_match_data(dev);
+	if (match && of_device_is_compatible(dev->of_node, "st,stmfts5"))
+		sdata->is_fts5 = true;
+	else
+		sdata->is_fts5 = false;
+
 	err = devm_regulator_bulk_get_const(dev,
 					    ARRAY_SIZE(stmfts_supplies),
 					    stmfts_supplies,
@@ -686,34 +1021,79 @@ static int stmfts_probe(struct i2c_client *client)
 		return dev_err_probe(dev, PTR_ERR(sdata->reset_gpio),
 				     "Failed to get GPIO 'reset'\n");
 
+	if (sdata->is_fts5) {
+		sdata->switch_gpio = devm_gpiod_get_optional(&client->dev, "switch",
+							     GPIOD_OUT_HIGH);
+		if (IS_ERR(sdata->switch_gpio))
+			return dev_err_probe(dev, PTR_ERR(sdata->switch_gpio),
+					     "Failed to get GPIO 'switch'\n");
+
+	}
+
 	sdata->input = devm_input_allocate_device(dev);
 	if (!sdata->input)
 		return -ENOMEM;
 
 	sdata->input->name = STMFTS_DEV_NAME;
 	sdata->input->id.bustype = BUS_I2C;
-	sdata->input->open = stmfts_input_open;
-	sdata->input->close = stmfts_input_close;
+	sdata->input->open = sdata->ops->input_open;
+	sdata->input->close = sdata->ops->input_close;
+
+	/* FTS5-specific input properties */
+	if (sdata->is_fts5) {
+		/* Mark as direct input device for calibration support */
+		__set_bit(INPUT_PROP_DIRECT, sdata->input->propbit);
+
+		/* Set up basic touch capabilities */
+		input_set_capability(sdata->input, EV_KEY, BTN_TOUCH);
+	}
 
 	input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_X);
 	input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_Y);
 	touchscreen_parse_properties(sdata->input, true, &sdata->prop);
 
+	/* Set resolution for accurate calibration (FTS5) */
+	if (sdata->is_fts5 && !input_abs_get_res(sdata->input, ABS_MT_POSITION_X)) {
+		input_abs_set_res(sdata->input, ABS_MT_POSITION_X, 10);
+		input_abs_set_res(sdata->input, ABS_MT_POSITION_Y, 10);
+	}
+
+	/* Enhanced MT parameters */
 	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
 	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
-	input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0);
 	input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
-	input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
+
+	if (sdata->is_fts5) {
+		input_set_abs_params(sdata->input, ABS_MT_DISTANCE, 0, 255, 0, 0);
+
+		/* Enable stylus support if requested */
+		sdata->stylus_enabled = device_property_read_bool(dev,
+								  "stylus-enabled");
+	} else {
+		input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0);
+		input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
+	}
 
 	sdata->use_key = device_property_read_bool(dev,
 						   "touch-key-connected");
-	if (sdata->use_key) {
+	if (sdata->use_key && !sdata->is_fts5) {
 		input_set_capability(sdata->input, EV_KEY, KEY_MENU);
 		input_set_capability(sdata->input, EV_KEY, KEY_BACK);
 	}
 
-	err = input_mt_init_slots(sdata->input,
-				  STMFTS_MAX_FINGERS, INPUT_MT_DIRECT);
+	/* Initialize touch tracking bitmaps (FTS5) */
+	if (sdata->is_fts5) {
+		sdata->touch_id = 0;
+		sdata->stylus_id = 0;
+
+		/* Initialize MT slots with support for pen tool type */
+		err = input_mt_init_slots(sdata->input, STMFTS_MAX_FINGERS,
+					  INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	} else {
+		err = input_mt_init_slots(sdata->input, STMFTS_MAX_FINGERS,
+					  INPUT_MT_DIRECT);
+	}
+
 	if (err)
 		return err;
 
@@ -733,9 +1113,11 @@ static int stmfts_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
-	dev_dbg(dev, "initializing ST-Microelectronics FTS...\n");
+	dev_dbg(dev, "initializing ST-Microelectronics FTS%s...\n",
+		sdata->is_fts5 ? "5" : "");
 
-	err = stmfts_power_on(sdata);
+
+	err = sdata->ops->power_on(sdata);
 	if (err)
 		return err;
 
@@ -747,7 +1129,7 @@ static int stmfts_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
-	if (sdata->use_key) {
+	if (sdata->use_key && !sdata->is_fts5) {
 		err = stmfts_enable_led(sdata);
 		if (err) {
 			/*
@@ -791,8 +1173,47 @@ static int stmfts_runtime_resume(struct device *dev)
 	int ret;
 
 	ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT);
-	if (ret)
+	if (ret) {
 		dev_err(dev, "failed to resume device: %d\n", ret);
+		return ret;
+	}
+
+	if (sdata->is_fts5) {
+		msleep(20);
+
+		/* Perform capacitance tuning after wakeup */
+		ret = i2c_smbus_write_byte(client, STMFTS_MS_CX_TUNING);
+		if (ret)
+			dev_warn(dev, "MS_CX_TUNING failed: %d\n", ret);
+		msleep(20);
+
+		ret = i2c_smbus_write_byte(client, STMFTS_SS_CX_TUNING);
+		if (ret)
+			dev_warn(dev, "SS_CX_TUNING failed: %d\n", ret);
+		msleep(20);
+
+		/* Force calibration */
+		ret = i2c_smbus_write_byte(client, STMFTS_FULL_FORCE_CALIBRATION);
+		if (ret)
+			dev_warn(dev, "FORCE_CALIBRATION failed: %d\n", ret);
+		msleep(50);
+
+		/* Enable controller interrupts */
+		u8 int_enable_cmd[4] = {0xB6, 0x00, 0x2C, 0x01};
+		struct i2c_msg msg = {
+			.addr = client->addr,
+			.len = 4,
+			.buf = int_enable_cmd,
+		};
+
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret != 1)
+			return ret < 0 ? ret : -EIO;
+
+		msleep(20);
+
+		return 0;
+	}
 
 	return ret;
 }
@@ -810,7 +1231,7 @@ static int stmfts_resume(struct device *dev)
 {
 	struct stmfts_data *sdata = dev_get_drvdata(dev);
 
-	return stmfts_power_on(sdata);
+	return sdata->ops->power_on(sdata);
 }
 
 static const struct dev_pm_ops stmfts_pm_ops = {
@@ -819,8 +1240,23 @@ static const struct dev_pm_ops stmfts_pm_ops = {
 };
 
 #ifdef CONFIG_OF
+static const struct stmfts_chip_ops stmfts4_ops = {
+	.power_on	= stmfts_power_on,
+	.input_open	= stmfts_input_open,
+	.input_close	= stmfts_input_close,
+	.parse_events	= stmfts_parse_events,
+};
+
+static const struct stmfts_chip_ops stmfts5_ops = {
+	.power_on	= stmfts5_power_on,
+	.input_open	= stmfts5_input_open,
+	.input_close	= stmfts5_input_close,
+	.parse_events	= stmfts5_parse_events,
+};
+
 static const struct of_device_id stmfts_of_match[] = {
-	{ .compatible = "st,stmfts", },
+	{ .compatible = "st,stmfts",	.data = &stmfts4_ops },
+	{ .compatible = "st,stmfts5",	.data = &stmfts5_ops },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, stmfts_of_match);
@@ -848,5 +1284,7 @@ static struct i2c_driver stmfts_driver = {
 module_i2c_driver(stmfts_driver);
 
 MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
+MODULE_AUTHOR("David Heidelberg <david@ixit.cz>");
+MODULE_AUTHOR("Petr Hodina <petr.hodina@protonmail.com>");
 MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
 MODULE_LICENSE("GPL");

-- 
2.53.0



^ permalink raw reply related

* [PATCH WIP v2 11/11] arm64: dts: qcom: sdm845-google: Add STM FTS touchscreen support
From: David Heidelberg via B4 Relay @ 2026-03-15 18:52 UTC (permalink / raw)
  To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bjorn Andersson, Konrad Dybcio
  Cc: Petr Hodina, linux-input, linux-stm32, linux-arm-kernel,
	linux-kernel, Krzysztof Kozlowski, devicetree, linux-arm-msm,
	phone-devel, David Heidelberg
In-Reply-To: <20260315-stmfts5-v2-0-70bc83ee9591@ixit.cz>

From: Petr Hodina <petr.hodina@protonmail.com>

Basic touchscreen connected to second i2c bus.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
 arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts b/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts
index fa89be500fb85..48d7e7f83c285 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-google-blueline.dts
@@ -26,7 +26,25 @@ &i2c2 {
 
 	status = "okay";
 
-	/* ST,FTS @ 49 */
+	touchscreen@49 {
+		compatible = "st,stmfts5";
+		reg = <0x49>;
+
+		pinctrl-0 = <&touchscreen_pins &touchscreen_reset>;
+		pinctrl-names = "default";
+
+		interrupt-parent = <&tlmm>;
+		interrupts = <125 IRQ_TYPE_LEVEL_LOW>;
+
+		switch-gpios = <&tlmm 136 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
+
+		avdd-supply = <&vreg_l14a_1p8>;
+		vdd-supply = <&vreg_l19a_3p3>;
+
+		touchscreen-size-x = <1080>;
+		touchscreen-size-y = <2160>;
+	};
 };
 
 &mdss_dsi0 {

-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH 1/2] dt-bindings: input: touchscreen: ti,tsc2005: Add
From: phucduc.bui @ 2026-03-16  2:41 UTC (permalink / raw)
  To: robh
  Cc: conor+dt, devicetree, dmitry.torokhov, krzk+dt, linux-input,
	linux-kernel, marex, mingo, mwelling, phucduc.bui, tglx
In-Reply-To: <20260313232347.GA3629471-robh@kernel.org>

Hi Rob,

> Write your commit messages independent of the Linux driver.

Thanks for the feedback.

I will rewrite the commit message to focus on the hardware description
and formalizing the binding, and remove references to the Linux driver
implementation.

I will send a v2 shortly with this change.

Best regards,
Phuc

^ permalink raw reply

* (no subject)
From: phucduc.bui @ 2026-03-16  2:44 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: conor+dt, devicetree, krzk+dt, linux-input, linux-kernel, marex,
	mingo, mwelling, phucduc.bui, robh, tglx
In-Reply-To: <abC1NfUoHCHEeZpr@google.com>

Subject: Re: [PATCH 2/2] Input: Touchscreen: tsc200x - delegate wakeup IRQ 
management to I2C core

Hi Dmitry,

Thanks for the feedback.

I will drop this patch and keep the previous behavior.

I'll send a v2 shortly with only the commit message improvements for
the first patch.

Thanks for the review.

Best regards,
Phuc

^ permalink raw reply

* RE: [PATCH] HID: intel-thc-hid: Set HID_PHYS with PCI BDF
From: Xu, Even @ 2026-03-16  3:38 UTC (permalink / raw)
  To: Daniel Schaefer, linux-input@vger.kernel.org
  Cc: Sun, Xinpeng, Jiri Kosina, Benjamin Tissoires, Sakari Ailus
In-Reply-To: <20260313133925.35740-1-git@danielschaefer.me>



> -----Original Message-----
> From: Daniel Schaefer <git@danielschaefer.me>
> Sent: Friday, March 13, 2026 9:39 PM
> To: linux-input@vger.kernel.org
> Cc: Daniel Schaefer <git@danielschaefer.me>; Xu, Even <even.xu@intel.com>;
> Sun, Xinpeng <xinpeng.sun@intel.com>; Jiri Kosina <jikos@kernel.org>; Benjamin
> Tissoires <bentiss@kernel.org>; Sakari Ailus <sakari.ailus@linux.intel.com>
> Subject: [PATCH] HID: intel-thc-hid: Set HID_PHYS with PCI BDF
> 
> Currently HID_PHYS is empty, which means userspace tools (e.g. fwupd) that
> depend on it for distinguishing the devices, are unable to do so.
> Other drivers like i2c-hid, usbhid, surface-hid, all populate it.
> 
> With this change it's set to, for example: HID_PHYS=0000:00:10.0
> 
> Each function has just a single HID device, as far as I can tell, so there is no need
> to add a suffix.
> 
> Tested with fwupd 2.1.1, can avoid https://github.com/fwupd/fwupd/pull/9995
> 
> Cc: Even Xu <even.xu@intel.com>
> Cc: Xinpeng Sun <xinpeng.sun@intel.com>
> Cc: Jiri Kosina <jikos@kernel.org>
> Cc: Benjamin Tissoires <bentiss@kernel.org>
> Cc: Sakari Ailus <sakari.ailus@linux.intel.com>
> Signed-off-by: Daniel Schaefer <git@danielschaefer.me>
> ---
>  drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c | 1 +  drivers/hid/intel-thc-
> hid/intel-quickspi/quickspi-hid.c | 1 +
>  2 files changed, 2 insertions(+)
> 
> diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
> b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
> index f9fcb398673b..8075992e8732 100644
> --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
> +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c
> @@ -127,6 +127,7 @@ int quicki2c_hid_probe(struct quicki2c_device *qcdev)
>  	hid->product = le16_to_cpu(qcdev->dev_desc.product_id);
>  	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quicki2c-hid",
>  		 hid->vendor, hid->product);
> +	strscpy(hid->phys, dev_name(qcdev->dev), sizeof(hid->phys));
> 
>  	ret = hid_add_device(hid);
>  	if (ret) {
> diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> index 82c72bfa2795..91d5807b4a83 100644
> --- a/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> +++ b/drivers/hid/intel-thc-hid/intel-quickspi/quickspi-hid.c
> @@ -118,6 +118,7 @@ int quickspi_hid_probe(struct quickspi_device *qsdev)
>  	hid->product = le16_to_cpu(qsdev->dev_desc.product_id);
>  	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quickspi-hid",
>  		 hid->vendor, hid->product);
> +	strscpy(hid->phys, dev_name(qsdev->dev), sizeof(hid->phys));

Thanks for the patch!

Reviewed-by: Even Xu <even.xu@intel.com>

> 
>  	ret = hid_add_device(hid);
>  	if (ret) {
> --
> 2.52.0


^ permalink raw reply

* [PATCH v2] dt-bindings: input: touchscreen: ti,tsc2005: Add wakeup-source
From: phucduc.bui @ 2026-03-16  3:46 UTC (permalink / raw)
  To: robh
  Cc: conor+dt, devicetree, dmitry.torokhov, krzk+dt, linux-input,
	linux-kernel, marex, mingo, phucduc.bui, tglx

From: bui duc phuc <phucduc.bui@gmail.com>

Document the "wakeup-source" property for the ti,tsc2005 touchscreen
controllers to allow the device to wake the system from suspend.

Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
---
 .../devicetree/bindings/input/touchscreen/ti,tsc2005.yaml  | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
index 7187c390b2f5..c0aae044d7d4 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
@@ -55,6 +55,9 @@ properties:
   touchscreen-size-x: true
   touchscreen-size-y: true
 
+  wakeup-source:
+    type: boolean
+
 allOf:
   - $ref: touchscreen.yaml#
   - if:
@@ -97,6 +100,8 @@ examples:
 
             ti,x-plate-ohms = <280>;
             ti,esd-recovery-timeout-ms = <8000>;
+
+            wakeup-source;
         };
     };
   - |
@@ -124,5 +129,7 @@ examples:
 
             ti,x-plate-ohms = <280>;
             ti,esd-recovery-timeout-ms = <8000>;
+
+            wakeup-source;
         };
     };
-- 
2.43.0


^ permalink raw reply related

* [RFC PATCH] HID: iota-ups: add driver for LattePanda IOTA UPS
From: Andrew Maney @ 2026-03-16  7:20 UTC (permalink / raw)
  To: linux-input; +Cc: jikos, benjamin.tissoires, Andrew Maney

This driver exposes the DFRobot LattePanda IOTA UPS board as a standard
power_supply device, allowing desktop environments and power management
tools such as UPower and systemd-logind to display battery status,
remaining capacity, and charging status without any special
configuration. It also enables automatic suspend or shutdown on low
battery and power profile configuration via any tool that supports the
standard power_supply interface.

The UPS presents itself as an Arduino Leonardo HID device running custom
firmware (VID 0x2341, PID 0x8036). It reports status and capacity via
HID reports 0x07 and 0x0C respectively.

The charge limit (80% or 100%) is configured via a physical DIP switch
on the UPS board and cannot be detected automatically. Userspace can
inform the driver of the configured limit via
charge_control_end_threshold.

Known issue: the driver occasionally reports 0% capacity briefly on
initial load before the first valid HID report is received. I am
investigating the cause.

Signed-off-by: Andrew Maney <andrewmaney05@gmail.com>
---
 iota-ups.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 355 insertions(+)
 create mode 100644 iota-ups.c

diff --git a/iota-ups.c b/iota-ups.c
new file mode 100644
index 0000000..df334b2
--- /dev/null
+++ b/iota-ups.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/completion.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#define IOTA_UPS_VENDOR_ID	0x2341
+#define IOTA_UPS_PRODUCT_ID	0x8036
+
+#define REPORT_ID_STATUS	0x07
+#define REPORT_ID_CAPACITY	0x0C
+
+#define STATUS_PLUGGED_IN	BIT(0)
+#define STATUS_DISCHARGING	BIT(1)
+#define STATUS_CHARGING		BIT(2)
+
+MODULE_AUTHOR("Andrew Maney");
+MODULE_DESCRIPTION("LattePanda IOTA UPS power supply driver");
+MODULE_LICENSE("GPL");
+
+struct iota_ups {
+	struct hid_device		*hiddev;
+	struct power_supply		*psu;
+	struct power_supply_desc	 psu_desc;
+	spinlock_t			 lock; /* Protects all cached HID report values */
+
+	/* Cached values updated from HID reports */
+	char	serial[64];
+	bool	plugged_in;
+	int	psu_status;
+	int	capacity;
+	int	charge_limit;
+
+	/*
+	 * Wait for both status and capacity reports before registering
+	 * with the power_supply core, so initial values are correct.
+	 */
+	struct completion	got_initial_data;
+	bool			data_ready;
+	bool			got_status;
+	bool			got_capacity;
+};
+
+static enum power_supply_property iota_ups_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
+	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static const struct hid_device_id iota_ups_devices[] = {
+	{ HID_USB_DEVICE(IOTA_UPS_VENDOR_ID, IOTA_UPS_PRODUCT_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, iota_ups_devices);
+
+static int iota_ups_get_property(struct power_supply *supply,
+				 enum power_supply_property psp,
+				 union power_supply_propval *val)
+{
+	struct iota_ups *ups = power_supply_get_drvdata(supply);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ups->lock, flags);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = ups->psu_status;
+		break;
+	/* Remaining capacity as a percentage, 0-100 */
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = ups->capacity;
+		break;
+	/* Always present if the driver is loaded */
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+	/* Whether mains power is connected */
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = ups->plugged_in ? 1 : 0;
+		break;
+	/* System-level UPS, not a laptop battery */
+	case POWER_SUPPLY_PROP_SCOPE:
+		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
+		break;
+	/* V1.0 only accepts 18650 Li-ion cells */
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	/* 80% or 100%, configured via DIP switch on the board */
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
+		val->intval = ups->charge_limit;
+		break;
+	/* V1.0 does not report capacity level via HID */
+	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+		val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+		break;
+	/* V1.0 does not report time remaining */
+	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+		val->intval = 0;
+		break;
+	/* V1.0 does not report health; assume good */
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	/* 3.7V in microvolts, typical Li-ion resting voltage */
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = 3700000;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = "DFRobot";
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = "LattePanda IOTA UPS";
+		break;
+	/* Retrieved from the USB descriptor */
+	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+		val->strval = ups->serial;
+		break;
+	default:
+		spin_unlock_irqrestore(&ups->lock, flags);
+		return -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&ups->lock, flags);
+	return 0;
+}
+
+static int iota_ups_set_property(struct power_supply *supply,
+				 enum power_supply_property psp,
+				 const union power_supply_propval *val)
+{
+	struct iota_ups *ups = power_supply_get_drvdata(supply);
+
+	if (psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) {
+		/*
+		 * V1.0 supports 80% and 100% charge limits only, set via
+		 * DIP switch on the board. This property allows userspace
+		 * to inform the driver which limit is configured.
+		 */
+		if (val->intval != 80 && val->intval != 100)
+			return -EINVAL;
+		ups->charge_limit = val->intval;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int iota_ups_property_is_writable(struct power_supply *supply,
+					 enum power_supply_property psp)
+{
+	return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD;
+}
+
+static int iota_ups_raw_event(struct hid_device *hdev,
+			      struct hid_report *report,
+			      u8 *data, int size)
+{
+	struct iota_ups *ups = hid_get_drvdata(hdev);
+	unsigned long flags;
+	bool changed = false;
+
+	/* All UPS reports are at least 2 bytes */
+	if (size < 2)
+		return 0;
+
+	spin_lock_irqsave(&ups->lock, flags);
+
+	switch (data[0]) {
+	case REPORT_ID_STATUS: {
+		u8 status = data[1];
+		int new_status;
+		bool plugged_in = !!(status & STATUS_PLUGGED_IN);
+
+		if (status & STATUS_CHARGING) {
+			if (ups->capacity >= ups->charge_limit)
+				new_status = POWER_SUPPLY_STATUS_FULL;
+			else
+				new_status = POWER_SUPPLY_STATUS_CHARGING;
+		} else if (status & STATUS_DISCHARGING) {
+			new_status = POWER_SUPPLY_STATUS_DISCHARGING;
+		} else if (plugged_in) {
+			new_status = POWER_SUPPLY_STATUS_FULL;
+		} else {
+			new_status = POWER_SUPPLY_STATUS_UNKNOWN;
+		}
+
+		if (new_status != ups->psu_status ||
+		    plugged_in != ups->plugged_in) {
+			ups->plugged_in = plugged_in;
+			ups->psu_status = new_status;
+			changed = true;
+		}
+
+		ups->got_status = true;
+		break;
+	}
+	case REPORT_ID_CAPACITY: {
+		int new_cap = clamp((int)data[1], 0, 100);
+
+		if (new_cap != ups->capacity) {
+			ups->capacity = new_cap;
+			changed = true;
+		}
+
+		ups->got_capacity = true;
+		break;
+	}
+	}
+
+	/*
+	 * Signal ready only once both status and capacity have been
+	 * received, so the power_supply is registered with valid data.
+	 */
+	if (!ups->data_ready && ups->got_status && ups->got_capacity) {
+		ups->data_ready = true;
+		complete(&ups->got_initial_data);
+	}
+
+	spin_unlock_irqrestore(&ups->lock, flags);
+
+	/*
+	 * Notify the power_supply core outside the spinlock. This
+	 * triggers UPower's PropertiesChanged signal with the new values.
+	 */
+	if (changed && ups->psu)
+		power_supply_changed(ups->psu);
+
+	return 0;
+}
+
+static int iota_ups_probe(struct hid_device *hdev,
+			  const struct hid_device_id *id)
+{
+	struct power_supply_config psu_config = {};
+	struct usb_device *udev;
+	struct iota_ups *ups;
+	int ret;
+
+	ups = devm_kzalloc(&hdev->dev, sizeof(*ups), GFP_KERNEL);
+	if (!ups)
+		return -ENOMEM;
+
+	ups->hiddev		= hdev;
+	ups->psu_status		= POWER_SUPPLY_STATUS_UNKNOWN;
+	ups->capacity		= 50;
+	/*
+	 * Default to 100% — the DIP switch may be set to 80% but there
+	 * is no way to detect this automatically from HID reports.
+	 * Userspace can update this via charge_control_end_threshold.
+	 */
+	ups->charge_limit	= 100;
+	ups->data_ready		= false;
+	ups->got_status		= false;
+	ups->got_capacity	= false;
+
+	init_completion(&ups->got_initial_data);
+	spin_lock_init(&ups->lock);
+	hid_set_drvdata(hdev, ups);
+
+	/* Retrieve serial number from the USB descriptor */
+	udev = to_usb_device(hdev->dev.parent->parent);
+	if (udev->serial)
+		strscpy(ups->serial, udev->serial, sizeof(ups->serial));
+	else
+		strscpy(ups->serial, "Unknown", sizeof(ups->serial));
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "HID parse failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+	if (ret) {
+		hid_err(hdev, "HID hw start failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = hid_hw_open(hdev);
+	if (ret) {
+		hid_err(hdev, "HID hw open failed: %d\n", ret);
+		goto err_stop;
+	}
+
+	/*
+	 * Wait for both status and capacity reports before registering.
+	 * The device sends reports every ~1 second; 3 seconds is safe.
+	 */
+	wait_for_completion_timeout(&ups->got_initial_data,
+				    msecs_to_jiffies(3000));
+
+	ups->psu_desc.name			= "lattepanda-iota-ups";
+	ups->psu_desc.type			= POWER_SUPPLY_TYPE_BATTERY;
+	ups->psu_desc.properties		= iota_ups_properties;
+	ups->psu_desc.num_properties		= ARRAY_SIZE(iota_ups_properties);
+	ups->psu_desc.get_property		= iota_ups_get_property;
+	ups->psu_desc.set_property		= iota_ups_set_property;
+	ups->psu_desc.property_is_writeable	= iota_ups_property_is_writable;
+	psu_config.drv_data = ups;
+
+	ups->psu = devm_power_supply_register(&hdev->dev,
+					      &ups->psu_desc,
+					      &psu_config);
+	if (IS_ERR(ups->psu)) {
+		ret = PTR_ERR(ups->psu);
+		hid_err(hdev, "power_supply register failed: %d\n", ret);
+		goto err_close;
+	}
+
+	/*
+	 * Force an immediate notification so UPower reads the correct
+	 * initial state right after registration.
+	 */
+	power_supply_changed(ups->psu);
+
+	hid_info(hdev, "LattePanda IOTA UPS registered as power supply\n");
+	return 0;
+
+err_close:
+	hid_hw_close(hdev);
+err_stop:
+	hid_hw_stop(hdev);
+	return ret;
+}
+
+static void iota_ups_remove(struct hid_device *hdev)
+{
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+}
+
+static struct hid_driver iota_ups_driver = {
+	.name		= "lattepanda-iota-ups",
+	.id_table	= iota_ups_devices,
+	.probe		= iota_ups_probe,
+	.remove		= iota_ups_remove,
+	.raw_event	= iota_ups_raw_event,
+};
+module_hid_driver(iota_ups_driver);
-- 
2.53.0


^ permalink raw reply related

* [dtor-input:next] BUILD SUCCESS beb2b0a26c3a1021421e8db40154c3b6687b6621
From: kernel test robot @ 2026-03-16  7:32 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: beb2b0a26c3a1021421e8db40154c3b6687b6621  Input: psmouse - remove dedicated kpsmoused workqueue

elapsed time: 736m

configs tested: 233
configs skipped: 3

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    clang-16
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    clang-23
arc                                 defconfig    gcc-15.2.0
arc                   randconfig-001-20260316    clang-23
arc                   randconfig-002-20260316    clang-23
arm                               allnoconfig    clang-23
arm                               allnoconfig    gcc-15.2.0
arm                              allyesconfig    clang-16
arm                                 defconfig    gcc-15.2.0
arm                   randconfig-001-20260316    clang-23
arm                   randconfig-002-20260316    clang-23
arm                   randconfig-003-20260316    clang-23
arm                   randconfig-004-20260316    clang-23
arm64                            allmodconfig    clang-23
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                 randconfig-001-20260316    clang-23
arm64                 randconfig-001-20260316    gcc-11.5.0
arm64                 randconfig-002-20260316    clang-23
arm64                 randconfig-003-20260316    clang-23
arm64                 randconfig-004-20260316    clang-19
arm64                 randconfig-004-20260316    clang-23
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
csky                                defconfig    gcc-15.2.0
csky                  randconfig-001-20260316    clang-23
csky                  randconfig-001-20260316    gcc-15.2.0
csky                  randconfig-002-20260316    clang-23
csky                  randconfig-002-20260316    gcc-14.3.0
hexagon                          allmodconfig    clang-17
hexagon                          allmodconfig    gcc-15.2.0
hexagon                           allnoconfig    clang-23
hexagon                           allnoconfig    gcc-15.2.0
hexagon                             defconfig    gcc-15.2.0
hexagon               randconfig-001-20260316    clang-23
hexagon               randconfig-001-20260316    gcc-11.5.0
hexagon               randconfig-002-20260316    clang-23
hexagon               randconfig-002-20260316    gcc-11.5.0
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-14
i386                              allnoconfig    gcc-15.2.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20260316    gcc-14
i386        buildonly-randconfig-002-20260316    gcc-14
i386        buildonly-randconfig-003-20260316    gcc-14
i386        buildonly-randconfig-004-20260316    gcc-14
i386        buildonly-randconfig-005-20260316    gcc-14
i386        buildonly-randconfig-006-20260316    gcc-14
i386                                defconfig    gcc-15.2.0
i386                  randconfig-001-20260316    gcc-14
i386                  randconfig-002-20260316    gcc-14
i386                  randconfig-003-20260316    gcc-14
i386                  randconfig-004-20260316    gcc-14
i386                  randconfig-005-20260316    gcc-14
i386                  randconfig-006-20260316    gcc-14
i386                  randconfig-007-20260316    gcc-14
i386                  randconfig-011-20260316    clang-20
i386                  randconfig-011-20260316    gcc-13
i386                  randconfig-012-20260316    gcc-13
i386                  randconfig-012-20260316    gcc-14
i386                  randconfig-013-20260316    clang-20
i386                  randconfig-013-20260316    gcc-13
i386                  randconfig-014-20260316    gcc-13
i386                  randconfig-015-20260316    clang-20
i386                  randconfig-015-20260316    gcc-13
i386                  randconfig-016-20260316    gcc-13
i386                  randconfig-016-20260316    gcc-14
i386                  randconfig-017-20260316    clang-20
i386                  randconfig-017-20260316    gcc-13
loongarch                        allmodconfig    clang-23
loongarch                         allnoconfig    clang-23
loongarch                         allnoconfig    gcc-15.2.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20260316    gcc-11.5.0
loongarch             randconfig-001-20260316    gcc-14.3.0
loongarch             randconfig-002-20260316    clang-18
loongarch             randconfig-002-20260316    gcc-11.5.0
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    clang-16
m68k                                defconfig    clang-19
m68k                                defconfig    gcc-15.2.0
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    clang-19
microblaze                          defconfig    gcc-15.2.0
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    clang-23
nios2                             allnoconfig    clang-23
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    clang-19
nios2                               defconfig    gcc-11.5.0
nios2                 randconfig-001-20260316    gcc-11.5.0
nios2                 randconfig-002-20260316    gcc-11.5.0
nios2                 randconfig-002-20260316    gcc-8.5.0
openrisc                         allmodconfig    clang-23
openrisc                          allnoconfig    clang-23
openrisc                          allnoconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    clang-23
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.2.0
parisc                randconfig-001-20260316    gcc-13.4.0
parisc                randconfig-001-20260316    gcc-8.5.0
parisc                randconfig-002-20260316    gcc-12.5.0
parisc                randconfig-002-20260316    gcc-13.4.0
parisc64                            defconfig    clang-19
parisc64                            defconfig    gcc-15.2.0
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    clang-23
powerpc                           allnoconfig    gcc-15.2.0
powerpc               randconfig-001-20260316    clang-23
powerpc               randconfig-001-20260316    gcc-13.4.0
powerpc               randconfig-002-20260316    clang-23
powerpc               randconfig-002-20260316    gcc-13.4.0
powerpc64             randconfig-001-20260316    gcc-13.4.0
powerpc64             randconfig-002-20260316    gcc-13.4.0
powerpc64             randconfig-002-20260316    gcc-8.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    clang-23
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.2.0
riscv                 randconfig-001-20260316    gcc-12.5.0
riscv                 randconfig-001-20260316    gcc-15.2.0
riscv                 randconfig-002-20260316    gcc-12.5.0
riscv                 randconfig-002-20260316    gcc-8.5.0
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    gcc-15.2.0
s390                  randconfig-001-20260316    clang-18
s390                  randconfig-001-20260316    gcc-12.5.0
s390                  randconfig-002-20260316    gcc-12.5.0
s390                  randconfig-002-20260316    gcc-14.3.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    clang-23
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sh                                  defconfig    gcc-15.2.0
sh                    randconfig-001-20260316    gcc-12.5.0
sh                    randconfig-001-20260316    gcc-15.2.0
sh                    randconfig-002-20260316    gcc-12.5.0
sh                          rsk7203_defconfig    gcc-15.2.0
sh                           sh2007_defconfig    gcc-15.2.0
sparc                             allnoconfig    clang-23
sparc                             allnoconfig    gcc-15.2.0
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260316    gcc-12.5.0
sparc                 randconfig-001-20260316    gcc-8.5.0
sparc                 randconfig-002-20260316    gcc-12.5.0
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20260316    gcc-12.5.0
sparc64               randconfig-001-20260316    gcc-8.5.0
sparc64               randconfig-002-20260316    gcc-12.5.0
sparc64               randconfig-002-20260316    gcc-15.2.0
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-14
um                               allyesconfig    gcc-15.2.0
um                                  defconfig    clang-23
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260316    gcc-12.5.0
um                    randconfig-001-20260316    gcc-14
um                    randconfig-002-20260316    clang-23
um                    randconfig-002-20260316    gcc-12.5.0
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                            allnoconfig    clang-23
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260316    clang-20
x86_64      buildonly-randconfig-001-20260316    gcc-14
x86_64      buildonly-randconfig-002-20260316    clang-20
x86_64      buildonly-randconfig-003-20260316    clang-20
x86_64      buildonly-randconfig-004-20260316    clang-20
x86_64      buildonly-randconfig-004-20260316    gcc-14
x86_64      buildonly-randconfig-005-20260316    clang-20
x86_64      buildonly-randconfig-005-20260316    gcc-14
x86_64      buildonly-randconfig-006-20260316    clang-20
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20260316    clang-20
x86_64                randconfig-001-20260316    gcc-14
x86_64                randconfig-002-20260316    clang-20
x86_64                randconfig-003-20260316    clang-20
x86_64                randconfig-004-20260316    clang-20
x86_64                randconfig-004-20260316    gcc-14
x86_64                randconfig-005-20260316    clang-20
x86_64                randconfig-006-20260316    clang-20
x86_64                randconfig-011-20260316    gcc-14
x86_64                randconfig-012-20260316    gcc-14
x86_64                randconfig-013-20260316    gcc-14
x86_64                randconfig-014-20260316    gcc-14
x86_64                randconfig-015-20260316    clang-20
x86_64                randconfig-015-20260316    gcc-14
x86_64                randconfig-016-20260316    gcc-14
x86_64                randconfig-071-20260316    gcc-12
x86_64                randconfig-072-20260316    gcc-12
x86_64                randconfig-072-20260316    gcc-14
x86_64                randconfig-073-20260316    gcc-12
x86_64                randconfig-073-20260316    gcc-14
x86_64                randconfig-074-20260316    gcc-12
x86_64                randconfig-074-20260316    gcc-14
x86_64                randconfig-075-20260316    clang-20
x86_64                randconfig-075-20260316    gcc-12
x86_64                randconfig-076-20260316    clang-20
x86_64                randconfig-076-20260316    gcc-12
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-23
xtensa                            allnoconfig    gcc-15.2.0
xtensa                           allyesconfig    clang-23
xtensa                randconfig-001-20260316    gcc-12.5.0
xtensa                randconfig-001-20260316    gcc-15.2.0
xtensa                randconfig-002-20260316    gcc-12.5.0
xtensa                randconfig-002-20260316    gcc-15.2.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH] HID: intel-thc-hid: Set HID_PHYS with PCI BDF
From: Jiri Kosina @ 2026-03-16 10:25 UTC (permalink / raw)
  To: Daniel Schaefer
  Cc: linux-input, Even Xu, Xinpeng Sun, Benjamin Tissoires,
	Sakari Ailus
In-Reply-To: <20260313133925.35740-1-git@danielschaefer.me>

On Fri, 13 Mar 2026, Daniel Schaefer wrote:

> Currently HID_PHYS is empty, which means userspace tools (e.g. fwupd)
> that depend on it for distinguishing the devices, are unable to do so.
> Other drivers like i2c-hid, usbhid, surface-hid, all populate it.
> 
> With this change it's set to, for example: HID_PHYS=0000:00:10.0
> 
> Each function has just a single HID device, as far as I can tell, so
> there is no need to add a suffix.
> 
> Tested with fwupd 2.1.1, can avoid https://github.com/fwupd/fwupd/pull/9995
> 
> Cc: Even Xu <even.xu@intel.com>
> Cc: Xinpeng Sun <xinpeng.sun@intel.com>
> Cc: Jiri Kosina <jikos@kernel.org>
> Cc: Benjamin Tissoires <bentiss@kernel.org>
> Cc: Sakari Ailus <sakari.ailus@linux.intel.com>
> Signed-off-by: Daniel Schaefer <git@danielschaefer.me>

Applied to hid.git#for-7.0/upstream-fixes, thanks.

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH v2] dt-bindings: input: touchscreen: ti,tsc2005: Add wakeup-source
From: Conor Dooley @ 2026-03-16 11:13 UTC (permalink / raw)
  To: phucduc.bui
  Cc: robh, conor+dt, devicetree, dmitry.torokhov, krzk+dt, linux-input,
	linux-kernel, marex, mingo, tglx
In-Reply-To: <20260316034606.11304-1-phucduc.bui@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

On Mon, Mar 16, 2026 at 10:46:06AM +0700, phucduc.bui@gmail.com wrote:
> From: bui duc phuc <phucduc.bui@gmail.com>
> 
> Document the "wakeup-source" property for the ti,tsc2005 touchscreen
> controllers to allow the device to wake the system from suspend.
> 
> Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
> ---
>  .../devicetree/bindings/input/touchscreen/ti,tsc2005.yaml  | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
> index 7187c390b2f5..c0aae044d7d4 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/ti,tsc2005.yaml
> @@ -55,6 +55,9 @@ properties:
>    touchscreen-size-x: true
>    touchscreen-size-y: true
>  
> +  wakeup-source:
> +    type: boolean

wakeup-source: true

> +
>  allOf:
>    - $ref: touchscreen.yaml#
>    - if:
> @@ -97,6 +100,8 @@ examples:
>  
>              ti,x-plate-ohms = <280>;
>              ti,esd-recovery-timeout-ms = <8000>;
> +

Remove the blank line please.

pw-bot: changes-requested

Thanks,
Conor.

> +            wakeup-source;
>          };
>      };
>    - |
> @@ -124,5 +129,7 @@ examples:
>  
>              ti,x-plate-ohms = <280>;
>              ti,esd-recovery-timeout-ms = <8000>;
> +
> +            wakeup-source;
>          };
>      };
> -- 
> 2.43.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH 50/61] iommu: Prefer IS_ERR_OR_NULL over manual NULL check
From: Robin Murphy @ 2026-03-16 13:30 UTC (permalink / raw)
  To: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
	dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
	linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
	linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
	linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
	linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
	linux-nfs, linux-omap, linux-phy, linux-pm, linux-rockchip,
	linux-s390, linux-scsi, linux-sctp, linux-security-module,
	linux-sh, linux-sound, linux-stm32, linux-trace-kernel, linux-usb,
	linux-wireless, netdev, ntfs3, samba-technical, sched-ext,
	target-devel, tipc-discussion, v9fs
  Cc: Joerg Roedel, Will Deacon
In-Reply-To: <20260310-b4-is_err_or_null-v1-50-bd63b656022d@avm.de>

On 2026-03-10 11:49 am, Philipp Hahn wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.

AFAICS it doesn't look possible for the argument to be anything other 
than valid at both callsites, so *both* conditions here seem in fact to 
be entirely redundant.

> Change generated with coccinelle.

Please use coccinelle responsibly. Mechanical changes are great for 
scripted API updates, but for cleanup, whilst it's ideal for *finding* 
areas of code that are worth looking at, the code then wants actually 
looking at, in its whole context, because meaningful cleanup often goes 
deeper than trivial replacement.

In particular, anywhere IS_ERR_OR_NULL() is genuinely relevant is 
usually a sign of bad interface design, so if you're looking at this 
then you really should be looking first and foremost to remove any 
checks that are already unnecessary, and for the remainder, to see if 
the thing being checked can be improved to not mix the two different 
styles. That would be constructive and (usually) welcome cleanup. Simply 
churning a bunch of code with this ugly macro that's arguably less 
readable than what it replaces, not so much.

Thanks,
Robin.

> To: Joerg Roedel <joro@8bytes.org>
> To: Will Deacon <will@kernel.org>
> To: Robin Murphy <robin.murphy@arm.com>
> Cc: iommu@lists.linux.dev
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
> ---
>   drivers/iommu/omap-iommu.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
> index 8231d7d6bb6a9202025643639a6b28e6faa84659..500a42b57a997696ff37c76f028a717ab71d01f9 100644
> --- a/drivers/iommu/omap-iommu.c
> +++ b/drivers/iommu/omap-iommu.c
> @@ -881,7 +881,7 @@ static int omap_iommu_attach(struct omap_iommu *obj, u32 *iopgd)
>    **/
>   static void omap_iommu_detach(struct omap_iommu *obj)
>   {
> -	if (!obj || IS_ERR(obj))
> +	if (IS_ERR_OR_NULL(obj))
>   		return;
>   
>   	spin_lock(&obj->iommu_lock);
> 


^ permalink raw reply

* [PATCH] HID: wiimote: Fix table layout in comment
From: J. Neuschäfer via B4 Relay @ 2026-03-16 14:45 UTC (permalink / raw)
  To: David Rheinsberg, Jiri Kosina, Benjamin Tissoires
  Cc: linux-input, linux-kernel, J. Neuschäfer

From: "J. Neuschäfer" <j.ne@posteo.net>

Some tab characters snuck into the data layout table for turntable
extensions, which resulted in the table only looking right at a tabstop
of 4, which is uncommon in the kernel. Change them to the equivalent
amount of spaces, which should look correct in any editor.

Signed-off-by: J. Neuschäfer <j.ne@posteo.net>
---
 drivers/hid/hid-wiimote-modules.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index dbccdfa6391672..d9e1b4313d6465 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -2442,12 +2442,12 @@ static void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext)
 	/* 
 	 * Byte |  7   |  6  |  5  |  4  |  3  |  2   |  1   |  0     |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
-	 *   0  | RTT<4:3>   | 		      	  SX <5:0> 			      |
-	 *   1  | RTT<2:1>   |				  SY <5:0>			      |
+	 *   0  | RTT<4:3>   |                SX <5:0>                |
+	 *   1  | RTT<2:1>   |                SY <5:0>                |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
 	 *   2  |RTT<0>|  ED<4:3>  |          CS<3:0>        | RTT<5> |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
-	 *   3  |     ED<2:0> 	   | 			 LTT<4:0>			  |
+	 *   3  |     ED<2:0>      |             LTT<4:0>             |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
 	 *   4  |  0   |  0  | LBR |  B- |  0  |  B+  |  RBR | LTT<5> |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
@@ -2458,12 +2458,12 @@ static void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext)
 	 * With Motion+ enabled, it will look like this:
 	 * Byte |  8   |  7  |  6  |  5  |  4  |  3   |  2   |  1     |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
-	 *   1  | RTT<4:3>   | 		      	  SX <5:1> 		 |	  0   |
-	 *   2  | RTT<2:1>   |				  SY <5:1>		 |	  0   |
+	 *   1  | RTT<4:3>   |                SX <5:1>       |    0   |
+	 *   2  | RTT<2:1>   |                SY <5:1>       |    0   |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
 	 *   3  |RTT<0>|  ED<4:3>  |          CS<3:0>        | RTT<5> |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
-	 *   4  |     ED<2:0> 	   | 			 LTT<4:0>			  |
+	 *   4  |     ED<2:0>      |             LTT<4:0>             |
 	 *------+------+-----+-----+-----+-----+------+------+--------+
 	 *   5  |  0   |  0  | LBR |  B- |  0  |  B+  | RBR  |  XXXX  |
 	 *------+------+-----+-----+-----+-----+------+------+--------+

---
base-commit: f338e77383789c0cae23ca3d48adcc5e9e137e3c
change-id: 20260316-wiimod-table-cd9abc0a2a98

Best regards,
-- 
J. Neuschäfer <j.ne@posteo.net>



^ permalink raw reply related

* Re: [PATCH 1/1] HID: logitech-hidpp: Prevent use-after-free on force feedback initialisation failure
From: Lee Jones @ 2026-03-16 15:11 UTC (permalink / raw)
  To: Günther Noack
  Cc: Filipe Laíns, Bastien Nocera, Jiri Kosina,
	Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <aaareetB3Hhd6xgI@google.com>

On Tue, 03 Mar 2026, Günther Noack wrote:

> On Fri, Feb 27, 2026 at 10:09:38AM +0000, Lee Jones wrote:
> > Presently, if the force feedback initialisation fails when probing the
> > Logitech G920 Driving Force Racing Wheel for Xbox One, an error number
> > will be returned and propagated before the userspace infrastructure
> > (sysfs and /dev/input) has been torn down.  If userspace ignores the
> > errors and continues to use its references to these dangling entities, a
> > UAF will promptly follow.
> > 
> > We have 2 options; continue to return the error, but ensure that all of
> > the infrastructure is torn down accordingly or continue to treat this
> > condition as a warning by emitting the message but returning success.
> > It is thought that the original author's intention was to emit the
> > warning but keep the device functional, less the force feedback feature,
> > so let's go with that.
> > 
> > Signed-off-by: Lee Jones <lee@kernel.org>
> > ---
> >  drivers/hid/hid-logitech-hidpp.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> > index e871f1729d4b..eee9ab6a2fc4 100644
> > --- a/drivers/hid/hid-logitech-hidpp.c
> > +++ b/drivers/hid/hid-logitech-hidpp.c
> > @@ -4487,10 +4487,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >  		if (!ret)
> >  			ret = hidpp_ff_init(hidpp, &data);
> >  
> > -		if (ret)
> > +		if (ret) {
> >  			hid_warn(hidpp->hid_dev,
> >  		     "Unable to initialize force feedback support, errno %d\n",
> >  				 ret);
> > +			ret = 0;
> > +		}
> >  	}
> >  
> >  	/*
> > -- 
> > 2.53.0.473.g4a7958ca14-goog
> > 
> 
> Reviewed-by: Günther Noack <gnoack@google.com>

What are the subsystem preferences in terms of pokes or [RESENDS], please?

I'm happy to submit a [RESEND] if that's required to get this back into view.

-- 
Lee Jones [李琼斯]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox