* [PATCH v6 2/7] mfd: macsmc: Wire up Apple SMC RTC subdevice
From: James Calligeros @ 2025-12-15 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, James Calligeros
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Add the new SMC RTC function to the mfd device
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
drivers/mfd/macsmc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index e3893e255ce5..9099a7a22f1f 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -47,6 +47,7 @@
static const struct mfd_cell apple_smc_devs[] = {
MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
+ MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"),
};
static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg,
--
2.52.0
^ permalink raw reply related
* [PATCH v6 3/7] mfd: macsmc: Wire up Apple SMC hwmon subdevice
From: James Calligeros @ 2025-12-15 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, James Calligeros
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Add the SMC hwmon functionality to the mfd device
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
drivers/mfd/macsmc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index 9099a7a22f1f..fa7b822d55bd 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -46,6 +46,7 @@
static const struct mfd_cell apple_smc_devs[] = {
MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
+ MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"),
MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"),
};
--
2.52.0
^ permalink raw reply related
* [PATCH v6 4/7] input: macsmc-input: New driver to handle the Apple Mac SMC buttons/lid
From: James Calligeros @ 2025-12-15 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, James Calligeros
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc, Hector Martin
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
From: Hector Martin <marcan@marcan.st>
This driver implements power button and lid switch support for Apple Mac
devices using SMC controllers driven by the macsmc driver.
In addition to basic input support, this also responds to the final
shutdown warning (when the power button is held down long enough) by
doing an emergency kernel poweroff. This allows the NVMe controller to
be cleanly shut down, which prevents data loss for in-cache data.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Hector Martin <marcan@marcan.st>
Co-developed-by: Sven Peter <sven@kernel.org>
Signed-off-by: Sven Peter <sven@kernel.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
MAINTAINERS | 1 +
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/macsmc-input.c | 207 +++++++++++++++++++++++++
4 files changed, 220 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5f160eb6762e..7f2160a18da2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2492,6 +2492,7 @@ F: drivers/hwmon/macsmc-hwmon.c
F: drivers/pmdomain/apple/
F: drivers/i2c/busses/i2c-pasemi-core.c
F: drivers/i2c/busses/i2c-pasemi-platform.c
+F: drivers/input/misc/macsmc-input.c
F: drivers/input/touchscreen/apple_z2.c
F: drivers/iommu/apple-dart.c
F: drivers/iommu/io-pgtable-dart.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 94a753fcb64f..0e805c870e29 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -1003,4 +1003,15 @@ config INPUT_STPMIC1_ONKEY
To compile this driver as a module, choose M here: the
module will be called stpmic1_onkey.
+config INPUT_MACSMC
+ tristate "Apple Mac SMC lid/buttons"
+ depends on MFD_MACSMC
+ help
+ Say Y here if you want to use the input events delivered via the
+ SMC controller on Apple Mac machines using the macsmc driver.
+ This includes lid open/close and the power button.
+
+ To compile this driver as a module, choose M here: the
+ module will be called macsmc-input.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415fc4e2918b..174031304975 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
+obj-$(CONFIG_INPUT_MACSMC_INPUT) += macsmc-input.o
obj-$(CONFIG_INPUT_MAX7360_ROTARY) += max7360-rotary.o
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
diff --git a/drivers/input/misc/macsmc-input.c b/drivers/input/misc/macsmc-input.c
new file mode 100644
index 000000000000..f4598e65fc80
--- /dev/null
+++ b/drivers/input/misc/macsmc-input.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SMC input event driver
+ * Copyright The Asahi Linux Contributors
+ *
+ * This driver exposes certain events from the SMC as an input device.
+ * This includes the lid open/close and power button notifications.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/mfd/macsmc.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+/**
+ * struct macsmc_input
+ * @dev: Underlying struct device for the input sub-device
+ * @smc: Pointer to apple_smc struct of the mfd parent
+ * @input: Allocated input_dev; devres managed
+ * @nb: Notifier block used for incoming events from SMC (e.g. button pressed down)
+ * @wakeup_mode: Set to true when system is suspended and power button events should wake it
+ */
+struct macsmc_input {
+ struct device *dev;
+ struct apple_smc *smc;
+ struct input_dev *input;
+ struct notifier_block nb;
+ bool wakeup_mode;
+};
+
+#define SMC_EV_BTN 0x7201
+#define SMC_EV_LID 0x7203
+
+#define BTN_POWER 0x01 /* power button on e.g. Mac Mini chasis pressed */
+#define BTN_TOUCHID 0x06 /* combined TouchID / power button on MacBooks pressed */
+#define BTN_POWER_HELD_SHORT 0xfe /* power button briefly held down */
+#define BTN_POWER_HELD_LONG 0x00 /* power button held down; sent just before forced poweroff */
+
+static void macsmc_input_event_button(struct macsmc_input *smcin, unsigned long event)
+{
+ u8 button = (event >> 8) & 0xff;
+ u8 state = !!(event & 0xff);
+
+ switch (button) {
+ case BTN_POWER:
+ case BTN_TOUCHID:
+ pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && state));
+
+ /* Suppress KEY_POWER event to prevent immediate shutdown on wake */
+ if (smcin->wakeup_mode)
+ return;
+
+ input_report_key(smcin->input, KEY_POWER, state);
+ input_sync(smcin->input);
+ break;
+ case BTN_POWER_HELD_SHORT: /* power button held down; ignore */
+ break;
+ case BTN_POWER_HELD_LONG:
+ /*
+ * If we get here the power button has been held down for a while and
+ * we have about 4 seconds before forced power-off is triggered by SMC.
+ * Try to do an emergency shutdown to make sure the NVMe cache is
+ * flushed. macOS actually does this by panicing (!)...
+ */
+ if (state) {
+ dev_crit(smcin->dev, "Triggering forced shutdown!\n");
+ if (kernel_can_power_off())
+ kernel_power_off();
+ else /* Missing macsmc-reboot driver? */
+ kernel_restart("SMC power button triggered restart");
+ }
+ break;
+ default:
+ dev_warn(smcin->dev, "Unknown SMC button event: %04lx\n", event & 0xffff);
+ }
+}
+
+static void macsmc_input_event_lid(struct macsmc_input *smcin, unsigned long event)
+{
+ u8 lid_state = !!((event >> 8) & 0xff);
+
+ pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && !lid_state));
+ input_report_switch(smcin->input, SW_LID, lid_state);
+ input_sync(smcin->input);
+}
+
+static int macsmc_input_event(struct notifier_block *nb, unsigned long event, void *data)
+{
+ struct macsmc_input *smcin = container_of(nb, struct macsmc_input, nb);
+ u16 type = event >> 16;
+
+ switch (type) {
+ case SMC_EV_BTN:
+ macsmc_input_event_button(smcin, event);
+ return NOTIFY_OK;
+ case SMC_EV_LID:
+ macsmc_input_event_lid(smcin, event);
+ return NOTIFY_OK;
+ default:
+ /* SMC event meant for another driver */
+ return NOTIFY_DONE;
+ }
+}
+
+static int macsmc_input_probe(struct platform_device *pdev)
+{
+ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
+ struct macsmc_input *smcin;
+ bool have_lid, have_power;
+ int error;
+
+ /* Bail early if this SMC neither supports power button nor lid events */
+ have_lid = apple_smc_key_exists(smc, SMC_KEY(MSLD));
+ have_power = apple_smc_key_exists(smc, SMC_KEY(bHLD));
+ if (!have_lid && !have_power)
+ return -ENODEV;
+
+ smcin = devm_kzalloc(&pdev->dev, sizeof(*smcin), GFP_KERNEL);
+ if (!smcin)
+ return -ENOMEM;
+
+ smcin->dev = &pdev->dev;
+ smcin->smc = smc;
+ platform_set_drvdata(pdev, smcin);
+
+ smcin->input = devm_input_allocate_device(&pdev->dev);
+ if (!smcin->input)
+ return -ENOMEM;
+
+ smcin->input->phys = "macsmc-input (0)";
+ smcin->input->name = "Apple SMC power/lid events";
+
+ if (have_lid)
+ input_set_capability(smcin->input, EV_SW, SW_LID);
+ if (have_power)
+ input_set_capability(smcin->input, EV_KEY, KEY_POWER);
+
+ if (have_lid) {
+ u8 val;
+
+ error = apple_smc_read_u8(smc, SMC_KEY(MSLD), &val);
+ if (error < 0)
+ dev_warn(&pdev->dev, "Failed to read initial lid state\n");
+ else
+ input_report_switch(smcin->input, SW_LID, val);
+ }
+
+ if (have_power) {
+ u32 val;
+
+ error = apple_smc_read_u32(smc, SMC_KEY(bHLD), &val);
+ if (error < 0)
+ dev_warn(&pdev->dev, "Failed to read initial power button state\n");
+ else
+ input_report_key(smcin->input, KEY_POWER, val & 1);
+ }
+
+ error = input_register_device(smcin->input);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+ return error;
+ }
+
+ input_sync(smcin->input);
+
+ smcin->nb.notifier_call = macsmc_input_event;
+ blocking_notifier_chain_register(&smc->event_handlers, &smcin->nb);
+
+ device_init_wakeup(&pdev->dev, true);
+
+ return 0;
+}
+
+static int macsmc_input_pm_prepare(struct device *dev)
+{
+ struct macsmc_input *smcin = dev_get_drvdata(dev);
+
+ smcin->wakeup_mode = true;
+ return 0;
+}
+
+static void macsmc_input_pm_complete(struct device *dev)
+{
+ struct macsmc_input *smcin = dev_get_drvdata(dev);
+
+ smcin->wakeup_mode = false;
+}
+
+static const struct dev_pm_ops macsmc_input_pm_ops = {
+ .prepare = macsmc_input_pm_prepare,
+ .complete = macsmc_input_pm_complete,
+};
+
+static struct platform_driver macsmc_input_driver = {
+ .driver = {
+ .name = "macsmc-input",
+ .pm = &macsmc_input_pm_ops,
+ },
+ .probe = macsmc_input_probe,
+};
+module_platform_driver(macsmc_input_driver);
+
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_DESCRIPTION("Apple SMC input driver");
+MODULE_ALIAS("platform:macsmc-input");
--
2.52.0
^ permalink raw reply related
* [PATCH v6 5/7] mfd: macsmc: Wire up Apple SMC input subdevice
From: James Calligeros @ 2025-12-15 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, James Calligeros
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Add the new SMC input function to the mfd device
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
drivers/mfd/macsmc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index fa7b822d55bd..85410f357603 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -45,6 +45,7 @@
#define SMC_TIMEOUT_MS 500
static const struct mfd_cell apple_smc_devs[] = {
+ MFD_CELL_NAME("macsmc-input"),
MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"),
MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
--
2.52.0
^ permalink raw reply related
* [PATCH v6 6/7] arm64: dts: apple: t8103,t60xx,t8112: Add SMC RTC node
From: James Calligeros @ 2025-12-15 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, James Calligeros
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
From: Sven Peter <sven@kernel.org>
The System Manager Controller of all M1/M2 SoCs supports the RTC
sub-device.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Sven Peter <sven@kernel.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../arm64/boot/dts/apple/t600x-die0.dtsi | 6 ++++++
.../arm64/boot/dts/apple/t602x-die0.dtsi | 6 ++++++
arch/arm64/boot/dts/apple/t8103.dtsi | 6 ++++++
arch/arm64/boot/dts/apple/t8112.dtsi | 6 ++++++
4 files changed, 24 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
index 3603b276a2ab..f715b19efd16 100644
--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
@@ -44,6 +44,12 @@ smc_reboot: reboot {
nvmem-cell-names = "shutdown_flag", "boot_stage",
"boot_error_count", "panic_count";
};
+
+ rtc {
+ compatible = "apple,smc-rtc";
+ nvmem-cells = <&rtc_offset>;
+ nvmem-cell-names = "rtc_offset";
+ };
};
smc_mbox: mbox@290408000 {
diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
index 2e7d2bf08ddc..8622ddea7b44 100644
--- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
@@ -121,6 +121,12 @@ smc_reboot: reboot {
nvmem-cell-names = "shutdown_flag", "boot_stage",
"boot_error_count", "panic_count";
};
+
+ rtc {
+ compatible = "apple,smc-rtc";
+ nvmem-cells = <&rtc_offset>;
+ nvmem-cell-names = "rtc_offset";
+ };
};
pinctrl_smc: pinctrl@2a2820000 {
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index 8b7b27887968..59f2678639cf 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -916,6 +916,12 @@ smc_reboot: reboot {
nvmem-cell-names = "shutdown_flag", "boot_stage",
"boot_error_count", "panic_count";
};
+
+ rtc {
+ compatible = "apple,smc-rtc";
+ nvmem-cells = <&rtc_offset>;
+ nvmem-cell-names = "rtc_offset";
+ };
};
smc_mbox: mbox@23e408000 {
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index 3f79878b25af..6bc3f58b06f7 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -919,6 +919,12 @@ smc_reboot: reboot {
nvmem-cell-names = "shutdown_flag", "boot_stage",
"boot_error_count", "panic_count";
};
+
+ rtc {
+ compatible = "apple,smc-rtc";
+ nvmem-cells = <&rtc_offset>;
+ nvmem-cell-names = "rtc_offset";
+ };
};
smc_mbox: mbox@23e408000 {
--
2.52.0
^ permalink raw reply related
* [PATCH v6 7/7] arm64: dts: apple: t8103, t8112, t60xx: Add hwmon SMC subdevice
From: James Calligeros @ 2025-12-15 9:37 UTC (permalink / raw)
To: Sven Peter, Janne Grunau, Alyssa Rosenzweig, Neal Gompa,
Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Jean Delvare, Guenter Roeck, Dmitry Torokhov,
Jonathan Corbet, James Calligeros
Cc: asahi, linux-arm-kernel, devicetree, linux-kernel, linux-rtc,
linux-hwmon, linux-input, linux-doc
In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com>
Apple's System Management Controller integrates numerous sensors
that can be exposed via hwmon. Add the subdevice, compatible,
and some common sensors that are exposed on every currently
supported device as a starting point.
Reviewed-by: Neal Gompa <neal@gompa.dev>
Co-developed-by: Janne Grunau <j@jannau.net>
Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
.../boot/dts/apple/hwmon-common.dtsi | 33 +++++++++++++++++++++++++
.../boot/dts/apple/hwmon-fan-dual.dtsi | 22 +++++++++++++++++
arch/arm64/boot/dts/apple/hwmon-fan.dtsi | 17 +++++++++++++
.../boot/dts/apple/hwmon-laptop.dtsi | 33 +++++++++++++++++++++++++
.../boot/dts/apple/hwmon-mac-mini.dtsi | 15 +++++++++++
.../arm64/boot/dts/apple/t6001-j375c.dts | 2 ++
arch/arm64/boot/dts/apple/t6001.dtsi | 2 ++
.../arm64/boot/dts/apple/t6002-j375d.dts | 2 ++
.../arm64/boot/dts/apple/t600x-die0.dtsi | 4 +++
.../boot/dts/apple/t600x-j314-j316.dtsi | 3 +++
.../arm64/boot/dts/apple/t602x-die0.dtsi | 4 +++
arch/arm64/boot/dts/apple/t8103-j274.dts | 2 ++
arch/arm64/boot/dts/apple/t8103-j293.dts | 3 +++
arch/arm64/boot/dts/apple/t8103-j313.dts | 2 ++
arch/arm64/boot/dts/apple/t8103-j456.dts | 2 ++
arch/arm64/boot/dts/apple/t8103-j457.dts | 2 ++
arch/arm64/boot/dts/apple/t8103.dtsi | 5 ++++
arch/arm64/boot/dts/apple/t8112-j413.dts | 2 ++
arch/arm64/boot/dts/apple/t8112-j473.dts | 2 ++
arch/arm64/boot/dts/apple/t8112-j493.dts | 3 +++
arch/arm64/boot/dts/apple/t8112.dtsi | 5 ++++
21 files changed, 165 insertions(+)
diff --git a/arch/arm64/boot/dts/apple/hwmon-common.dtsi b/arch/arm64/boot/dts/apple/hwmon-common.dtsi
new file mode 100644
index 000000000000..b87021855fdf
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-common.dtsi
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Hardware monitoring sensors expected to be found on all Apple Silicon devices
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&smc_hwmon {
+ current-ID0R {
+ apple,key-id = "ID0R";
+ label = "AC Input Current";
+ };
+ power-PSTR {
+ apple,key-id = "PSTR";
+ label = "Total System Power";
+ };
+ power-PDTR {
+ apple,key-id = "PDTR";
+ label = "AC Input Power";
+ };
+ power-PMVR {
+ apple,key-id = "PMVR";
+ label = "3.8 V Rail Power";
+ };
+ temperature-TH0x {
+ apple,key-id = "TH0x";
+ label = "NAND Flash Temperature";
+ };
+ voltage-VD0R {
+ apple,key-id = "VD0R";
+ label = "AC Input Voltage";
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi
new file mode 100644
index 000000000000..3eef0721bcca
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-fan-dual.dtsi
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * SMC hwmon fan keys for Apple Silicon desktops/laptops with two fans
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include "hwmon-fan.dtsi"
+
+&smc_hwmon {
+ fan-F0Ac {
+ label = "Fan 1";
+ };
+ fan-F1Ac {
+ apple,key-id = "F1Ac";
+ label = "Fan 2";
+ apple,fan-minimum = "F1Mn";
+ apple,fan-maximum = "F1Mx";
+ apple,fan-target = "F1Tg";
+ apple,fan-mode = "F1Md";
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-fan.dtsi b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi
new file mode 100644
index 000000000000..fba9faf38f4b
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-fan.dtsi
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * hwmon fan keys for Apple Silicon desktops/laptops with a single fan.
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&smc_hwmon {
+ fan-F0Ac {
+ apple,key-id = "F0Ac";
+ label = "Fan";
+ apple,fan-minimum = "F0Mn";
+ apple,fan-maximum = "F0Mx";
+ apple,fan-target = "F0Tg";
+ apple,fan-mode = "F0Md";
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi
new file mode 100644
index 000000000000..0c4666282a5c
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-laptop.dtsi
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Hardware monitoring sensors expected on all Apple Silicon laptops
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+&smc_hwmon {
+ power-PHPC {
+ apple,key-id = "PHPC";
+ label = "Heatpipe Power";
+ };
+ temperature-TB0T {
+ apple,key-id = "TB0T";
+ label = "Battery Hotspot Temperature";
+ };
+ temperature-TCHP {
+ apple,key-id = "TCHP";
+ label = "Charge Regulator Temperature";
+ };
+ temperature-TW0P {
+ apple,key-id = "TW0P";
+ label = "WiFi/BT Module Temperature";
+ };
+ voltage-SBAV {
+ apple,key-id = "SBAV";
+ label = "Battery Voltage";
+ };
+ voltage-VD0R {
+ apple,key-id = "VD0R";
+ label = "Charger Input Voltage";
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/hwmon-mac-mini.dtsi b/arch/arm64/boot/dts/apple/hwmon-mac-mini.dtsi
new file mode 100644
index 000000000000..f32627336ae7
--- /dev/null
+++ b/arch/arm64/boot/dts/apple/hwmon-mac-mini.dtsi
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * hwmon sensors expected on all Mac mini models
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include "hwmon-fan.dtsi"
+
+&smc_hwmon {
+ temperature-TW0P {
+ apple,key-id = "TW0P";
+ label = "WiFi/BT Module Temperature";
+ };
+};
diff --git a/arch/arm64/boot/dts/apple/t6001-j375c.dts b/arch/arm64/boot/dts/apple/t6001-j375c.dts
index 2e7c23714d4d..08276114c1d8 100644
--- a/arch/arm64/boot/dts/apple/t6001-j375c.dts
+++ b/arch/arm64/boot/dts/apple/t6001-j375c.dts
@@ -24,3 +24,5 @@ &wifi0 {
&bluetooth0 {
brcm,board-type = "apple,okinawa";
};
+
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi
index ffbe823b71bc..264df90f07d8 100644
--- a/arch/arm64/boot/dts/apple/t6001.dtsi
+++ b/arch/arm64/boot/dts/apple/t6001.dtsi
@@ -66,3 +66,5 @@ p-core-pmu-affinity {
&gpu {
compatible = "apple,agx-g13c", "apple,agx-g13s";
};
+
+#include "hwmon-common.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t6002-j375d.dts b/arch/arm64/boot/dts/apple/t6002-j375d.dts
index 2b7f80119618..d12c0ae418f7 100644
--- a/arch/arm64/boot/dts/apple/t6002-j375d.dts
+++ b/arch/arm64/boot/dts/apple/t6002-j375d.dts
@@ -56,3 +56,5 @@ &bluetooth0 {
/delete-node/ &ps_disp0_cpu0_die1;
/delete-node/ &ps_disp0_fe_die1;
+
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
index f715b19efd16..e6647c1a9173 100644
--- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
@@ -37,6 +37,10 @@ smc_gpio: gpio {
#gpio-cells = <2>;
};
+ smc_hwmon: hwmon {
+ compatible = "apple,smc-hwmon";
+ };
+
smc_reboot: reboot {
compatible = "apple,smc-reboot";
nvmem-cells = <&shutdown_flag>, <&boot_stage>,
diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
index c0aac59a6fae..127814a9dfa4 100644
--- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
+++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
@@ -131,3 +131,6 @@ &fpwm0 {
};
#include "spi1-nvram.dtsi"
+
+#include "hwmon-laptop.dtsi"
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
index 8622ddea7b44..680c103c1c0f 100644
--- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi
+++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi
@@ -114,6 +114,10 @@ smc_gpio: gpio {
#gpio-cells = <2>;
};
+ smc_hwmon: hwmon {
+ compatible = "apple,smc-hwmon";
+ };
+
smc_reboot: reboot {
compatible = "apple,smc-reboot";
nvmem-cells = <&shutdown_flag>, <&boot_stage>,
diff --git a/arch/arm64/boot/dts/apple/t8103-j274.dts b/arch/arm64/boot/dts/apple/t8103-j274.dts
index 1c3e37f86d46..f5b8cc087882 100644
--- a/arch/arm64/boot/dts/apple/t8103-j274.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j274.dts
@@ -61,3 +61,5 @@ &pcie0_dart_2 {
&i2c2 {
status = "okay";
};
+
+#include "hwmon-mac-mini.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts
index 5b3c42e9f0e6..abb88391635f 100644
--- a/arch/arm64/boot/dts/apple/t8103-j293.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j293.dts
@@ -119,3 +119,6 @@ dfr_panel_in: endpoint {
&displaydfr_dart {
status = "okay";
};
+
+#include "hwmon-laptop.dtsi"
+#include "hwmon-fan.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts
index 97a4344d8dca..491ead016b21 100644
--- a/arch/arm64/boot/dts/apple/t8103-j313.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j313.dts
@@ -41,3 +41,5 @@ &wifi0 {
&fpwm1 {
status = "okay";
};
+
+#include "hwmon-laptop.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j456.dts b/arch/arm64/boot/dts/apple/t8103-j456.dts
index 58c8e43789b4..c2ec6fbb633c 100644
--- a/arch/arm64/boot/dts/apple/t8103-j456.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j456.dts
@@ -75,3 +75,5 @@ &pcie0_dart_1 {
&pcie0_dart_2 {
status = "okay";
};
+
+#include "hwmon-fan-dual.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103-j457.dts b/arch/arm64/boot/dts/apple/t8103-j457.dts
index 7089ccf3ce55..aeaab2482d54 100644
--- a/arch/arm64/boot/dts/apple/t8103-j457.dts
+++ b/arch/arm64/boot/dts/apple/t8103-j457.dts
@@ -56,3 +56,5 @@ ethernet0: ethernet@0,0 {
&pcie0_dart_2 {
status = "okay";
};
+
+#include "hwmon-fan.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
index 59f2678639cf..f1820bdc0910 100644
--- a/arch/arm64/boot/dts/apple/t8103.dtsi
+++ b/arch/arm64/boot/dts/apple/t8103.dtsi
@@ -909,6 +909,10 @@ smc_gpio: gpio {
#gpio-cells = <2>;
};
+ smc_hwmon: hwmon {
+ compatible = "apple,smc-hwmon";
+ };
+
smc_reboot: reboot {
compatible = "apple,smc-reboot";
nvmem-cells = <&shutdown_flag>, <&boot_stage>,
@@ -1141,3 +1145,4 @@ port02: pci@2,0 {
};
#include "t8103-pmgr.dtsi"
+#include "hwmon-common.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts
index 6f69658623bf..500dcdf2d4b5 100644
--- a/arch/arm64/boot/dts/apple/t8112-j413.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j413.dts
@@ -78,3 +78,5 @@ &i2c4 {
&fpwm1 {
status = "okay";
};
+
+#include "hwmon-laptop.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112-j473.dts b/arch/arm64/boot/dts/apple/t8112-j473.dts
index 06fe257f08be..11db6a92493f 100644
--- a/arch/arm64/boot/dts/apple/t8112-j473.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j473.dts
@@ -52,3 +52,5 @@ &pcie1_dart {
&pcie2_dart {
status = "okay";
};
+
+#include "hwmon-mac-mini.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts
index fb8ad7d4c65a..a0da02c00f15 100644
--- a/arch/arm64/boot/dts/apple/t8112-j493.dts
+++ b/arch/arm64/boot/dts/apple/t8112-j493.dts
@@ -133,3 +133,6 @@ touchbar0: touchbar@0 {
touchscreen-inverted-y;
};
};
+
+#include "hwmon-laptop.dtsi"
+#include "hwmon-fan.dtsi"
diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
index 6bc3f58b06f7..c4d1e5ffaee9 100644
--- a/arch/arm64/boot/dts/apple/t8112.dtsi
+++ b/arch/arm64/boot/dts/apple/t8112.dtsi
@@ -912,6 +912,10 @@ smc_gpio: gpio {
#gpio-cells = <2>;
};
+ smc_hwmon: hwmon {
+ compatible = "apple,smc-hwmon";
+ };
+
smc_reboot: reboot {
compatible = "apple,smc-reboot";
nvmem-cells = <&shutdown_flag>, <&boot_stage>,
@@ -1180,3 +1184,4 @@ port03: pci@3,0 {
};
#include "t8112-pmgr.dtsi"
+#include "hwmon-common.dtsi"
--
2.52.0
^ permalink raw reply related
* Re: usb hid descriptor requirements are rejecting hardware (ZWO EFWmini, 03c3:1f01)
From: Benjamin Tissoires @ 2025-12-15 10:11 UTC (permalink / raw)
To: Salvatore Bonaccorso
Cc: Sam Halliday, 1122193, Jiri Kosina, linux-usb, linux-input,
linux-kernel
In-Reply-To: <aT7TPAInuBOXctEZ@eldamar.lan>
On Dec 14 2025, Salvatore Bonaccorso wrote:
> Hi Sam,
>
> Jiri, Benjamin, this is about a report originally done in Debian as
> https://bugs.debian.org/1122193 where Sam's device, a ZWO EFWmini with
> vendor and product id's as 03c3:1f01 is not working, usbhid not
> loaded.
>
> On Mon, Dec 08, 2025 at 03:03:49PM +0000, Sam Halliday wrote:
> > Package: linux-image-amd64
> > Version: 6.12.57-1
> > Severity: normal
> > Tags: patch
> > X-Debbugs-Cc: debian-amd64@lists.debian.org
> > User: debian-amd64@lists.debian.org
> > Usertags: amd64
> >
> > Dear Maintainer,
> >
> > I propose a patch to workaround USB HID descriptor requirements that
> > are stopping users from being able to use astrophotography
> > equipment.
> >
> > I have a usb device (an ZWO EFWmini, used for astronomy) which has
> > the following vendor information: 03c3:1f01 ZWO ZWO EFW
> >
> > This device is known to offer a suboptimal descriptor, e.g. see the lsusb output
> >
> > Warning: Descriptor too short
> > HID Device Descriptor:
> > bLength 9
> > bDescriptorType 33
> > bcdHID 1.01
> > bCountryCode 0 Not supported
> > bNumDescriptors 2
> > bDescriptorType 34 (null)
> > wDescriptorLength 68
> > bDescriptorType 0 (null)
> > wDescriptorLength 0
> > Report Descriptors:
> > ** UNAVAILABLE **
> >
> > My software (I write it, it is GPLv3, I'm the only user, but it isn't particularly relevant...) runs primarilly on a raspberry pi, which accepts this with kernel 6.12.25-1+rpt1, and I've also done some desktop development on archlinux (unknown kernel versions but up to at least 6 months ago). I only access the hardware for development from a debian desktop computer.
> >
> > Since moving to Debian 13, my hardware no longer works, with dmesg showing the following error:
> >
> > [ 14.182522] usb 1-2.2: new full-speed USB device number 10 using xhci_hcd
> > [ 14.276921] usb 1-2.2: New USB device found, idVendor=03c3, idProduct=1f01, bcdDevice= 0.00
> > [ 14.276930] usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
> > [ 14.276933] usb 1-2.2: Product: ZWO EFW
> > [ 14.276935] usb 1-2.2: Manufacturer: ZW0
> > [ 14.282951] usbhid 1-2.2:1.0: can't add hid device: -22
> > [ 14.282963] usbhid 1-2.2:1.0: probe with driver usbhid failed with error -22
> >
> > I have tried going back as far as debian's kernel from bullseye (5.10), bookworm (6.1), trixie (6.12) and backports (6.17) but it's the same error every time.
> >
> > Communicating with the ZWO (the device manufacturer) support team, they recommended patching the kernel, which I did, and it now works.
> >
> > I applied the following patch and built my own kernel
> >
> > ===========================================================================
> > --- drivers/hid/usbhid/hid-core.c.orig 2025-12-08 13:15:08.657917762 +0000
> > +++ drivers/hid/usbhid/hid-core.c 2025-12-08 13:16:24.293959487 +0000
> > @@ -1015,7 +1015,7 @@
> > (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
> > dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
> > hdesc->bLength, hdesc->bNumDescriptors);
> > - return -EINVAL;
> > + // return -EINVAL;
That looks like the wrong thing to do, especialy because the 2 previous
commits introducing that check are to protect against out of bound
errors:
See fe7f7ac8e0c7 ("HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()")
Can we get the debug output from the line above (or just add plain
printks in the running kernel)? I suspect we might losen the test with a
'<' instead of an '!='.
> > }
> >
> > hid->version = le16_to_cpu(hdesc->bcdHID);
> > ===========================================================================
> >
> > The new dmesg output is
> >
> > [ 366.477628] usbhid 1-2:1.0: 1 unsupported optional hid class descriptors
> > [ 366.478327] hid-generic 0003:03C3:1F01.0006: hiddev1,hidraw4: USB HID v1.01 Device [ZW0 ZWO EFW] on usb-000
> >
> >
> > Apologies but I don't think I'm giving you a particularly good patch
> > because the author of this code clearly intended for a -EINVAL
> > failure. A kernel dev may prefer to create a hardware quirk (which
> > ideally should be enabled for 03c3:1f01 by default) to exit if the
> > descriptor isn't valid. I'm not a kernel developer so that's beyond
> > me.
> >
> > The device works perfectly fine despite the descriptor not meeting
> > the kernel's current requirements. And I don't believe a firmware
> > upgrade is possible... it's just a little motor that turns a wheel
> > containing photographic filters.
>
> I suspect your case can be a candidate for HID-BPF, cf.
> https://docs.kernel.org/hid/hid-bpf.html and you might try to fixup
> the required descriptors.
Unfortunatelly no. HID-BPF works for fixing HID protocol errors, but in
this case the device is not presented by the transport layer, so we can
not do anything there :(
>
> But I'm not entirely sure. Jiri and Benjamin is that something we
> could have quirk for the device or the problem tackled in some other
> way?
Quirking seems the wrong approach. I would be curious to know the length
of the binary descriptor. I suspect there is some mismatch and the end
is filled with 0. If the length is shorter, that's going to be a bigger
problem to solve.
Cheers,
Benjamin
>
> Regards,
> Salvatore
^ permalink raw reply
* Re: [PATCH v6 1/7] dt-bindings: hwmon: Add Apple System Management Controller hwmon schema
From: Rob Herring (Arm) @ 2025-12-15 10:36 UTC (permalink / raw)
To: James Calligeros
Cc: Dmitry Torokhov, Jonathan Corbet, linux-hwmon, Conor Dooley,
Sven Peter, Alyssa Rosenzweig, asahi, Lee Jones, linux-input,
linux-kernel, Jean Delvare, linux-arm-kernel, Alexandre Belloni,
Guenter Roeck, linux-rtc, devicetree, linux-doc, Janne Grunau,
Neal Gompa, Krzysztof Kozlowski
In-Reply-To: <20251215-macsmc-subdevs-v6-1-0518cb5f28ae@gmail.com>
On Mon, 15 Dec 2025 19:37:45 +1000, James Calligeros wrote:
> Apple Silicon devices integrate a vast array of sensors, monitoring
> current, power, temperature, and voltage across almost every part of
> the system. The sensors themselves are all connected to the System
> Management Controller (SMC). The SMC firmware exposes the data
> reported by these sensors via its standard FourCC-based key-value
> API. The SMC is also responsible for monitoring and controlling any
> fans connected to the system, exposing them in the same way.
>
> For reasons known only to Apple, each device exposes its sensors with
> an almost totally unique set of keys. This is true even for devices
> which share an SoC. An M1 Mac mini, for example, will report its core
> temperatures on different keys to an M1 MacBook Pro. Worse still, the
> SMC does not provide a way to enumerate the available keys at runtime,
> nor do the keys follow any sort of reasonable or consistent naming
> rules that could be used to deduce their purpose. We must therefore
> know which keys are present on any given device, and which function
> they serve, ahead of time.
>
> Add a schema so that we can describe the available sensors for a given
> Apple Silicon device in the Devicetree.
>
> Reviewed-by: Neal Gompa <neal@gompa.dev>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
> ---
> .../bindings/hwmon/apple,smc-hwmon.yaml | 86 +++++++++++++++++++++++++
> .../bindings/mfd/apple,smc.yaml | 36 +++++++++++
> MAINTAINERS | 1 +
> 3 files changed, 123 insertions(+)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
./Documentation/devicetree/bindings/hwmon/apple,smc-hwmon.yaml:73:1: [warning] too many blank lines (2 > 1) (empty-lines)
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20251215-macsmc-subdevs-v6-1-0518cb5f28ae@gmail.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply
* Re: [PATCH 2/4] Input: adc-keys - support types that aren't just keyboard keys
From: Nicolas Frattaroli @ 2025-12-15 11:10 UTC (permalink / raw)
To: Dragan Simic
Cc: alexandre.belloni, conor+dt, devicetree, dmitry.torokhov, heiko,
kernel, krzk+dt, linux-arm-kernel, linux-input, linux-kernel,
linux-rockchip, robh
In-Reply-To: <20251028213209.2646838-1-dsimic@manjaro.org>
On Tuesday, 28 October 2025 22:32:09 Central European Standard Time Dragan Simic wrote:
> Hello Nicolas,
>
> On Monday, June 30, 2025, 12:19:24 Nicolas Frattaroli wrote:
> > Instead of doing something like what gpio-keys is doing, adc-keys
> > hardcodes that all keycodes must be of type EV_KEY.
> >
> > This limits the usefulness of adc-keys, and overcomplicates the code
> > with manual bit-setting logic.
> >
> > Instead, refactor the code to read the linux,input-type fwnode property,
> > and get rid of the custom bit setting logic, replacing it with
> > input_set_capability instead. input_report_key is replaced with
> > input_event, which allows us to explicitly pass the type.
>
> Thanks for this patch, it's indeed very useful! Please see some
> comments below.
>
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > ---
> > drivers/input/keyboard/adc-keys.c | 16 ++++++++++++----
> > 1 file changed, 12 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
> > index f1753207429db02ce6510e5ec0da9b24d9edb61d..339dd4d4a0842108da2c6136b1e0098cd1f6a3cd 100644
> > --- a/drivers/input/keyboard/adc-keys.c
> > +++ b/drivers/input/keyboard/adc-keys.c
> > @@ -19,12 +19,14 @@
> > struct adc_keys_button {
> > u32 voltage;
> > u32 keycode;
> > + u32 type;
> > };
> >
> > struct adc_keys_state {
> > struct iio_channel *channel;
> > u32 num_keys;
> > u32 last_key;
> > + u32 last_type;
> > u32 keyup_voltage;
> > const struct adc_keys_button *map;
> > };
> > @@ -35,6 +37,7 @@ static void adc_keys_poll(struct input_dev *input)
> > int i, value, ret;
> > u32 diff, closest = 0xffffffff;
> > int keycode = 0;
> > + u32 type = EV_KEY;
> >
> > ret = iio_read_channel_processed(st->channel, &value);
> > if (unlikely(ret < 0)) {
> > @@ -46,6 +49,7 @@ static void adc_keys_poll(struct input_dev *input)
> > if (diff < closest) {
> > closest = diff;
> > keycode = st->map[i].keycode;
> > + type = st->map[i].type;
> > }
> > }
> > }
> > @@ -54,13 +58,14 @@ static void adc_keys_poll(struct input_dev *input)
> > keycode = 0;
> >
> > if (st->last_key && st->last_key != keycode)
> > - input_report_key(input, st->last_key, 0);
> > + input_event(input, st->last_type, st->last_key, 0);
> >
> > if (keycode)
> > - input_report_key(input, keycode, 1);
> > + input_event(input, type, keycode, 1);
>
> When EV_ABS is defined in the DT as the key type, which happens with
> joysticks and whatnot, separate handling is needed, by requiring the
> actual associated button values to be reported in the input_event()
> invocations, more specifically on the keypresses only.
Analogue control devices like joysticks are handled in adc-joystick.c.
adc-keys is specifically for resistor-ladder key devices. A driver or
binding for some absolute/relative positioning device that is not a
joystick should get its own binding first. Overloading the meaning
of the adc-keys binding and then adding functionality to the driver
is not the way to go.
I'll instead add code to only allow EV_KEY and EV_SW. Switches
function like keys for all intents and purposes, so they fit here.
>
> That's also visible in the gpio_keys_gpio_report_event() function in
> drivers/input/keyboard/gpio_keys.c.
>
> > input_sync(input);
> > st->last_key = keycode;
> > + st->last_type = type;
> > }
> >
> > static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
> > @@ -93,6 +98,10 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
> > return -EINVAL;
> > }
> >
> > + if (fwnode_property_read_u32(child, "linux,input-type",
> > + &map[i].type))
> > + map[i].type = EV_KEY;
>
> Going along with the remarks above, it will also be needed to read
> and record the values of "linux,input-value" DT properties here, and
> to extend the associated binding to define their presence.
>
> > i++;
> > }
> >
> > @@ -156,9 +165,8 @@ static int adc_keys_probe(struct platform_device *pdev)
> > input->id.product = 0x0001;
> > input->id.version = 0x0100;
> >
> > - __set_bit(EV_KEY, input->evbit);
> > for (i = 0; i < st->num_keys; i++)
> > - __set_bit(st->map[i].keycode, input->keybit);
> > + input_set_capability(input, st->map[i].type, st->map[i].keycode);
> >
> > if (device_property_read_bool(dev, "autorepeat"))
> > __set_bit(EV_REP, input->evbit);
>
^ permalink raw reply
* Re: usb hid descriptor requirements are rejecting hardware (ZWO EFWmini, 03c3:1f01)
From: Benjamin Tissoires @ 2025-12-15 12:25 UTC (permalink / raw)
To: Sam Halliday
Cc: Salvatore Bonaccorso, 1122193, Jiri Kosina, linux-usb,
linux-input, linux-kernel
In-Reply-To: <cpgdwmdhfl7tkqe2x263o2xeeclgvbal5onlkj7qcte73jhs5i@h2tdtzmiabcn>
On Dec 15, 2025, Sam Halliday wrote:
> Hi Ben,
>
> In answer to your logging request, this is the output after running
>
> echo 'file drivers/hid/usbhid/hid-core.c +p' | sudo tee /sys/kernel/debug/dynamic_debug/control
>
> and plugging in the device (with the debian kernel, not my patched one)
>
> [ 371.897694] usb 1-2: new full-speed USB device number 8 using xhci_hcd
> [ 372.036133] usb 1-2: New USB device found, idVendor=03c3, idProduct=1f01, bcdDevice= 0.00
> [ 372.036145] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
> [ 372.036149] usb 1-2: Product: ZWO EFW
> [ 372.036152] usb 1-2: Manufacturer: ZW0
> [ 372.043375] drivers/hid/usbhid/hid-core.c: HID probe called for ifnum 0
> [ 372.043404] drivers/hid/usbhid/hid-core.c: hid descriptor invalid, bLen=9 bNum=2
Looks like the length is shorter than expected. However, after looking
more carefully into the code, it seems we can bypass the check as long
as the provided length is greater than sizeof(*hdesc), because later in
the code we simply ignore any optional HID class descriptors.
Would you mind testing the following patch?:
---
From 07020d68764a29a9e5d4e95be1820e0c75a4216a Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <bentiss@kernel.org>
Date: Mon, 15 Dec 2025 12:57:21 +0100
Subject: [PATCH] HID: usbhid: paper over wrong bNumDescriptor field
Some faulty devices (ZWO EFWmini) have a wrong optional HID class
descriptor count compared to the provided length.
Given that we plainly ignore those optional descriptor, we can attempt
to fix the provided number so we do not lock out those devices.
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
drivers/hid/usbhid/hid-core.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index aac0051a2cf6..758eb21430cd 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -985,6 +985,7 @@ static int usbhid_parse(struct hid_device *hid)
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_descriptor *hdesc;
struct hid_class_descriptor *hcdesc;
+ __u8 fixed_opt_descriptors_size;
u32 quirks = 0;
unsigned int rsize = 0;
char *rdesc;
@@ -1015,7 +1016,21 @@ static int usbhid_parse(struct hid_device *hid)
(hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
hdesc->bLength, hdesc->bNumDescriptors);
- return -EINVAL;
+
+ /*
+ * Some devices may expose a wrong number of descriptors compared
+ * to the provided length.
+ * However, we ignore the optional hid class descriptors entirely
+ * so we can safely recompute the proper field.
+ */
+ if (hdesc->bLength >= sizeof(*hdesc)) {
+ fixed_opt_descriptors_size = hdesc->bLength - sizeof(*hdesc);
+
+ hid_warn(intf, "fixing wrong optional hid class descriptors count\n");
+ hdesc->bNumDescriptors = fixed_opt_descriptors_size / sizeof(*hcdesc) + 1;
+ } else {
+ return -EINVAL;
+ }
}
hid->version = le16_to_cpu(hdesc->bcdHID);
--
2.51.1
---
Cheers,
Benjamin
> [ 372.043409] usbhid 1-2:1.0: can't add hid device: -22
> [ 372.043422] usbhid 1-2:1.0: probe with driver usbhid failed with error -22
>
> Also here is a more detailed lsusb output
>
>
> Bus 001 Device 008: ID 03c3:1f01 ZWO ZWO EFW
> Negotiated speed: Full Speed (12Mbps)
> Device Descriptor:
> bLength 18
> bDescriptorType 1
> bcdUSB 1.10
> bDeviceClass 0 [unknown]
> bDeviceSubClass 0 [unknown]
> bDeviceProtocol 0
> bMaxPacketSize0 16
> idVendor 0x03c3 ZWO
> idProduct 0x1f01 ZWO EFW
> bcdDevice 0.00
> iManufacturer 1 ZW0
> iProduct 2 ZWO EFW
> iSerial 0
> bNumConfigurations 1
> Configuration Descriptor:
> bLength 9
> bDescriptorType 2
> wTotalLength 0x0029
> bNumInterfaces 1
> bConfigurationValue 1
> iConfiguration 0
> bmAttributes 0x80
> (Bus Powered)
> MaxPower 64mA
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 0
> bAlternateSetting 0
> bNumEndpoints 2
> bInterfaceClass 3 Human Interface Device
> bInterfaceSubClass 0 [unknown]
> bInterfaceProtocol 0
> iInterface 0
> Warning: Descriptor too short
> HID Device Descriptor:
> bLength 9
> bDescriptorType 33
> bcdHID 1.01
> bCountryCode 0 Not supported
> bNumDescriptors 2
> bDescriptorType 34 (null)
> wDescriptorLength 68
> bDescriptorType 0 (null)
> wDescriptorLength 0
> Report Descriptor: (length is 68)
> Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
> (null)
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x01 ] 1
> Application
> Item(Global): (null), data= [ 0x01 ] 1
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Global): (null), data= [ 0x02 ] 2
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Global): (null), data= [ 0x03 ] 3
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Global): (null), data= [ 0x04 ] 4
> Item(Global): (null), data= [ 0x0f ] 15
> Item(Global): (null), data= [ 0x08 ] 8
> Item(Global): (null), data= [ 0xff 0x00 ] 255
> Item(Global): (null), data= [ 0x00 ] 0
> Item(Local ): (null), data= [ 0x01 ] 1
> (null)
> Item(Main ): (null), data= [ 0x02 ] 2
> Data Variable Absolute No_Wrap Linear
> Preferred_State No_Null_Position Non_Volatile Bitfield
> Item(Main ): (null), data=none
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x81 EP 1 IN
> bmAttributes 3
> Transfer Type Interrupt
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0010 1x 16 bytes
> bInterval 10
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x01 EP 1 OUT
> bmAttributes 3
> Transfer Type Interrupt
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0010 1x 16 bytes
> bInterval 10
> Device Status: 0x0000
>
>
> (Bus Powered)> On Dec 15 2025, Benjamin Tissoires wrote:
> > On Dec 14 2025, Salvatore Bonaccorso wrote:
> > > Hi Sam,
> > >
> > > Jiri, Benjamin, this is about a report originally done in Debian as
> > > https://bugs.debian.org/1122193 where Sam's device, a ZWO EFWmini with
> > > vendor and product id's as 03c3:1f01 is not working, usbhid not
> > > loaded.
> > >
> > > On Mon, Dec 08, 2025 at 03:03:49PM +0000, Sam Halliday wrote:
> > > > Package: linux-image-amd64
> > > > Version: 6.12.57-1
> > > > Severity: normal
> > > > Tags: patch
> > > > X-Debbugs-Cc: debian-amd64@lists.debian.org
> > > > User: debian-amd64@lists.debian.org
> > > > Usertags: amd64
> > > >
> > > > Dear Maintainer,
> > > >
> > > > I propose a patch to workaround USB HID descriptor requirements that
> > > > are stopping users from being able to use astrophotography
> > > > equipment.
> > > >
> > > > I have a usb device (an ZWO EFWmini, used for astronomy) which has
> > > > the following vendor information: 03c3:1f01 ZWO ZWO EFW
> > > >
> > > > This device is known to offer a suboptimal descriptor, e.g. see the lsusb output
> > > >
> > > > Warning: Descriptor too short
> > > > HID Device Descriptor:
> > > > bLength 9
> > > > bDescriptorType 33
> > > > bcdHID 1.01
> > > > bCountryCode 0 Not supported
> > > > bNumDescriptors 2
> > > > bDescriptorType 34 (null)
> > > > wDescriptorLength 68
> > > > bDescriptorType 0 (null)
> > > > wDescriptorLength 0
> > > > Report Descriptors:
> > > > ** UNAVAILABLE **
> > > >
> > > > My software (I write it, it is GPLv3, I'm the only user, but it isn't particularly relevant...) runs primarilly on a raspberry pi, which accepts this with kernel 6.12.25-1+rpt1, and I've also done some desktop development on archlinux (unknown kernel versions but up to at least 6 months ago). I only access the hardware for development from a debian desktop computer.
> > > >
> > > > Since moving to Debian 13, my hardware no longer works, with dmesg showing the following error:
> > > >
> > > > [ 14.182522] usb 1-2.2: new full-speed USB device number 10 using xhci_hcd
> > > > [ 14.276921] usb 1-2.2: New USB device found, idVendor=03c3, idProduct=1f01, bcdDevice= 0.00
> > > > [ 14.276930] usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
> > > > [ 14.276933] usb 1-2.2: Product: ZWO EFW
> > > > [ 14.276935] usb 1-2.2: Manufacturer: ZW0
> > > > [ 14.282951] usbhid 1-2.2:1.0: can't add hid device: -22
> > > > [ 14.282963] usbhid 1-2.2:1.0: probe with driver usbhid failed with error -22
> > > >
> > > > I have tried going back as far as debian's kernel from bullseye (5.10), bookworm (6.1), trixie (6.12) and backports (6.17) but it's the same error every time.
> > > >
> > > > Communicating with the ZWO (the device manufacturer) support team, they recommended patching the kernel, which I did, and it now works.
> > > >
> > > > I applied the following patch and built my own kernel
> > > >
> > > > ===========================================================================
> > > > --- drivers/hid/usbhid/hid-core.c.orig 2025-12-08 13:15:08.657917762 +0000
> > > > +++ drivers/hid/usbhid/hid-core.c 2025-12-08 13:16:24.293959487 +0000
> > > > @@ -1015,7 +1015,7 @@
> > > > (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
> > > > dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
> > > > hdesc->bLength, hdesc->bNumDescriptors);
> > > > - return -EINVAL;
> > > > + // return -EINVAL;
> >
> > That looks like the wrong thing to do, especialy because the 2 previous
> > commits introducing that check are to protect against out of bound
> > errors:
> > See fe7f7ac8e0c7 ("HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()")
> >
> > Can we get the debug output from the line above (or just add plain
> > printks in the running kernel)? I suspect we might losen the test with a
> > '<' instead of an '!='.
> >
> > > > }
> > > >
> > > > hid->version = le16_to_cpu(hdesc->bcdHID);
> > > > ===========================================================================
> > > >
> > > > The new dmesg output is
> > > >
> > > > [ 366.477628] usbhid 1-2:1.0: 1 unsupported optional hid class descriptors
> > > > [ 366.478327] hid-generic 0003:03C3:1F01.0006: hiddev1,hidraw4: USB HID v1.01 Device [ZW0 ZWO EFW] on usb-000
> > > >
> > > >
> > > > Apologies but I don't think I'm giving you a particularly good patch
> > > > because the author of this code clearly intended for a -EINVAL
> > > > failure. A kernel dev may prefer to create a hardware quirk (which
> > > > ideally should be enabled for 03c3:1f01 by default) to exit if the
> > > > descriptor isn't valid. I'm not a kernel developer so that's beyond
> > > > me.
> > > >
> > > > The device works perfectly fine despite the descriptor not meeting
> > > > the kernel's current requirements. And I don't believe a firmware
> > > > upgrade is possible... it's just a little motor that turns a wheel
> > > > containing photographic filters.
> > >
> > > I suspect your case can be a candidate for HID-BPF, cf.
> > > https://docs.kernel.org/hid/hid-bpf.html and you might try to fixup
> > > the required descriptors.
> >
> > Unfortunatelly no. HID-BPF works for fixing HID protocol errors, but in
> > this case the device is not presented by the transport layer, so we can
> > not do anything there :(
> >
> > >
> > > But I'm not entirely sure. Jiri and Benjamin is that something we
> > > could have quirk for the device or the problem tackled in some other
> > > way?
> >
> > Quirking seems the wrong approach. I would be curious to know the length
> > of the binary descriptor. I suspect there is some mismatch and the end
> > is filled with 0. If the length is shorter, that's going to be a bigger
> > problem to solve.
> >
> > Cheers,
> > Benjamin
> >
> > >
> > > Regards,
> > > Salvatore
^ permalink raw reply related
* [PATCH v2 0/4] ROCK 4D audio enablement
From: Nicolas Frattaroli @ 2025-12-15 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Heiko Stuebner
Cc: kernel, linux-input, devicetree, linux-kernel, linux-arm-kernel,
linux-rockchip, Nicolas Frattaroli, Cristian Ciocaltea
The ROCK 4D uses an ADC input to distinguish between a headphone (i.e.,
no mic) and a headset (i.e., with mic). After some searching, it appears
that the closest we can get to modelling this is by sending a particular
switch input event.
So this series modifies the adc-keys bindings, extends the adc-keys
driver to allow sending other input types as well, and then adds the
analog audio nodes to ROCK 4D's device tree.
It should be noted that analog capture from the TRRS jack currently
results in completely digitally silent audio for me, i.e. no data other
than 0xFF. There's a few reasons why this could happen, chief among them
that my SAI driver is broken or that the ES8328 codec driver is once
again broken. The DAPM routes when graphed out look fine though. So the
DTS part is correct, and I can fix the broken capture in a separate
follow-up patch that doesn't have to include DT people.
Another possibility is that my phone headset, despite being 4 rings and
having a little pin hole at the back of the volume doodad, does not
actually have a microphone, but in that case I'd still expect some noise
in the PCM. Maybe it's just shy.
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
Changes in v2:
- Drop HDMI audio patch, as it was already merged.
- adc-keys: rename "keycode" to "code".
- adc-keys: make the keycode (now "code") local a u32 instead of an int
- adc-keys: only allow EV_KEY and EV_SW for now. Rename patch
accordingly.
- adc-keys: Add another patch to rework probe function error logging.
- Link to v1: https://lore.kernel.org/r/20250630-rock4d-audio-v1-0-0b3c8e8fda9c@collabora.com
---
Nicolas Frattaroli (4):
dt-bindings: input: adc-keys: allow linux,input-type property
Input: adc-keys - support EV_SW as well, not just EV_KEY.
Input: adc-keys - Use dev_err_probe in probe function
arm64: dts: rockchip: add analog audio to ROCK 4D
.../devicetree/bindings/input/adc-keys.yaml | 3 +
arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts | 90 ++++++++++++++++++++++
drivers/input/keyboard/adc-keys.c | 88 ++++++++++-----------
3 files changed, 138 insertions(+), 43 deletions(-)
---
base-commit: 3e7f562e20ee87a25e104ef4fce557d39d62fa85
change-id: 20250627-rock4d-audio-cfc07f168a08
Best regards,
--
Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
^ permalink raw reply
* [PATCH v2 2/4] Input: adc-keys - support EV_SW as well, not just EV_KEY.
From: Nicolas Frattaroli @ 2025-12-15 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Heiko Stuebner
Cc: kernel, linux-input, devicetree, linux-kernel, linux-arm-kernel,
linux-rockchip, Nicolas Frattaroli
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
Instead of doing something like what gpio-keys is doing, adc-keys
hardcodes that all keycodes must be of type EV_KEY.
This limits the usefulness of adc-keys, and overcomplicates the code
with manual bit-setting logic.
Instead, refactor the code to read the linux,input-type fwnode property,
and get rid of the custom bit setting logic, replacing it with
input_set_capability instead. input_report_key is replaced with
input_event, which allows us to explicitly pass the type.
Only EV_KEY and EV_SW is allowed at this stage.
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/input/keyboard/adc-keys.c | 37 +++++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index f1753207429d..62376f34f7d0 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -18,13 +18,15 @@
struct adc_keys_button {
u32 voltage;
- u32 keycode;
+ u32 code;
+ u32 type;
};
struct adc_keys_state {
struct iio_channel *channel;
u32 num_keys;
u32 last_key;
+ u32 last_type;
u32 keyup_voltage;
const struct adc_keys_button *map;
};
@@ -34,7 +36,8 @@ static void adc_keys_poll(struct input_dev *input)
struct adc_keys_state *st = input_get_drvdata(input);
int i, value, ret;
u32 diff, closest = 0xffffffff;
- int keycode = 0;
+ u32 code = 0;
+ u32 type = EV_KEY;
ret = iio_read_channel_processed(st->channel, &value);
if (unlikely(ret < 0)) {
@@ -45,22 +48,24 @@ static void adc_keys_poll(struct input_dev *input)
diff = abs(st->map[i].voltage - value);
if (diff < closest) {
closest = diff;
- keycode = st->map[i].keycode;
+ code = st->map[i].code;
+ type = st->map[i].type;
}
}
}
if (abs(st->keyup_voltage - value) < closest)
- keycode = 0;
+ code = 0;
- if (st->last_key && st->last_key != keycode)
- input_report_key(input, st->last_key, 0);
+ if (st->last_key && st->last_key != code)
+ input_event(input, st->last_type, st->last_key, 0);
- if (keycode)
- input_report_key(input, keycode, 1);
+ if (code)
+ input_event(input, type, code, 1);
input_sync(input);
- st->last_key = keycode;
+ st->last_key = code;
+ st->last_type = type;
}
static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
@@ -88,11 +93,20 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
map[i].voltage /= 1000;
if (fwnode_property_read_u32(child, "linux,code",
- &map[i].keycode)) {
+ &map[i].code)) {
dev_err(dev, "Key with invalid or missing linux,code\n");
return -EINVAL;
}
+ if (fwnode_property_read_u32(child, "linux,input-type",
+ &map[i].type))
+ map[i].type = EV_KEY;
+
+ if (map[i].type != EV_KEY && map[i].type != EV_SW)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid linux,input-type: 0x%x\n",
+ map[i].type);
+
i++;
}
@@ -156,9 +170,8 @@ static int adc_keys_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0100;
- __set_bit(EV_KEY, input->evbit);
for (i = 0; i < st->num_keys; i++)
- __set_bit(st->map[i].keycode, input->keybit);
+ input_set_capability(input, st->map[i].type, st->map[i].code);
if (device_property_read_bool(dev, "autorepeat"))
__set_bit(EV_REP, input->evbit);
--
2.52.0
^ permalink raw reply related
* [PATCH v2 1/4] dt-bindings: input: adc-keys: allow linux,input-type property
From: Nicolas Frattaroli @ 2025-12-15 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Heiko Stuebner
Cc: kernel, linux-input, devicetree, linux-kernel, linux-arm-kernel,
linux-rockchip, Nicolas Frattaroli
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
adc-keys, unlike gpio-keys, does not allow linux,input-type as a valid
property. This makes it impossible to model devices that have ADC inputs
that should generate switch events.
Add the property to the binding with the same default as gpio-keys.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
Documentation/devicetree/bindings/input/adc-keys.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/adc-keys.yaml b/Documentation/devicetree/bindings/input/adc-keys.yaml
index 7aa078dead37..e372ebc23d16 100644
--- a/Documentation/devicetree/bindings/input/adc-keys.yaml
+++ b/Documentation/devicetree/bindings/input/adc-keys.yaml
@@ -42,6 +42,9 @@ patternProperties:
linux,code: true
+ linux,input-type:
+ default: 1 # EV_KEY
+
press-threshold-microvolt:
description:
Voltage above or equal to which this key is considered pressed. No
--
2.52.0
^ permalink raw reply related
* [PATCH v2 3/4] Input: adc-keys - Use dev_err_probe in probe function
From: Nicolas Frattaroli @ 2025-12-15 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Heiko Stuebner
Cc: kernel, linux-input, devicetree, linux-kernel, linux-arm-kernel,
linux-rockchip, Nicolas Frattaroli
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
Rework the probe function, and functions called by the probe function,
to use dev_err_probe for error logging.
While at it, also do some minor style cleanups, like not error logging
on -ENOMEM and using ! instead of == 0.
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/input/keyboard/adc-keys.c | 53 ++++++++++++++++-----------------------
1 file changed, 21 insertions(+), 32 deletions(-)
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index 62376f34f7d0..6f2ddcecea99 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -74,10 +74,8 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
int i;
st->num_keys = device_get_child_node_count(dev);
- if (st->num_keys == 0) {
- dev_err(dev, "keymap is missing\n");
- return -EINVAL;
- }
+ if (!st->num_keys)
+ return dev_err_probe(dev, -EINVAL, "keymap is missing\n");
map = devm_kmalloc_array(dev, st->num_keys, sizeof(*map), GFP_KERNEL);
if (!map)
@@ -86,17 +84,16 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
i = 0;
device_for_each_child_node_scoped(dev, child) {
if (fwnode_property_read_u32(child, "press-threshold-microvolt",
- &map[i].voltage)) {
- dev_err(dev, "Key with invalid or missing voltage\n");
- return -EINVAL;
- }
+ &map[i].voltage))
+ return dev_err_probe(dev, -EINVAL,
+ "Key with invalid or missing voltage\n");
+
map[i].voltage /= 1000;
if (fwnode_property_read_u32(child, "linux,code",
- &map[i].code)) {
- dev_err(dev, "Key with invalid or missing linux,code\n");
- return -EINVAL;
- }
+ &map[i].code))
+ return dev_err_probe(dev, -EINVAL,
+ "Key with invalid or missing linux,code\n");
if (fwnode_property_read_u32(child, "linux,input-type",
&map[i].type))
@@ -129,7 +126,8 @@ static int adc_keys_probe(struct platform_device *pdev)
st->channel = devm_iio_channel_get(dev, "buttons");
if (IS_ERR(st->channel))
- return PTR_ERR(st->channel);
+ return dev_err_probe(dev, PTR_ERR(st->channel),
+ "Could not get iio channel\n");
if (!st->channel->indio_dev)
return -ENXIO;
@@ -138,16 +136,13 @@ static int adc_keys_probe(struct platform_device *pdev)
if (error < 0)
return error;
- if (type != IIO_VOLTAGE) {
- dev_err(dev, "Incompatible channel type %d\n", type);
- return -EINVAL;
- }
+ if (type != IIO_VOLTAGE)
+ return dev_err_probe(dev, -EINVAL, "Incompatible channel type %d\n", type);
if (device_property_read_u32(dev, "keyup-threshold-microvolt",
- &st->keyup_voltage)) {
- dev_err(dev, "Invalid or missing keyup voltage\n");
- return -EINVAL;
- }
+ &st->keyup_voltage))
+ return dev_err_probe(dev, -EINVAL, "Invalid or missing keyup voltage\n");
+
st->keyup_voltage /= 1000;
error = adc_keys_load_keymap(dev, st);
@@ -155,10 +150,8 @@ static int adc_keys_probe(struct platform_device *pdev)
return error;
input = devm_input_allocate_device(dev);
- if (!input) {
- dev_err(dev, "failed to allocate input device\n");
+ if (!input)
return -ENOMEM;
- }
input_set_drvdata(input, st);
@@ -178,19 +171,15 @@ static int adc_keys_probe(struct platform_device *pdev)
error = input_setup_polling(input, adc_keys_poll);
- if (error) {
- dev_err(dev, "Unable to set up polling: %d\n", error);
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "Unable to set up polling\n");
if (!device_property_read_u32(dev, "poll-interval", &value))
input_set_poll_interval(input, value);
error = input_register_device(input);
- if (error) {
- dev_err(dev, "Unable to register input device: %d\n", error);
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "Unable to register input device\n");
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v2 4/4] arm64: dts: rockchip: add analog audio to ROCK 4D
From: Nicolas Frattaroli @ 2025-12-15 12:29 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alexandre Belloni, Heiko Stuebner
Cc: kernel, linux-input, devicetree, linux-kernel, linux-arm-kernel,
linux-rockchip, Nicolas Frattaroli, Cristian Ciocaltea
In-Reply-To: <20251215-rock4d-audio-v2-0-82a61de39b4c@collabora.com>
The RADXA ROCK 4D, like many other Rockchip-based boards, uses an ES8388
analog audio codec. On the production version of the board, the codec's
LOUT1 and ROUT1 pins are tied to the headphone jack, whereas pins LOUT2
and ROUT2 lead to a non-populated speaker amplifier that itself leads to
a non-populated speaker jack. The schematic is still haunted by the
ghosts of those symbols, but it clearly marks them as "NC".
The 3.5mm TRRS jack has its microphone ring (and ground ring) wired to
the codec's LINPUT1 and RINPUT1 pins for differential signalling.
Furthermore, it uses the SoCs ADC to detect whether the inserted cable
is of headphones (i.e., no microphone), or a headset (i.e., with
microphone). The way this is done is that the ADC input taps the output
of a 100K/100K resistor divider that divides the microphone ring pin
that's pulled up to 3.3V.
There is no ADC level difference between a completely empty jack and one
with a set of headphones (i.e., ones that don't have a microphone)
connected. Consequently headphone insertion detection isn't something
that can be done.
Add the necessary codec and audio card nodes. The non-populated parts,
i.e. LOUT2 and ROUT2, are not modeled at all, as they are not present on
the hardware.
Also, add an adc-keys node for the headset detection, which uses an
input type of EV_SW with the SW_MICROPHONE_INSERT keycode. Below the
220mV pressed voltage level of our SW_MICROPHONE_INSERT switch, we also
define a button that emits a KEY_RESERVED code, which is there to model
this part of the voltage range as not just being extra legroom for the
button above it, but actually a state that is encountered in the real
world, and should be recognised as a valid state for the ADC range to be
in so that no "closer" ADC button is chosen.
Tested-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts | 90 +++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts b/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
index 7023dc326d0e..d86fe2951da6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3576-rock-4d.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/pwm/pwm.h>
@@ -37,6 +38,31 @@ hdmi_con_in: endpoint {
};
};
+ es8388_sound: es8388-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,name = "On-board Analog ES8388";
+ simple-audio-card,widgets = "Microphone", "Headphone Mic",
+ "Headphone", "Headphone";
+ simple-audio-card,routing = "Headphone", "LOUT1",
+ "Headphone", "ROUT1",
+ "Left PGA Mux", "Differential Mux",
+ "Differential Mux", "LINPUT1",
+ "Differential Mux", "RINPUT1",
+ "LINPUT1", "Headphone Mic",
+ "RINPUT1", "Headphone Mic";
+
+ simple-audio-card,cpu {
+ sound-dai = <&sai1>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&es8388>;
+ system-clock-frequency = <12288000>;
+ };
+ };
+
rfkill {
compatible = "rfkill-gpio";
pinctrl-names = "default";
@@ -65,6 +91,37 @@ user-led {
};
};
+ saradc_keys: adc-keys {
+ compatible = "adc-keys";
+ io-channels = <&saradc 3>;
+ io-channel-names = "buttons";
+ keyup-threshold-microvolt = <3000000>;
+ poll-interval = <100>;
+
+ /*
+ * During insertion and removal of a regular set of headphones,
+ * i.e. one without a microphone, the voltage level briefly
+ * dips below the 220mV of the headset connection switch.
+ * By having a button definition with a KEY_RESERVED signal
+ * between 0 to 220, we ensure no driver implementation thinks
+ * that the closest thing to 0V is 220mV so clearly there must
+ * be a headset connected.
+ */
+
+ button-headset-disconnected {
+ label = "Headset Microphone Disconnected";
+ linux,code = <KEY_RESERVED>;
+ press-threshold-microvolt = <0>;
+ };
+
+ button-headset-connected {
+ label = "Headset Microphone Connected";
+ linux,code = <SW_MICROPHONE_INSERT>;
+ linux,input-type = <EV_SW>;
+ press-threshold-microvolt = <220000>;
+ };
+ };
+
vcc_5v0_dcin: regulator-vcc-5v0-dcin {
compatible = "regulator-fixed";
regulator-always-on;
@@ -682,6 +739,25 @@ hym8563: rtc@51 {
};
};
+&i2c3 {
+ status = "okay";
+
+ es8388: audio-codec@10 {
+ compatible = "everest,es8388", "everest,es8328";
+ reg = <0x10>;
+ clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+ AVDD-supply = <&vcca_3v3_s0>;
+ DVDD-supply = <&vcc_3v3_s0>;
+ HPVDD-supply = <&vcca_3v3_s0>;
+ PVDD-supply = <&vcc_3v3_s0>;
+ assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+ assigned-clock-rates = <12288000>;
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sai1m0_mclk>;
+ };
+};
+
&mdio0 {
rgmii_phy0: ethernet-phy@1 {
compatible = "ethernet-phy-id001c.c916";
@@ -756,10 +832,24 @@ wifi_en_h: wifi-en-h {
};
};
+&sai1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sai1m0_lrck
+ &sai1m0_sclk
+ &sai1m0_sdi0
+ &sai1m0_sdo0>;
+ status = "okay";
+};
+
&sai6 {
status = "okay";
};
+&saradc {
+ vref-supply = <&vcca1v8_pldo2_s0>;
+ status = "okay";
+};
+
&sdmmc {
bus-width = <4>;
cap-mmc-highspeed;
--
2.52.0
^ permalink raw reply related
* [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531)
From: DevExalt @ 2025-12-15 12:53 UTC (permalink / raw)
To: jikos, bentiss
Cc: lains, hadess, linux-input, linux-kernel, sari.kreitem, hbarnor,
Baraa Atta (Dev Exalt)
From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com>
Add support in the Logitech HID++ driver for the HID++ Multi-Platform
feature (0x4531), which enables HID++ devices to adjust their behavior
based on the host operating system (Linux, ChromeOS, Android).
This patch:
* Adds device IDs for MX Keys S (046d:b378) and Casa Keys (046d:b371).
* Introduces the module parameter "hidpp_platform" to allow selecting a
target platform.
* Detects whether a device implements feature 0x4531.
* Validates that the requested platform is supported by the device.
* Applies the platform index when valid, otherwise leaves the device
unchanged.
* Keeps default behavior when "hidpp_platform" is unset or invalid.
Supported values for hidpp_platform:
Android, Linux, Chrome
TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify:
* Feature 0x4531 is detected.
* Valid platform values are accepted and applied.
* Invalid platform values result in no update.
* Devices without 0x4531 retain default behavior.
* Platform-specific key behavior is observed once applied.
Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com>
---
drivers/hid/hid-ids.h | 2 +
drivers/hid/hid-logitech-hidpp.c | 280 +++++++++++++++++++++++++++++++
drivers/hid/hid-quirks.c | 2 +
3 files changed, 284 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index d31711f1aaec..12de1194d7fa 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -866,6 +866,8 @@
#define USB_DEVICE_ID_LOGITECH_T651 0xb00c
#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309
#define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00
+#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371
+#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378
#define USB_DEVICE_ID_LOGITECH_C007 0xc007
#define USB_DEVICE_ID_LOGITECH_C077 0xc077
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index d5011a5d0890..e94daed31981 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct hid_device *hdev,
return report && report->application == application;
}
+/* -------------------------------------------------------------------------- */
+/* 0x4531: Multi-Platform Support */
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Some Logitech devices expose the HID++ feature 0x4531 (Multi-Platform) allowing
+ * the host to specify which operating system platform to use on the device. Changing device's
+ * platform may alter the behavior of the device to match the specified platform.
+ */
+
+static char *hidpp_platform;
+module_param(hidpp_platform, charp, 0644);
+MODULE_PARM_DESC(hidpp_platform, "Select host platform type for Logitech HID++ Multi-Platform feature "
+ "0x4531, valid values: (linux|chrome|android). If unset, no "
+ "change is applied.");
+
+#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531
+#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F
+#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F
+#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F
+
+#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10)
+#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11)
+#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12)
+
+struct hidpp_platform_desc {
+ u8 plat_idx;
+ u8 desc_idx;
+ u16 plat_mask;
+};
+
+/**
+ * hidpp_multiplatform_mask_from_str() - Convert platform name to an HID++ platform mask
+ * @pname: Platform name string
+ *
+ * Converts a platform name string to its corresponding HID++ platform mask based on
+ * the Multi-Platform feature specification.
+ *
+ * Return: Platform mask corresponding to @pname on success,
+ * or 0 if @pname is NULL or unsupported.
+ */
+static u16 hidpp_multiplatform_mask_from_str(const char *pname)
+{
+ if (!pname)
+ return 0;
+
+ if (!strcasecmp(pname, "linux"))
+ return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX;
+ if (!strcasecmp(pname, "chrome"))
+ return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME;
+ if (!strcasecmp(pname, "android"))
+ return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID;
+
+ return 0;
+}
+
+/**
+ * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform descriptors
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @num_desc: Pointer to store the number of platform descriptors
+ *
+ * Retrieves the number of platform descriptors supported by the device through
+ * the Multi-Platform feature and stores it in @num_desc.
+ *
+ * Return: 0 on success, or non-zero on failure.
+ */
+static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device *hidpp,
+ u8 feat_index, u8 *num_desc)
+{
+ int ret;
+ struct hidpp_report response;
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ ret = hidpp_send_fap_command_sync(hidpp, feat_index,
+ HIDPP_MULTIPLATFORM_GET_FEATURE_INFO,
+ NULL, 0, &response);
+ if (ret) {
+ hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO failed (err=%d)", ret);
+ return ret;
+ }
+
+ *num_desc = response.fap.params[3];
+ hid_dbg(hdev, "Multiplatform: Device supports %d platform descriptors", *num_desc);
+
+ return 0;
+}
+
+/**
+ * hidpp_multiplatform_get_platform_desc() - Retrieve a platform descriptor entry
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @platform_idx: Index of the platform descriptor to retrieve
+ * @pdesc: Pointer to store the retrieved platform descriptor
+ *
+ * Retrieves a single platform descriptor identified by @platform_idx from the
+ * device and stores the parsed descriptor fields in @pdesc.
+ *
+ * Return: 0 on success, or non-zero on failure.
+ */
+static int hidpp_multiplatform_get_platform_desc(struct hidpp_device *hidpp, u8 feat_index,
+ u8 platform_idx, struct hidpp_platform_desc *pdesc)
+{
+ int ret;
+ struct hidpp_report response;
+ u8 params[1] = { platform_idx };
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ ret = hidpp_send_fap_command_sync(hidpp, feat_index,
+ HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR,
+ params, sizeof(params), &response);
+
+ if (ret) {
+ hid_warn(hdev,
+ "Multiplatform: GET_PLATFORM_DESCRIPTOR failed for index %d (err=%d)",
+ platform_idx, ret);
+ return ret;
+ }
+
+ pdesc->plat_idx = response.fap.params[0];
+ pdesc->desc_idx = response.fap.params[1];
+ pdesc->plat_mask = get_unaligned_be16(&response.fap.params[2]);
+
+ hid_dbg(hdev,
+ "Multiplatform: descriptor %d: plat_idx=%d, desc_idx=%d, plat_mask=0x%04x",
+ platform_idx, pdesc->plat_idx, pdesc->desc_idx, pdesc->plat_mask);
+
+ return 0;
+}
+
+/**
+ * hidpp_multiplatform_get_platform_index() - Find platform index for a mask
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @plat_mask: Platform mask to search for
+ * @plat_index: Pointer to store the matched platform index
+ *
+ * Iterates through all platform descriptors exposed by the device via the
+ * Multi-Platform feature, retrieving each descriptor and comparing its
+ * platform mask to @plat_mask. A descriptor matches if its mask overlaps with
+ * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is non-zero).
+ *
+ * When a matching descriptor is found, its platform index (plat_idx) is
+ * written to @plat_index and the function returns success.
+ *
+ * If no descriptor matches, -ENOENT is returned.
+ *
+ * Return: 0 on success; -ENOENT if no matching descriptor exists;
+ * or non-zero on failure.
+ */
+static int hidpp_multiplatform_get_platform_index(struct hidpp_device *hidpp,
+ u8 feat_index, u16 plat_mask,
+ u8 *plat_index)
+{
+ int i;
+ int ret;
+ u8 num_desc;
+ struct hidpp_platform_desc pdesc;
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, &num_desc);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_desc; i++) {
+ ret = hidpp_multiplatform_get_platform_desc(hidpp, feat_index, i, &pdesc);
+ if (ret)
+ return ret;
+
+ if (pdesc.plat_mask & plat_mask) {
+ *plat_index = pdesc.plat_idx;
+ hid_dbg(hdev,
+ "Multiplatform: Selected platform index %d for platform '%s'",
+ *plat_index, hidpp_platform);
+ return 0;
+ }
+ }
+
+ hid_dbg(hdev,
+ "Multiplatform: No matching platform descriptor found for platform '%s'",
+ hidpp_platform);
+ return -ENOENT;
+}
+
+/**
+ * hidpp_multiplatform_update_device_platform() - Update the device platform
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @plat_index: Platform index to set on the device
+ *
+ * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to the device to
+ * update its platform index to @plat_index.
+ *
+ * Return: 0 on success, or non-zero on failure.
+ */
+static int hidpp_multiplatform_update_device_platform(struct hidpp_device *hidpp,
+ u8 feat_index, u8 plat_index)
+{
+ int ret;
+ struct hidpp_report response;
+ /* Byte 0 (hostIndex): 0xFF selects the current host. */
+ u8 params[2] = { 0xFF, plat_index };
+
+ ret = hidpp_send_fap_command_sync(hidpp, feat_index,
+ HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM,
+ params, sizeof(params), &response);
+
+ if (ret)
+ hid_warn(hidpp->hid_dev,
+ "Multiplatform: SET_CURRENT_PLATFORM failed for index %d (err=%d)",
+ plat_index, ret);
+
+ return ret;
+}
+
+/**
+ * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform (0x4531) feature
+ * @hidpp: Pointer to the hidpp_device instance
+ *
+ * Initializes the Multi-Platform feature by selecting the device platform
+ * corresponding to the module parameter @hidpp_platform, if provided.
+ *
+ * The function performs the following steps:
+ * 1. Convert the @hidpp_platform string into a platform mask.
+ * 2. Check whether the device supports the Multi-Platform feature (0x4531).
+ * 3. Look up the device's platform index whose mask matches the host
+ * platform mask.
+ * 4. Apply that platform index to the device via 'SET_CURRENT_PLATFORM'.
+ *
+ * If the module parameter is unset or invalid, or the device does not support
+ * the feature, or no matching platform descriptor is found, the function exits
+ * silently without modifying the device state.
+ *
+ * On success, the device's platform configuration is updated.
+ */
+static void hidpp_multiplatform_init(struct hidpp_device *hidpp)
+{
+ int ret;
+ u8 feat_index;
+ u8 plat_index;
+ u16 host_plat_mask;
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ if (!hidpp_platform)
+ return;
+
+ host_plat_mask = hidpp_multiplatform_mask_from_str(hidpp_platform);
+ if (!host_plat_mask) {
+ hid_warn(hdev,
+ "Multiplatform: Invalid or unsupported platform name '%s'",
+ hidpp_platform);
+ return;
+ }
+
+ ret = hidpp_root_get_feature(hidpp, HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index);
+ if (ret) {
+ hid_warn(hdev,
+ "Multiplatform: Failed to get the HID++ multiplatform feature 0x4531");
+ return;
+ }
+
+ ret = hidpp_multiplatform_get_platform_index(hidpp, feat_index, host_plat_mask,
+ &plat_index);
+ if (ret)
+ return;
+
+ ret = hidpp_multiplatform_update_device_platform(hidpp, feat_index, plat_index);
+ if (ret)
+ return;
+
+ hid_info(hdev,
+ "Multiplatform: Device platform successfully set to '%s'", hidpp_platform);
+}
+
static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct hidpp_device *hidpp;
@@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
connect_mask &= ~HID_CONNECT_HIDINPUT;
+ hidpp_multiplatform_init(hidpp);
+
/* Now export the actual inputs and hidraw nodes to the world */
hid_device_io_stop(hdev);
ret = hid_connect(hdev, connect_mask);
@@ -4664,6 +4940,10 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) },
{ /* MX Anywhere 3SB mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
+ { /* Casa Keys keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) },
+ { /* MX Keys S keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) },
{}
};
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index c89a015686c0..99ca04b61bda 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -520,6 +520,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
#endif
#if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP)
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) },
#endif
#if IS_ENABLED(CONFIG_HID_MAGICMOUSE)
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v1 2/3] Input: cros_ec_keyb: add function key support
From: Fabio Baltieri @ 2025-12-15 13:09 UTC (permalink / raw)
To: Simon Glass
Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Benson Leung, Guenter Roeck, Tzung-Bi Shih, linux-input,
devicetree, chrome-platform, linux-kernel
In-Reply-To: <CAFLszThUU4hfb4vY4mmGHQadRKThG3e=9cAKRy_ampKwA_XNcA@mail.gmail.com>
Hey Simon,
On Thu, Dec 11, 2025 at 06:29:01AM -0700, Simon Glass wrote:
> > @@ -44,6 +52,13 @@
> > * @bs_idev: The input device for non-matrix buttons and switches (or NULL).
> > * @notifier: interrupt event notifier for transport devices
> > * @vdata: vivaldi function row data
> > + * @fn_key: coordinate of the function key
> > + * @fn_keymap: array of coordinate and codes for the function keys
> > + * @fn_keymap_len: number of entries in the fn_keymap array
> > + * @fn_key_status: active function keys bitmap
> > + * @normal_key_status: active normal keys bitmap
> > + * @fn_key_pressed: tracks the function key status
> > + * @fn_key_triggered: tracks where any function key fired
> > */
> > struct cros_ec_keyb {
> > unsigned int rows;
> > @@ -61,6 +76,14 @@ struct cros_ec_keyb {
> > struct notifier_block notifier;
> >
> > struct vivaldi_data vdata;
> > +
> > + uint32_t fn_key;
>
> Normally we use u32/u8 these days
Okay, I did notice the file was a bit of a mix, I'll change them in v2.
>
> > + uint32_t *fn_keymap;
> > + int fn_keymap_len;
> > + uint32_t fn_key_status;
> > + uint8_t normal_key_status[CROS_EC_KEYBOARD_COLS_MAX];
> > + bool fn_key_pressed;
> > + bool fn_key_triggered;
> > };
> >
> > /**
> > @@ -166,16 +189,108 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf)
> > return false;
> > }
> >
> > +static bool cros_ec_key_is(int row, int col, uint32_t key)
> > +{
> > + if (row == KEY_ROW(key) && col == KEY_COL(key))
> > + return true;
> > +
> > + return false;
> > +}
> > +
> > +static void cros_ec_keyb_process_one(struct cros_ec_keyb *ckdev,
> > + int row, int col, bool state)
> > +{
> > + struct input_dev *idev = ckdev->idev;
> > + const unsigned short *keycodes = idev->keycode;
> > + int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
> > + unsigned int code = keycodes[pos];
> > +
> > + dev_dbg(ckdev->dev, "changed: [r%d c%d]: byte %02x\n", row, col, state);
> > +
> > + if (ckdev->fn_keymap) {
> > + if (cros_ec_key_is(row, col, ckdev->fn_key)) {
> > + ckdev->fn_key_pressed = state;
> > +
> > + if (state) {
> > + ckdev->fn_key_triggered = false;
> > + } else if (!ckdev->fn_key_triggered) {
> > + /*
> > + * Send the original code if nothing else has
> > + * been pressed together with Fn.
> > + */
> > + input_event(idev, EV_MSC, MSC_SCAN, pos);
> > + input_report_key(idev, code, true);
> > + input_sync(ckdev->idev);
>
> What is this function? I might be missing a patch?
input_sync? it sends an EV_SYN, been there from the start, though I
noticed I miss one two lines below, was relying on the rest of the
function to send it but I changed the logic at some point and broke that
path, will fix that.
>
> > +
> > + input_event(idev, EV_MSC, MSC_SCAN, pos);
> > + input_report_key(idev, code, false);
> > + }
> > +
> > + return;
> > + }
> > +
> > + if (!state) {
> > + /* Key release, may need to release the Fn code */
> > + for (int i = 0; i < ckdev->fn_keymap_len; i++) {
> > + if (!cros_ec_key_is(row, col,
> > + ckdev->fn_keymap[i]))
> > + continue;
> > +
> > + if ((ckdev->fn_key_status & BIT(i)) == 0)
> > + continue;
> > +
> > + code = KEY_VAL(ckdev->fn_keymap[i]);
> > + ckdev->fn_key_status &= ~BIT(i);
> > +
> > + input_event(idev, EV_MSC, MSC_SCAN, pos);
> > + input_report_key(idev, code, state);
> > +
> > + return;
> > + }
> > +
> > + if ((ckdev->normal_key_status[col] & BIT(row)) == 0)
> > + /* Discard, key press code was not sent */
> > + return;
> > + } else if (ckdev->fn_key_pressed) {
> > + /* Key press while holding Fn */
> > + ckdev->fn_key_triggered = true;
> > +
> > + for (int i = 0; i < ckdev->fn_keymap_len; i++) {
> > + if (!cros_ec_key_is(row, col,
> > + ckdev->fn_keymap[i]))
> > + continue;
> > +
> > + code = KEY_VAL(ckdev->fn_keymap[i]);
> > + ckdev->fn_key_status |= BIT(i);
> > +
> > + input_event(idev, EV_MSC, MSC_SCAN, pos);
> > + input_report_key(idev, code, state);
> > +
> > + return;
> > + }
> > +
> > + /* Do not emit a code if the key is not mapped */
> > + return;
> > + }
> > + }
>
> I think this function could do with splitting a bit
Yeah, I don't love it either but there's a lot of logic intertwined in
there, tried to split it myself and ended up breaking stuff, the logic
for the fn key itsel though can go that's a good 16 lines, I'll start
with that, send a v2 and then go from there.
> Can the sandbox driver support this too?
Not sure what you are referring to, can you give me a pointer?
Hey thanks for the review, good to hear from you. :-)
Cheers,
Fabio
--
Fabio Baltieri
^ permalink raw reply
* [PATCH 1/4] Input: stmfts - correct wording for the warning message
From: David Heidelberg via B4 Relay @ 2025-12-15 14:30 UTC (permalink / raw)
To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Petr Hodina,
Javier Martinez Canillas, Rob Herring, Andi Shyti
Cc: linux-input, linux-stm32, linux-arm-kernel, linux-kernel,
David Heidelberg
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
From: David Heidelberg <david@ixit.cz>
We're trying to enable regulator, not disable it.
Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen")
Suggested-by: Petr Hodina <petr.hodina@protonmail.com>
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 119cd26851cf6..9f5609524fef6 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -120,7 +120,7 @@ static int stmfts_brightness_set(struct led_classdev *led_cdev,
err = regulator_enable(sdata->ledvdd);
if (err) {
dev_warn(&sdata->client->dev,
- "failed to disable ledvdd regulator: %d\n",
+ "failed to enable ledvdd regulator: %d\n",
err);
return err;
}
--
2.51.0
^ permalink raw reply related
* [PATCH 0/4] Input: small nitpick fixes
From: David Heidelberg via B4 Relay @ 2025-12-15 14:30 UTC (permalink / raw)
To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Petr Hodina,
Javier Martinez Canillas, Rob Herring, Andi Shyti
Cc: linux-input, linux-stm32, linux-arm-kernel, linux-kernel,
David Heidelberg
Feel free to ignore the last patch, if you want to wait for FTS5
support.
Signed-off-by: David Heidelberg <david@ixit.cz>
---
David Heidelberg (1):
Input: stmfts - correct wording for the warning message
Petr Hodina (3):
Input: stmfts - Make comments correct
Input: stmfts - use sysfs_emit() instead of sprintf()
Input: stmfts - use client to make future code cleaner
drivers/input/touchscreen/stmfts.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
---
base-commit: 4a5663c04bb679631985a15efab774da58c37815
change-id: 20251212-fts-fixes-30253fde92d9
Best regards,
--
David Heidelberg <david@ixit.cz>
^ permalink raw reply
* [PATCH 3/4] Input: stmfts - use sysfs_emit() instead of sprintf()
From: David Heidelberg via B4 Relay @ 2025-12-15 14:30 UTC (permalink / raw)
To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Petr Hodina,
Javier Martinez Canillas, Rob Herring, Andi Shyti
Cc: linux-input, linux-stm32, linux-arm-kernel, linux-kernel,
David Heidelberg
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
From: Petr Hodina <petr.hodina@protonmail.com>
Follow the advice in Documentation/filesystems/sysfs.rst:
show() should only use sysfs_emit() or sysfs_emit_at() when formatting
the value to be returned to user space.
Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/input/touchscreen/stmfts.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index ad363b3c344cd..4b166b0a9a5a6 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -410,7 +410,7 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%#x\n", sdata->chip_id);
+ return sysfs_emit(buf, "%#x\n", sdata->chip_id);
}
static ssize_t stmfts_sysfs_chip_version(struct device *dev,
@@ -418,7 +418,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->chip_ver);
+ return sysfs_emit(buf, "%u\n", sdata->chip_ver);
}
static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
@@ -426,7 +426,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->fw_ver);
+ return sysfs_emit(buf, "%u\n", sdata->fw_ver);
}
static ssize_t stmfts_sysfs_config_id(struct device *dev,
@@ -434,7 +434,7 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%#x\n", sdata->config_id);
+ return sysfs_emit(buf, "%#x\n", sdata->config_id);
}
static ssize_t stmfts_sysfs_config_version(struct device *dev,
@@ -442,7 +442,7 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->config_ver);
+ return sysfs_emit(buf, "%u\n", sdata->config_ver);
}
static ssize_t stmfts_sysfs_read_status(struct device *dev,
@@ -457,7 +457,7 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev,
if (err)
return err;
- return sprintf(buf, "%#02x\n", status[0]);
+ return sysfs_emit(buf, "%#02x\n", status[0]);
}
static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
@@ -465,7 +465,7 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", sdata->hover_enabled);
+ return sysfs_emit(buf, "%u\n", sdata->hover_enabled);
}
static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
--
2.51.0
^ permalink raw reply related
* [PATCH 2/4] Input: stmfts - Make comments correct
From: David Heidelberg via B4 Relay @ 2025-12-15 14:30 UTC (permalink / raw)
To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Petr Hodina,
Javier Martinez Canillas, Rob Herring, Andi Shyti
Cc: linux-input, linux-stm32, linux-arm-kernel, linux-kernel,
David Heidelberg
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@ixit.cz>
From: Petr Hodina <petr.hodina@protonmail.com>
No functional change.
Fixes: 78bcac7b2ae1 ("Input: add support for the STMicroelectronics FingerTip touchscreen")
Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/input/touchscreen/stmfts.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index 9f5609524fef6..ad363b3c344cd 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -141,7 +141,7 @@ static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
/*
* We can't simply use i2c_smbus_read_i2c_block_data because we
- * need to read more than 255 bytes (
+ * need to read 256 bytes, which exceeds the 255-byte SMBus block limit.
*/
static int stmfts_read_events(struct stmfts_data *sdata)
{
@@ -594,9 +594,6 @@ static void stmfts_power_off(void *data)
sdata->regulators);
}
-/* This function is void because I don't want to prevent using the touch key
- * only because the LEDs don't get registered
- */
static int stmfts_enable_led(struct stmfts_data *sdata)
{
int err;
--
2.51.0
^ permalink raw reply related
* [PATCH 4/4] Input: stmfts - use client to make future code cleaner
From: David Heidelberg via B4 Relay @ 2025-12-15 14:30 UTC (permalink / raw)
To: Dmitry Torokhov, Maxime Coquelin, Alexandre Torgue, Petr Hodina,
Javier Martinez Canillas, Rob Herring, Andi Shyti
Cc: linux-input, linux-stm32, linux-arm-kernel, linux-kernel,
David Heidelberg
In-Reply-To: <20251215-fts-fixes-v1-0-8c1e3a63ebf1@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 4b166b0a9a5a6..06845a00348cc 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -747,9 +747,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.51.0
^ permalink raw reply related
* Re: [PATCH v3] Input: rename INPUT_PROP_HAPTIC_TOUCHPAD to INPUT_PROP_PRESSUREPAD
From: Dmitry V. Levin @ 2025-12-15 16:51 UTC (permalink / raw)
To: Peter Hutterer
Cc: Jonathan Denose, Jiri Kosina, Benjamin Tissoires, Dmitry Torokhov,
Jonathan Corbet, Henrik Rydberg, linux-input, linux-kernel,
linux-doc, Angela Czubak, Sean O'Brien, Randy Dunlap
In-Reply-To: <20251106114534.GA405512@tassie>
Hi,
On Thu, Nov 06, 2025 at 09:45:34PM +1000, Peter Hutterer wrote:
> And expand it to encompass all pressure pads.
>
> Definition: "pressure pad" as used here as includes all touchpads that
> use physical pressure to convert to click, without physical hinges. Also
> called haptic touchpads in general parlance, Synaptics calls them
> ForcePads.
>
> Most (all?) pressure pads are currently advertised as
> INPUT_PROP_BUTTONPAD. The suggestion to identify them as pressure pads
> by defining the resolution on ABS_MT_PRESSURE has been in the docs since
> commit 20ccc8dd38a3 ("Documentation: input: define
> ABS_PRESSURE/ABS_MT_PRESSURE resolution as grams") but few devices
> provide this information.
>
> In userspace it's thus impossible to determine whether a device is a
> true pressure pad (pressure equals pressure) or a normal clickpad with
> (pressure equals finger size).
>
> Commit 7075ae4ac9db ("Input: add INPUT_PROP_HAPTIC_TOUCHPAD") introduces
> INPUT_PROP_HAPTIC_TOUCHPAD but restricted it to those touchpads that
> have support for userspace-controlled effects. Let's expand and rename
> that definition to include all pressure pad touchpads since those that
> do support FF effects can be identified by the presence of the
> FF_HAPTIC bit.
>
> This means:
> - clickpad: INPUT_PROP_BUTTONPAD
> - pressurepad: INPUT_PROP_BUTTONPAD + INPUT_PROP_PRESSUREPAD
> - pressurepad with configurable haptics:
> INPUT_PROP_BUTTONPAD + INPUT_PROP_PRESSUREPAD + FF_HAPTIC
>
> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
> ---
> ftr, I picked PRESSUREPAD over Dmitry's PRESSURE_TOUCHPAD suggestion
> because it matches better with the existing BUTTONPAD.
>
> Changes to v1: extra empty lines to render the lists as lists
> Changes to v2: rename to PRESSUREPAD and rename it in the instances
> where it's used in the code
>
> v1: https://lore.kernel.org/linux-input/20251030011735.GA969565@quokka/T/#u
> v2: https://lore.kernel.org/linux-input/20251030011735.GA969565@quokka/T/#m9504de27b02d00a55d540fd9fec9aed3edd0133c
>
> Documentation/input/event-codes.rst | 25 ++++++++++++++++++-------
> drivers/hid/hid-haptic.c | 2 +-
> include/uapi/linux/input-event-codes.h | 2 +-
> 3 files changed, 20 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst
> index 1ead9bb8d9c6..4424cbff251f 100644
> --- a/Documentation/input/event-codes.rst
> +++ b/Documentation/input/event-codes.rst
> @@ -400,19 +400,30 @@ can report through the rotational axes (absolute and/or relative rx, ry, rz).
> All other axes retain their meaning. A device must not mix
> regular directional axes and accelerometer axes on the same event node.
>
> -INPUT_PROP_HAPTIC_TOUCHPAD
> ---------------------------
> +INPUT_PROP_PRESSUREPAD
> +----------------------
> +
> +The INPUT_PROP_PRESSUREPAD property indicates that the device provides
> +simulated haptic feedback (e.g. a vibrator motor situated below the surface)
> +instead of physical haptic feedback (e.g. a hinge). This property is only set
> +if the device:
>
> -The INPUT_PROP_HAPTIC_TOUCHPAD property indicates that device:
> -- supports simple haptic auto and manual triggering
> - can differentiate between at least 5 fingers
> - uses correct resolution for the X/Y (units and value)
> -- reports correct force per touch, and correct units for them (newtons or grams)
> - follows the MT protocol type B
>
> +If the simulated haptic feedback is controllable by userspace the device must:
> +
> +- support simple haptic auto and manual triggering, and
> +- report correct force per touch, and correct units for them (newtons or grams), and
> +- provide the EV_FF FF_HAPTIC force feedback effect.
> +
> Summing up, such devices follow the MS spec for input devices in
> -Win8 and Win8.1, and in addition support the Simple haptic controller HID table,
> -and report correct units for the pressure.
> +Win8 and Win8.1, and in addition may support the Simple haptic controller HID
> +table, and report correct units for the pressure.
> +
> +Where applicable, this property is set in addition to INPUT_PROP_BUTTONPAD, it
> +does not replace that property.
>
> Guidelines
> ==========
> diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
> index aa090684c1f2..fc8a9997f815 100644
> --- a/drivers/hid/hid-haptic.c
> +++ b/drivers/hid/hid-haptic.c
> @@ -86,7 +86,7 @@ int hid_haptic_input_configured(struct hid_device *hdev,
> if (hi->application == HID_DG_TOUCHPAD) {
> if (haptic->auto_trigger_report &&
> haptic->manual_trigger_report) {
> - __set_bit(INPUT_PROP_HAPTIC_TOUCHPAD, hi->input->propbit);
> + __set_bit(INPUT_PROP_PRESSUREPAD, hi->input->propbit);
> return 1;
> }
> return 0;
> diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
> index 8ba48590bd2c..d21172c6a266 100644
> --- a/include/uapi/linux/input-event-codes.h
> +++ b/include/uapi/linux/input-event-codes.h
> @@ -27,7 +27,7 @@
> #define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
> #define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
> #define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
> -#define INPUT_PROP_HAPTIC_TOUCHPAD 0x07 /* is a haptic touchpad */
> +#define INPUT_PROP_PRESSUREPAD 0x07 /* pressure triggers clicks */
>
> #define INPUT_PROP_MAX 0x1f
> #define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
When you rename UAPI constants, please don't forget to retain old names,
otherwise there is a high chance you'll break userspace.
This time you've broken the build of strace.
--
ldv
^ permalink raw reply
* Re: [PATCH v3] Input: rename INPUT_PROP_HAPTIC_TOUCHPAD to INPUT_PROP_PRESSUREPAD
From: Jiri Kosina @ 2025-12-15 17:20 UTC (permalink / raw)
To: Dmitry V. Levin
Cc: Peter Hutterer, Jonathan Denose, Benjamin Tissoires,
Dmitry Torokhov, Jonathan Corbet, Henrik Rydberg, linux-input,
linux-kernel, linux-doc, Angela Czubak, Sean O'Brien,
Randy Dunlap
In-Reply-To: <20251215165122.GB32290@strace.io>
On Mon, 15 Dec 2025, Dmitry V. Levin wrote:
> > diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
> > index 8ba48590bd2c..d21172c6a266 100644
> > --- a/include/uapi/linux/input-event-codes.h
> > +++ b/include/uapi/linux/input-event-codes.h
> > @@ -27,7 +27,7 @@
> > #define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
> > #define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
> > #define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
> > -#define INPUT_PROP_HAPTIC_TOUCHPAD 0x07 /* is a haptic touchpad */
> > +#define INPUT_PROP_PRESSUREPAD 0x07 /* pressure triggers clicks */
> >
> > #define INPUT_PROP_MAX 0x1f
> > #define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
>
> When you rename UAPI constants, please don't forget to retain old names,
> otherwise there is a high chance you'll break userspace.
> This time you've broken the build of strace.
In general I'd agree, but in this particular case, both commits happened
within the development window (6.18-rc1 vs 6.18-rc7).
"No breaking of userspace" is certainly a hard (and good) rule between
actual existing version releases, but I hope we're not expected to adhere
to it in between -rcs during a development cycle.
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] Input: i8042 - add TUXEDO InfinityBook Max Gen10 AMD to i8042 quirk table
From: Dmitry Torokhov @ 2025-12-15 18:15 UTC (permalink / raw)
To: Werner Sembach; +Cc: Christoffer Sandberg, linux-input, linux-kernel
In-Reply-To: <20251124203336.64072-1-wse@tuxedocomputers.com>
On Mon, Nov 24, 2025 at 09:31:34PM +0100, Werner Sembach wrote:
> From: Christoffer Sandberg <cs@tuxedo.de>
>
> The device occasionally wakes up from suspend with missing input on the
> internal keyboard and the following suspend attempt results in an instant
> wake-up. The quirks fix both issues for this device.
>
> Signed-off-by: Christoffer Sandberg <cs@tuxedo.de>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> Cc: stable@vger.kernel.org
Applied, thank you.
--
Dmitry
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox