* [PATCH v3 0/7] mfd: Add support for Asus Transformer embedded controller
From: Svyatoslav Ryhel @ 2026-02-14 18:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
Lee Jones, Pavel Machek, Sebastian Reichel, Svyatoslav Ryhel,
Ion Agorria, Michał Mirosław
Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm
Add support for embedded controller used in Asus Transformers for
managing power and input functions.
---
Changes in v2:
- converted sysfs debug exports into debugfs
- added kernel-doc comments for exposed functions
- fixed minor typos and inconsistencies
Changes in v3:
- dropped DockRAM commits (both schema and driver)
- integrated DockRAM functionality directly into the controller driver
- EC schema moved to embedded controllers folder
- removed all cell descriptions from the schema
- removed all compatibles from the cell drivers
- adjusted naming conventions to better align with the ASUS Transformers
- defined EC variant sets to provide coverage for all known devices
---
Michał Mirosław (6):
mfd: Add driver for ASUS Transformer embedded controller
input: serio: Add driver for ASUS Transformer dock keyboard and
touchpad
input: keyboard: Add driver for ASUS Transformer dock multimedia keys
leds: Add driver for ASUS Transformer LEDs
power: supply: Add driver for ASUS Transformer battery
power: supply: Add charger driver for Asus Transformers
Svyatoslav Ryhel (1):
dt-bindings: embedded-controller: document ASUS Transformer EC
.../asus,transformer-ec.yaml | 98 +++
drivers/input/keyboard/Kconfig | 10 +
drivers/input/keyboard/Makefile | 1 +
.../input/keyboard/asus-transformer-ec-keys.c | 272 +++++++
drivers/input/serio/Kconfig | 15 +
drivers/input/serio/Makefile | 1 +
drivers/input/serio/asus-transformer-ec-kbc.c | 147 ++++
drivers/leds/Kconfig | 11 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-asus-transformer-ec.c | 79 ++
drivers/mfd/Kconfig | 14 +
drivers/mfd/Makefile | 1 +
drivers/mfd/asus-transformer-ec.c | 763 ++++++++++++++++++
drivers/power/supply/Kconfig | 22 +
drivers/power/supply/Makefile | 2 +
.../supply/asus-transformer-ec-battery.c | 272 +++++++
.../supply/asus-transformer-ec-charger.c | 193 +++++
include/linux/mfd/asus-transformer-ec.h | 162 ++++
18 files changed, 2064 insertions(+)
create mode 100644 Documentation/devicetree/bindings/embedded-controller/asus,transformer-ec.yaml
create mode 100644 drivers/input/keyboard/asus-transformer-ec-keys.c
create mode 100644 drivers/input/serio/asus-transformer-ec-kbc.c
create mode 100644 drivers/leds/leds-asus-transformer-ec.c
create mode 100644 drivers/mfd/asus-transformer-ec.c
create mode 100644 drivers/power/supply/asus-transformer-ec-battery.c
create mode 100644 drivers/power/supply/asus-transformer-ec-charger.c
create mode 100644 include/linux/mfd/asus-transformer-ec.h
--
2.51.0
^ permalink raw reply
* Re: [patch 1/1] drivers/input/misc/pf1550-onkey.c: fix build with CONFIG_PM_SLEEP=n
From: Dmitry Torokhov @ 2026-02-14 2:56 UTC (permalink / raw)
To: Andrew Morton; +Cc: sean, Frank.Li, linux-input, samuel.kayode
In-Reply-To: <20260214003828.BD1A5C116C6@smtp.kernel.org>
Hi Andrew,
On Fri, Feb 13, 2026 at 04:38:28PM -0800, Andrew Morton wrote:
> From: Andrew Morton <akpm@linux-foundation.org>
> Subject: drivers/input/misc/pf1550-onkey.c: fix build with CONFIG_PM_SLEEP=n
> Date: Fri Feb 13 02:39:04 PM PST 2026
>
> riscv randconfig:
>
> drivers/input/misc/pf1550-onkey.c:154:12: error: 'pf1550_onkey_resume' defined but not used [-Werror=unused-function]
> 154 | static int pf1550_onkey_resume(struct device *dev)
> | ^~~~~~~~~~~~~~~~~~~
> drivers/input/misc/pf1550-onkey.c:133:12: error: 'pf1550_onkey_suspend' defined but not used [-Werror=unused-function]
> 133 | static int pf1550_onkey_suspend(struct device *dev)
> | ^~~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
Picked the following fix for this:
https://patch.msgid.link/20251210211149.543928-1-vaibhavgupta40@gmail.com
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH AUTOSEL 6.19-6.1] HID: apple: Add "SONiX KN85 Keyboard" to the list of non-apple keyboards
From: Sasha Levin @ 2026-02-14 0:59 UTC (permalink / raw)
To: patches, stable
Cc: Joey Bednar, Jiri Kosina, Sasha Levin, jikos, bentiss,
linux-input
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: Joey Bednar <linux@joeybednar.com>
[ Upstream commit 7273acfd0aef106093a8ffa3b4973eb70e5a3799 ]
The SoNiX KN85 keyboard identifies as the "Apple, Inc. Aluminium
Keyboard" and is not recognized as a non-apple keyboard. Adding "SoNiX
KN85 Keyboard" to the list of non-apple keyboards fixes the function
keys.
Signed-off-by: Joey Bednar <linux@joeybednar.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This confirms the exact same pattern. The "SONiX KN85 Keyboard"
identifies itself as an Apple keyboard (via vendor/product IDs matching
Apple's Aluminium Keyboard) but has a different HID name string than
"SONiX USB DEVICE", so the existing entry doesn't match it. The
`strncmp` prefix match means "SONiX USB DEVICE" would only match devices
whose name starts with exactly that string — "SONiX KN85 Keyboard"
starts with "SONiX KN" which doesn't match "SONiX USB".
---
## Complete Analysis
### 1. COMMIT MESSAGE ANALYSIS
The commit message is clear and concise:
- **Problem**: The SoNiX KN85 keyboard identifies itself (via USB
VID:PID) as the "Apple, Inc. Aluminium Keyboard" but is not an Apple
keyboard.
- **Consequence**: Without the fix, the HID apple driver applies Apple-
specific function key mapping (`fnmode=1`, fkeyslast), making the
function keys behave as media keys by default. This is wrong for a
non-Apple keyboard.
- **Fix**: Adding the keyboard's name string to the
`non_apple_keyboards[]` list so it gets properly detected and uses
`fnmode=2` (fkeysfirst) by default.
- The commit was signed off by the HID subsystem maintainer Jiri Kosina,
confirming it was accepted through the proper review process.
### 2. CODE CHANGE ANALYSIS
The change is a **single line addition** to a static constant array:
```356:367:drivers/hid/hid-apple.c
static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
{ "SONiX USB DEVICE" },
{ "SONiX AK870 PRO" },
// ... rest of array
};
```
The new entry `{ "SONiX KN85 Keyboard" }` is added at the top. The
matching mechanism (`apple_is_non_apple_keyboard()` at line 369) does a
`strncmp` prefix comparison, so the full name "SONiX KN85 Keyboard"
would need to start with "SONiX KN85 Keyboard" to match (which it does
exactly). The existing "SONiX USB DEVICE" entry does NOT match because
the KN85 keyboard reports its name starting with "SONiX KN85", not
"SONiX USB".
### 3. CLASSIFICATION
This is a **hardware quirk/workaround**. The SoNiX KN85 keyboard is a
non-Apple keyboard that falsely presents Apple USB vendor/product IDs (a
common practice for cheap third-party keyboards), causing it to be
handled by the `hid-apple` driver. The driver then applies Apple-
specific key translation logic to a keyboard that doesn't need or want
it, breaking the function keys for the user.
This falls squarely into the "QUIRKS and WORKAROUNDS" exception category
for stable backporting:
- It's a hardware-specific fix for a real device with broken behavior
- It uses an existing mechanism (the `non_apple_keyboards` array)
- It fixes a real user-facing issue (broken function keys)
### 4. SCOPE AND RISK ASSESSMENT
- **Size**: 1 line added to a data array. Cannot be smaller.
- **Files touched**: 1 (`drivers/hid/hid-apple.c`)
- **Complexity**: Zero — it's a string literal added to an array
- **Risk of regression**: Effectively zero. The string match only
triggers for devices reporting "SONiX KN85 Keyboard" as their name. No
other devices are affected. The matching is by HID device name, not
vendor/product ID, so it's extremely targeted.
- **Dependencies**: None. The `non_apple_keyboards[]` mechanism exists
in all relevant stable trees (introduced in v6.0-rc1).
### 5. USER IMPACT
- **Who is affected**: Users of the SoNiX KN85 keyboard running Linux.
These are real-world hardware owners.
- **Severity**: Without this fix, the function keys (F1-F12) on the KN85
keyboard are mapped to media keys by default (brightness, volume,
etc.), which is wrong for this keyboard. This makes the keyboard
effectively unusable for standard function key operations unless the
user manually overrides `fnmode` via a module parameter.
- **Workaround exists**: Users can set `fnmode=2` manually, but this is
not discoverable and should not be needed.
### 6. STABILITY INDICATORS
- The commit follows the exact same pattern as **5+ previous similar
commits** (SONiX AK870 PRO, hfd.cn/WKB603, Jamesdonkey/A3R, Hailuck,
the original non-apple keyboards mechanism).
- Signed off by the HID subsystem maintainer (Jiri Kosina).
- The pattern has been in the kernel since v6.0 and is well understood.
### 7. DEPENDENCY CHECK
- **No dependencies**. The `non_apple_keyboards[]` array and
`apple_is_non_apple_keyboard()` function exist in all relevant stable
trees.
- The patch applies cleanly to any tree that already has the "SONiX
AK870 PRO" entry (or can trivially be adjusted if that entry isn't
present — it's just adding a line to an array).
### 8. PRECEDENT
This is identical in nature to the "SONiX AK870 PRO" (743c81cdc98fd),
"hfd.cn/WKB603" (df83a0df820b9), "Hailuck" (c4444d8749f69), and
"Jamesdonkey/A3R" (113f736655e4f) commits. All follow the same one-line-
addition pattern to the same array.
### Summary
This is a textbook hardware quirk addition — a single line of data added
to an existing mechanism that fixes broken function keys for a specific
keyboard model. It has zero risk of regression, zero dependencies beyond
existing infrastructure, fixes a real user-facing problem, and follows a
well-established pattern with multiple precedents. This is exactly the
kind of commit that stable trees exist to carry.
**YES**
drivers/hid/hid-apple.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 57da4f86a9fa7..233e367cce1d1 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -354,6 +354,7 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
};
static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
+ { "SONiX KN85 Keyboard" },
{ "SONiX USB DEVICE" },
{ "SONiX AK870 PRO" },
{ "Keychron" },
--
2.51.0
^ permalink raw reply related
* [PATCH AUTOSEL 6.19-6.18] HID: multitouch: add quirks for Lenovo Yoga Book 9i
From: Sasha Levin @ 2026-02-14 0:59 UTC (permalink / raw)
To: patches, stable
Cc: Brian Howard, Kris Fredrick, Andrei Shumailov, Jiri Kosina,
Sasha Levin, jikos, bentiss, linux-input
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: Brian Howard <blhoward2@gmail.com>
[ Upstream commit 822bc5b3744b0b2c2c9678aa1d80b2cf04fdfabf ]
The Lenovo Yoga Book 9i is a dual-screen laptop, with a single composite
USB device providing both touch and tablet interfaces for both screens.
All inputs report through a single device, differentiated solely by report
numbers. As there is no way for udev to differentiate the inputs based on
USB vendor/product ID or interface numbers, custom naming is required to
match against for downstream configuration. A firmware bug also results
in an erroneous InRange message report being received after the stylus
leaves proximity, blocking later touch events. Add required quirks for
Gen 8 to Gen 10 models, including a new quirk providing for custom input
device naming and dropping erroneous InRange reports.
Signed-off-by: Brian Howard <blhoward2@gmail.com>
Tested-by: Brian Howard <blhoward2@gmail.com>
Tested-by: Kris Fredrick <linux.baguette800@slmail.me>
Reported-by: Andrei Shumailov <gentoo1993@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220386
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Here is my complete analysis:
---
## Commit Analysis: HID: multitouch: add quirks for Lenovo Yoga Book 9i
### 1. COMMIT MESSAGE ANALYSIS
The commit message is clear and well-structured. Key signals:
- **"firmware bug"** explicitly mentioned — erroneous InRange reports
block touch events
- **Closes: bugzilla.kernel.org/show_bug.cgi?id=220386** — tracked
kernel bug
- **Reported-by: Andrei Shumailov** — user-reported real-world issue
- **Tested-by** from both the author (Brian Howard) and another user
(Kris Fredrick) — multiple testers
- **Signed-off-by: Jiri Kosina** — accepted by HID subsystem maintainer
The Lenovo Yoga Book 9i is a dual-screen laptop shipping to consumers.
All touch/stylus inputs are multiplexed through a single USB composite
device.
### 2. CODE CHANGE ANALYSIS
The commit makes changes in **two files** with **73 lines added**:
**a) `drivers/hid/hid-ids.h` — 1 line:**
Adds `USB_DEVICE_ID_LENOVO_YOGABOOK9I 0x6161`. Standard device ID
addition.
**b) `drivers/hid/hid-multitouch.c` — 72 lines across 5 insertion
points:**
1. **New quirk flag** (`MT_QUIRK_YOGABOOK9I BIT(24)`) — follows the
existing pattern (BIT(23) is `MT_QUIRK_APPLE_TOUCHBAR`).
2. **New device class** (`MT_CLS_YOGABOOK9I 0x0115`) — standard pattern,
same as `MT_CLS_APPLE_TOUCHBAR 0x0114`, `MT_CLS_SIS 0x0457`, etc.
3. **Class definition in `mt_classes[]`** (~8 lines) — combines existing
quirk flags (`MT_QUIRK_ALWAYS_VALID`, `MT_QUIRK_FORCE_MULTI_INPUT`,
`MT_QUIRK_SEPARATE_APP_REPORT`, `MT_QUIRK_HOVERING`) plus the device-
specific `MT_QUIRK_YOGABOOK9I`. Sets `export_all_inputs = true`. This
is the exact same pattern used by many existing classes (e.g.,
`MT_CLS_WIN_8_FORCE_MULTI_INPUT`).
4. **Firmware bug workaround in `mt_report()`** (~30 lines) — **THE
CRITICAL FIX**: After the stylus leaves proximity, the device
firmware erroneously sends an all-zero report with InRange set. This
report is consumed by the multitouch stack and blocks subsequent
touch events. The fix detects these bogus reports (all relevant
digitizer fields — InRange, TipSwitch, BarrelSwitch, BarrelSwitch2,
ContactID, TiltX, TiltY — are zero) and drops them by returning
early. Without this fix, **touch input becomes non-functional** after
stylus use.
5. **Custom naming in `mt_input_configured()`** (~20 lines) — Maps
report IDs to human-readable names (e.g., report 48→"Touchscreen
Top", 56→"Touchscreen Bottom", 20→"Stylus Top", 40→"Stylus Bottom",
80→"Emulated Touchpad"). Since all inputs come through a single USB
device with no interface differentiation, udev has **no other way**
to distinguish which input corresponds to which physical screen.
Without this, the dual-screen touchscreen/stylus configuration is
effectively impossible.
6. **Device ID table entry** (~6 lines) — Standard `HID_DEVICE()` entry
mapping `USB_VENDOR_ID_LENOVO` + `USB_DEVICE_ID_LENOVO_YOGABOOK9I` to
`MT_CLS_YOGABOOK9I`.
### 3. CLASSIFICATION
This is a **hardware quirk/workaround**, which falls squarely under the
"QUIRKS and WORKAROUNDS" stable exception:
- Fixes firmware-induced bug that blocks touch events (bug fix)
- Adds device-specific naming for a multiplexed USB device (hardware
workaround for udev differentiation)
- Uses the well-established `hid-multitouch` quirk framework
- Pattern is identical to Apple Touch Bar, ASUS, SIS, Razer Blade
Stealth, Smart Tech, and many other device-specific quirk additions
### 4. SCOPE AND RISK ASSESSMENT
**Scope**: 73 lines added across 2 files. All changes are behind a
**device-specific quirk flag** (`MT_QUIRK_YOGABOOK9I`) that is **only
activated** for USB VID:PID `0x17ef:0x6161` (Lenovo Yoga Book 9i).
**Risk**: **EXTREMELY LOW**. The changes:
- Are only triggered for one specific USB device ID
- Do not modify any common code paths
- Do not change behavior for any other hardware
- Use only existing framework constructs (`mt_classes[]` entries, quirk
flags, `mt_report()` filtering, `mt_input_configured()` naming)
- Are well-tested by multiple users
**Dependencies**: The commit is self-contained. It uses standard HID
definitions (`HID_DG_INRANGE`, `HID_DG_TIPSWITCH`, etc.) and `hid-
multitouch` structures that exist in all current stable trees (v6.1,
v6.6, v6.12). The `for (int ...)` C11 syntax is valid in all stable
trees (kernel uses `-std=gnu11` since v5.18+). The only backport
adjustment needed is the context around BIT(23)/BIT(24) numbering — in
stable trees without `MT_QUIRK_APPLE_TOUCHBAR` (v6.12 and earlier), the
BIT number would need adjustment from 24 to 23. This is a trivial
context fixup.
### 5. USER IMPACT
**HIGH for affected users**: The Lenovo Yoga Book 9i (Gen 8-10) is a
commercially available dual-screen laptop. Without this fix:
- Touch input **stops working** after stylus use (firmware InRange bug)
- Both screens cannot be independently configured (no input
differentiation)
The bugzilla (#220386) and multiple Reported-by/Tested-by tags confirm
this affects real users.
### 6. STABILITY INDICATORS
- Tested-by from author (Brian Howard) and second tester (Kris Fredrick)
- Signed-off by HID subsystem maintainer (Jiri Kosina)
- Kernel bugzilla with tracking
- Follows well-established pattern in hid-multitouch with many precedent
quirk additions
### 7. DEPENDENCY CHECK
No dependencies on other patches. The commit is completely self-
contained. All referenced symbols (`HID_DG_INRANGE`, `HID_DG_TIPSWITCH`,
`mt_find_report_data`, `rdata->application->quirks`, `hi->report->id`,
etc.) exist in all current stable kernel trees. Minor context adjustment
may be needed for older stable trees lacking the Apple Touch Bar quirk.
### Verdict
This commit fixes a real firmware bug that **blocks touch events** on
the Lenovo Yoga Book 9i, making the device partially non-functional. It
also provides necessary input naming for the dual-screen device to be
properly configurable. All changes are device-specific hardware quirks
behind a USB VID:PID-gated quirk flag with zero risk to other devices.
The commit follows the well-established hid-multitouch quirk pattern, is
tested by multiple users, and is accepted by the subsystem maintainer.
This is textbook "hardware quirk for a broken device" — exactly the type
of change stable trees are designed to accept.
**YES**
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-multitouch.c | 72 ++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9c2bf584d9f6f..5a18cb41e6d79 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -841,6 +841,7 @@
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
+#define USB_DEVICE_ID_LENOVO_YOGABOOK9I 0x6161
#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index b1c3ef1290587..f21850f7d89e4 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -76,6 +76,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
+#define MT_QUIRK_YOGABOOK9I BIT(24)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -231,6 +232,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
#define MT_CLS_APPLE_TOUCHBAR 0x0114
+#define MT_CLS_YOGABOOK9I 0x0115
#define MT_CLS_SIS 0x0457
#define MT_DEFAULT_MAXCONTACT 10
@@ -427,6 +429,14 @@ static const struct mt_class mt_classes[] = {
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE,
+ },
+ { .name = MT_CLS_YOGABOOK9I,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_FORCE_MULTI_INPUT |
+ MT_QUIRK_SEPARATE_APP_REPORT |
+ MT_QUIRK_HOVERING |
+ MT_QUIRK_YOGABOOK9I,
+ .export_all_inputs = true
},
{ }
};
@@ -1576,6 +1586,38 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
if (rdata && rdata->is_mt_collection)
return mt_touch_report(hid, rdata);
+ /* Lenovo Yoga Book 9i requires consuming and dropping certain bogus reports */
+ if (rdata && rdata->application &&
+ (rdata->application->quirks & MT_QUIRK_YOGABOOK9I)) {
+
+ bool all_zero_report = true;
+
+ for (int f = 0; f < report->maxfield && all_zero_report; f++) {
+ struct hid_field *fld = report->field[f];
+
+ for (int i = 0; i < fld->report_count; i++) {
+ unsigned int usage = fld->usage[i].hid;
+
+ if (usage == HID_DG_INRANGE ||
+ usage == HID_DG_TIPSWITCH ||
+ usage == HID_DG_BARRELSWITCH ||
+ usage == HID_DG_BARRELSWITCH2 ||
+ usage == HID_DG_CONTACTID ||
+ usage == HID_DG_TILT_X ||
+ usage == HID_DG_TILT_Y) {
+
+ if (fld->value[i] != 0) {
+ all_zero_report = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (all_zero_report)
+ return;
+ }
+
if (field && field->hidinput && field->hidinput->input)
input_sync(field->hidinput->input);
}
@@ -1772,6 +1814,30 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
break;
}
+ /* Lenovo Yoga Book 9i requires custom naming to allow differentiation in udev */
+ if (hi->report && td->mtclass.quirks & MT_QUIRK_YOGABOOK9I) {
+ switch (hi->report->id) {
+ case 48:
+ suffix = "Touchscreen Top";
+ break;
+ case 56:
+ suffix = "Touchscreen Bottom";
+ break;
+ case 20:
+ suffix = "Stylus Top";
+ break;
+ case 40:
+ suffix = "Stylus Bottom";
+ break;
+ case 80:
+ suffix = "Emulated Touchpad";
+ break;
+ default:
+ suffix = "";
+ break;
+ }
+ }
+
if (suffix) {
hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
"%s %s", hdev->name, suffix);
@@ -2277,6 +2343,12 @@ static const struct hid_device_id mt_devices[] = {
USB_VENDOR_ID_LENOVO,
USB_DEVICE_ID_LENOVO_X12_TAB2) },
+ /* Lenovo Yoga Book 9i */
+ { .driver_data = MT_CLS_YOGABOOK9I,
+ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_LENOVO,
+ USB_DEVICE_ID_LENOVO_YOGABOOK9I) },
+
/* Logitech devices */
{ .driver_data = MT_CLS_NSMU,
HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8,
--
2.51.0
^ permalink raw reply related
* [PATCH AUTOSEL 6.19-6.12] HID: logitech-hidpp: Add support for Logitech K980
From: Sasha Levin @ 2026-02-14 0:58 UTC (permalink / raw)
To: patches, stable
Cc: Bastien Nocera, Jiri Kosina, Sasha Levin, jikos, bentiss,
linux-input
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: Bastien Nocera <hadess@hadess.net>
[ Upstream commit af4fe07a9d963a72438ade96cf090e84b3399d0c ]
Add support for the solar-charging Logitech K980 keyboard, over
Bluetooth. Bolt traffic doesn't get routed through logitech-dj, so
this code isn't triggered when Bolt is used.
Signed-off-by: Bastien Nocera <hadess@hadess.net>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Analysis of HID: logitech-hidpp: Add support for Logitech K980
### Commit Message Analysis
The commit adds support for the Logitech K980 (Slim Solar+ keyboard)
over Bluetooth by adding its device ID to the `hidpp_devices` table in
the logitech-hidpp HID driver.
### Code Change Analysis
The change is a **two-line addition** of a new `HID_BLUETOOTH_DEVICE`
entry to the existing `hidpp_devices[]` table:
```c
{ /* Slim Solar+ K980 Keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
```
This is the textbook definition of a **new device ID addition** to an
existing driver. The driver (`hid-logitech-hidpp`) already exists in all
stable trees, and this just adds a Bluetooth product ID (0xb391) so the
kernel recognizes and properly handles this keyboard.
### Exception Category: New Device ID
This falls squarely into the "NEW DEVICE IDs" exception category for
stable backports:
- The driver already exists in stable trees
- Only a device ID is being added (no new code paths, no new functions)
- It's a trivial two-line addition to an ID table
- It enables an existing, well-tested driver to work with a specific
piece of hardware
### Risk Assessment
- **Risk: Extremely low.** Adding an entry to a device ID table cannot
break any existing functionality. The new entry only matches a
specific Logitech Bluetooth device (vendor 0x046d, product 0xb391). No
existing device matching is affected.
- **Scope: Minimal.** Two lines added, one file changed.
- **Dependencies: None.** This is completely self-contained.
### User Impact
Without this patch, users of the Logitech K980 keyboard over Bluetooth
won't get the hidpp driver's features (which for a solar keyboard
includes battery/charging status reporting). With this patch, the
keyboard is properly recognized and handled by the specialized Logitech
HID++ driver.
### Stability Considerations
- The commit was reviewed and applied by the HID subsystem maintainer
(Jiri Kosina)
- The pattern is identical to dozens of other device ID entries in the
same table
- Zero chance of regression for existing users
### Conclusion
This is a classic device ID addition — one of the most common and safest
types of stable backports. It enables hardware support for a specific
Logitech keyboard with zero risk to existing functionality. It meets all
stable criteria: obviously correct, small, tested, and fixes a real
issue (device not working with the appropriate driver).
**YES**
drivers/hid/hid-logitech-hidpp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index e871f1729d4b3..ca96102121b85 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4666,6 +4666,8 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb037) },
{ /* MX Anywhere 3SB mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
+ { /* Slim Solar+ K980 Keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) },
{}
};
--
2.51.0
^ permalink raw reply related
* [PATCH AUTOSEL 6.19-5.10] HID: multitouch: add eGalaxTouch EXC3188 support
From: Sasha Levin @ 2026-02-14 0:58 UTC (permalink / raw)
To: patches, stable
Cc: Thorsten Schmelzer, Michael Tretter, Jiri Kosina, Sasha Levin,
jikos, bentiss, linux-input
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: Thorsten Schmelzer <tschmelzer@topcon.com>
[ Upstream commit 8e4ac86b2ddd36fe501e20ecfcc080e536df1f48 ]
Add support for the for the EXC3188 touchscreen from eGalaxy.
Signed-off-by: Thorsten Schmelzer <tschmelzer@topcon.com>
Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Analysis
### Commit Message Analysis
The commit adds support for the eGalaxTouch EXC3188 touchscreen device
by adding a new USB device ID (0xC000) to the existing HID multitouch
driver. The commit message is straightforward: "Add support for the
EXC3188 touchscreen from eGalaxy."
### Code Change Analysis
The changes are minimal and confined to two files:
1. **`drivers/hid/hid-ids.h`**: Adds a single `#define` for the new
device ID:
```c
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000 0xc000
```
2. **`drivers/hid/hid-multitouch.c`**: Adds a 3-line entry to the
`mt_devices[]` device ID table:
```c
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000) },
```
The new device uses `MT_CLS_EGALAX_SERIAL`, which is an existing device
class already used by several other eGalax devices (A001, 73F7, 7349).
No new code paths, no new driver logic, no behavioral changes.
### Classification: New Device ID Addition
This falls squarely into the **"New Device IDs"** exception category for
stable backports:
- The driver (`hid-multitouch`) already exists in stable trees
- Only the device ID is new
- It uses an existing device class (`MT_CLS_EGALAX_SERIAL`)
- The pattern is identical to many other eGalax entries already in the
table
### Risk Assessment
- **Risk: Extremely low** — This is a pure device ID addition to an
existing table. It cannot affect any existing device. The new entry
only matches the specific USB vendor/product ID pair (0x0aec/0xc000).
- **Scope: Minimal** — 4 lines added across 2 files (1 define + 3 lines
in device table)
- **Dependencies: None** — Completely self-contained, no other commits
needed
### User Impact
Without this patch, users with the eGalaxTouch EXC3188 touchscreen have
a non-functional device. With this patch, the touchscreen works using
the existing, well-tested eGalax serial multitouch driver class. This is
exactly the kind of hardware enablement that stable users need — their
hardware simply doesn't work without it.
### Stability Indicators
- Uses existing driver infrastructure (no new code paths)
- Follows the exact same pattern as ~20 other eGalax device entries
- Signed off by the HID subsystem maintainer (Jiri Kosina)
- Has been reviewed and accepted through the normal HID subsystem
process
### Conclusion
This is a textbook example of a device ID addition that should be
backported to stable. It enables real hardware for real users, has zero
risk of regression, requires no dependencies, and follows established
patterns in the driver. These types of commits are explicitly called out
in stable kernel rules as appropriate for backporting.
**YES**
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-multitouch.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5a18cb41e6d79..6d8b64872cefe 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -437,6 +437,7 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000 0xc000
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002 0xc002
#define USB_VENDOR_ID_EDIFIER 0x2d99
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index f21850f7d89e4..7daa8f6d81870 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -2212,6 +2212,9 @@ static const struct hid_device_id mt_devices[] = {
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
+ { .driver_data = MT_CLS_EGALAX_SERIAL,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000) },
{ .driver_data = MT_CLS_EGALAX,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
--
2.51.0
^ permalink raw reply related
* [PATCH AUTOSEL 6.19-5.15] HID: elecom: Add support for ELECOM HUGE Plus M-HT1MRBK
From: Sasha Levin @ 2026-02-14 0:58 UTC (permalink / raw)
To: patches, stable
Cc: David Phillips, Jiri Kosina, Sasha Levin, jikos, bentiss,
linux-input
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: David Phillips <david@profile.sh>
[ Upstream commit b8e5fdf0bd022cd5493a5987ef66f5a24f8352d8 ]
New model in the ELECOM HUGE trackball line that has 8 buttons but the
report descriptor specifies only 5. The HUGE Plus supports connecting via
Bluetooth, 2.4GHz wireless USB dongle, and directly via a USB-C cable.
Each connection type reports a different device id, 01AA for cable,
01AB for USB dongle, and 01AC for Bluetooth.
This patch adds these device IDs and applies the fixups similar to the
other ELECOM devices to get all 8 buttons working for all 3 connection
types.
For reference, the usbhid-dump output:
001:013:001:DESCRIPTOR 1769085639.598405
05 01 09 02 A1 01 85 01 09 01 A1 00 05 09 19 01
29 05 15 00 25 01 75 01 95 05 81 02 75 03 95 01
81 01 05 01 09 30 09 31 16 01 80 26 FF 7F 75 10
95 02 81 06 09 38 15 81 25 7F 75 08 95 01 81 06
05 0C 0A 38 02 15 81 25 7F 75 08 95 01 81 06 C0
C0 05 0C 09 01 A1 01 85 02 15 01 26 8C 02 19 01
2A 8C 02 75 10 95 01 81 00 C0 05 01 09 80 A1 01
85 03 09 82 09 81 09 83 15 00 25 01 19 01 29 03
75 01 95 03 81 02 95 05 81 01 C0 06 01 FF 09 00
A1 01 85 08 09 00 15 00 26 FF 00 75 08 95 07 81
02 C0 06 02 FF 09 02 A1 01 85 06 09 02 15 00 26
FF 00 75 08 95 07 B1 02 C0
Signed-off-by: David Phillips <david@profile.sh>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Analysis
### Commit Message Analysis
This commit adds support for the ELECOM HUGE Plus trackball (M-HT1MRBK)
across three connection types (USB-C cable, 2.4GHz USB dongle,
Bluetooth). The device has 8 buttons but the HID report descriptor only
reports 5, so the driver applies a report descriptor fixup to expose all
8 buttons — the same pattern used for other ELECOM devices already
supported by this driver.
### Code Change Analysis
The changes span 4 files:
1. **`drivers/hid/hid-ids.h`**: Adds 3 new device ID defines (0x01aa,
0x01ab, 0x01ac) for the three connection types.
2. **`drivers/hid/hid-elecom.c`**:
- Adds a new case block in `elecom_report_fixup()` for the three new
device IDs, calling `mouse_button_fixup()` with appropriate offsets
(24, 28, 22, 16, 8). Note the offsets differ slightly from the
existing HUGE (M-HT1DRBK) which uses (22, 30, 24, 16, 8) — this is
because the HUGE Plus has a different report descriptor format as
shown in the commit message.
- Adds the three device IDs to `elecom_devices[]` table (USB for 01AA
and 01AB, Bluetooth for 01AC).
3. **`drivers/hid/hid-quirks.c`**: Adds the three device IDs to
`hid_have_special_driver[]` so the HID core knows to route these
devices to the elecom driver.
4. **`drivers/hid/Kconfig`**: Updates help text to mention the new
device.
### Classification
This is a **new device ID addition with report descriptor fixup** — one
of the explicitly allowed exception categories for stable backports. The
ELECOM HID driver already exists in stable trees, and this commit adds
IDs for a new variant of an existing product line (HUGE Plus vs HUGE),
applying the same `mouse_button_fixup()` mechanism already used by other
ELECOM devices.
### Scope and Risk Assessment
- **Lines changed**: Small — ~30 lines of meaningful additions across 4
files.
- **Risk**: Very low. The changes are purely additive (new device IDs +
new case in switch statement). They cannot affect any existing device
since they only trigger for the new device IDs. The
`mouse_button_fixup()` function is already well-tested with other
ELECOM devices.
- **Pattern**: Follows the exact same pattern as previous ELECOM device
additions (e.g., the HUGE M-HT1DRBK, DEFT M-DT2DRBK, etc.).
### User Impact
Without this patch, users of the ELECOM HUGE Plus trackball can only use
5 of 8 buttons. This is a real hardware functionality issue — the
device's report descriptor is broken (reports 5 buttons when 8 exist),
and the driver fixup is needed to make all buttons work. This affects
real users who purchased this trackball.
### Stability and Dependencies
- No dependencies on other commits.
- The `mouse_button_fixup()` function and the entire ELECOM driver
infrastructure exist in stable trees already.
- The patch is self-contained and applies cleanly.
- The different report descriptor offsets (24, 28, 22, 16 vs 22, 30, 24,
16 for older HUGE) are correctly derived from the actual descriptor
dump provided in the commit message.
### Conclusion
This is a textbook device ID addition to an existing driver with a
hardware quirk/fixup. It follows the same pattern as all other ELECOM
devices in the driver, is small and self-contained, fixes a real
hardware issue (only 5 of 8 buttons work), and carries essentially zero
risk of regression to existing devices. This falls squarely into the
"new device IDs / hardware quirks" exception category that is explicitly
allowed in stable.
**YES**
drivers/hid/Kconfig | 1 +
drivers/hid/hid-elecom.c | 16 ++++++++++++++++
drivers/hid/hid-ids.h | 3 +++
drivers/hid/hid-quirks.c | 3 +++
4 files changed, 23 insertions(+)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 920a64b66b25b..6ff4a3ad34cbf 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -369,6 +369,7 @@ config HID_ELECOM
- EX-G Trackballs (M-XT3DRBK, M-XT3URBK)
- DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK)
- HUGE Trackballs (M-HT1DRBK, M-HT1URBK)
+ - HUGE Plus Trackball (M-HT1MRBK)
config HID_ELO
tristate "ELO USB 4000/4500 touchscreen"
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
index 2003d2dcda7cc..37d88ce57f671 100644
--- a/drivers/hid/hid-elecom.c
+++ b/drivers/hid/hid-elecom.c
@@ -5,6 +5,7 @@
* - EX-G Trackballs (M-XT3DRBK, M-XT3URBK, M-XT4DRBK)
* - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK)
* - HUGE Trackballs (M-HT1DRBK, M-HT1URBK)
+ * - HUGE Plus Trackball (M-HT1MRBK)
*
* Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
* Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>
@@ -123,12 +124,25 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*/
mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8);
break;
+ case USB_DEVICE_ID_ELECOM_M_HT1MRBK:
+ case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB:
+ case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC:
+ /*
+ * Report descriptor format:
+ * 24: button bit count
+ * 28: padding bit count
+ * 22: button report size
+ * 16: button usage maximum
+ */
+ mouse_button_fixup(hdev, rdesc, *rsize, 24, 28, 22, 16, 8);
+ break;
}
return rdesc;
}
static const struct hid_device_id elecom_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) },
@@ -142,6 +156,8 @@ static const struct hid_device_id elecom_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) },
{ }
};
MODULE_DEVICE_TABLE(hid, elecom_devices);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 6d8b64872cefe..85ab1ac511096 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -466,6 +466,9 @@
#define USB_DEVICE_ID_ELECOM_M_HT1URBK_019B 0x019b
#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D 0x010d
#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C 0x011c
+#define USB_DEVICE_ID_ELECOM_M_HT1MRBK 0x01aa
+#define USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB 0x01ab
+#define USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC 0x01ac
#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
#define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 11438039cdb7f..3217e436c052c 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -420,6 +420,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_ELECOM)
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) },
@@ -432,6 +433,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) },
#endif
#if IS_ENABLED(CONFIG_HID_ELO)
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
--
2.51.0
^ permalink raw reply related
* [patch 1/1] drivers/input/misc/pf1550-onkey.c: fix build with CONFIG_PM_SLEEP=n
From: Andrew Morton @ 2026-02-14 0:38 UTC (permalink / raw)
To: sean, Frank.Li, akpm, linux-input, samuel.kayode, dmitry.torokhov,
akpm
From: Andrew Morton <akpm@linux-foundation.org>
Subject: drivers/input/misc/pf1550-onkey.c: fix build with CONFIG_PM_SLEEP=n
Date: Fri Feb 13 02:39:04 PM PST 2026
riscv randconfig:
drivers/input/misc/pf1550-onkey.c:154:12: error: 'pf1550_onkey_resume' defined but not used [-Werror=unused-function]
154 | static int pf1550_onkey_resume(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~
drivers/input/misc/pf1550-onkey.c:133:12: error: 'pf1550_onkey_suspend' defined but not used [-Werror=unused-function]
133 | static int pf1550_onkey_suspend(struct device *dev)
| ^~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Cc: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Frank Li <Frank.Li@nxp.com>
Cc: Sean Nyekjaer <sean@geanix.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
drivers/input/misc/pf1550-onkey.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/input/misc/pf1550-onkey.c~drivers-input-misc-pf1550-onkeyc-fix-build-with-config_pm_sleep=n
+++ a/drivers/input/misc/pf1550-onkey.c
@@ -130,6 +130,7 @@ static int pf1550_onkey_probe(struct pla
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int pf1550_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -175,6 +176,7 @@ static int pf1550_onkey_resume(struct de
static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
pf1550_onkey_resume);
+#endif CONFIG_PM_SLEEP
static const struct platform_device_id pf1550_onkey_id[] = {
{ "pf1550-onkey", },
_
^ permalink raw reply
* Re: [PATCH 5/5] input: drv260x: Don't try to disable dummy regulator
From: Yauhen Kharuzhy @ 2026-02-13 21:56 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <aY4QBqz4tadR2-Yt@google.com>
On Thu, Feb 12, 2026 at 09:41:04AM -0800, Dmitry Torokhov wrote:
> On Thu, Feb 12, 2026 at 01:46:55AM +0200, Yauhen Kharuzhy wrote:
> > Don't use a dummy regulator for 'vbat' because it cannot be disabled
> > during suspending.
>
> Why? Dummy regulator is supposed to be a placeholder that allows all the
> regular operations (enable/disable/etc) without having actually supply
> attached. Optional regulators are supposed to only be users when there
> are parts of a chip that are powered separately and may be not in use in
> a given design.
Hmm, I definitely had an issue with this. Will re-check.
Thanks for the review.
>
> This change is counter to the regulator framework.
>
> Thanks.
>
> --
> Dmitry
--
Yauhen Kharuzhy
^ permalink raw reply
* Re: [PATCH 4/5] input: drv260x: Stop waiting for GO bit clearing after timeout
From: Yauhen Kharuzhy @ 2026-02-13 21:00 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <aY4OAw_IMeta1z9e@google.com>
On Thu, Feb 12, 2026 at 09:34:51AM -0800, Dmitry Torokhov wrote:
> On Thu, Feb 12, 2026 at 01:46:54AM +0200, Yauhen Kharuzhy wrote:
> > If something goes wrong during effect playing or calibration, the GO bit
> > may not be cleared after some time, and the driver will get stuck.
> > To prevent this, add a timeout to the waiting loop.
> >
> > Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com>
> > ---
> > drivers/input/misc/drv260x.c | 12 ++++++++++++
> > 1 file changed, 12 insertions(+)
> >
> > diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
> > index f08a3d6c3ed8..f7bfac6d3973 100644
> > --- a/drivers/input/misc/drv260x.c
> > +++ b/drivers/input/misc/drv260x.c
> > @@ -173,6 +173,12 @@
> > #define DRV260X_AUTOCAL_TIME_500MS (2 << 4)
> > #define DRV260X_AUTOCAL_TIME_1000MS (3 << 4)
> >
> > +/*
> > + * Timeout for waiting for the GO status bit, in seconds. Should be reasonably
> > + * large to allow long-duration effects and a calibration cycle
> > + */
> > +#define DRV260X_GO_TIMEOUT_S 5
> > +
> > /**
> > * struct drv260x_data -
> > * @input_dev: Pointer to the input device
> > @@ -339,6 +345,7 @@ static int drv260x_init(struct drv260x_data *haptics)
> > {
> > int error;
> > unsigned int cal_buf;
> > + unsigned long timeout;
> > u8 id;
> >
> > error = regmap_read(haptics->regmap, DRV260X_STATUS, &cal_buf);
> > @@ -442,6 +449,7 @@ static int drv260x_init(struct drv260x_data *haptics)
> > return error;
> > }
> >
> > + timeout = jiffies + DRV260X_GO_TIMEOUT_S * HZ;
> > do {
> > usleep_range(15000, 15500);
> > error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
> > @@ -451,6 +459,10 @@ static int drv260x_init(struct drv260x_data *haptics)
> > error);
> > return error;
> > }
> > + if (jiffies - timeout <= 0) {
>
> time_after()
>
> > + dev_err(&haptics->client->dev, "GO timeout\n");
>
> This should be a warning, not error, since we are continuing.
>
> But actually, shouldn't we signal an error? This is probe path and if
> the controller does not ever signal readiness I do not think we should
> pretend that it will work.
Sounds reasonable. I got such a hang when selecting invalid mode/library
properties, and yes, it doesn't look like we can expect correct
functioning afterward. Will change to error.
>
> > + break;
> > + }
> > } while (cal_buf == DRV260X_GO_BIT);
>
> Thanks.
>
> --
> Dmitry
--
Yauhen Kharuzhy
^ permalink raw reply
* Re: [PATCH 3/5] input: drv260x: Check the device ID at initialization
From: Yauhen Kharuzhy @ 2026-02-13 20:53 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <aY4NfZm80ofkxzNW@google.com>
On Thu, Feb 12, 2026 at 09:28:51AM -0800, Dmitry Torokhov wrote:
> On Thu, Feb 12, 2026 at 01:46:53AM +0200, Yauhen Kharuzhy wrote:
> > To ensure that the device is accessible on the I2C bus, read the status
> > register and check the Device ID field in drv260x_init().
> >
> > Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com>
> > ---
> > drivers/input/misc/drv260x.c | 44 ++++++++++++++++++++++++++++++++++++
> > 1 file changed, 44 insertions(+)
> >
> > diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
> > index f613c81fa2ba..f08a3d6c3ed8 100644
> > --- a/drivers/input/misc/drv260x.c
> > +++ b/drivers/input/misc/drv260x.c
> > @@ -56,6 +56,13 @@
> > #define DRV260X_LRA_RES_PERIOD 0x22
> > #define DRV260X_MAX_REG 0x23
> >
> > +#define DRV260X_STATUS_ID_MASK 0xe0
> > +#define DRV260X_STATUS_ID_SHIFT 5
> > +#define DRV260X_ID_DRV2605 3
> > +#define DRV260X_ID_DRV2604 4
> > +#define DRV260X_ID_DRV2604L 6
> > +#define DRV260X_ID_DRV2605L 7
> > +
> > #define DRV260X_GO_BIT 0x01
> >
> > /* Library Selection */
> > @@ -305,10 +312,47 @@ static const struct reg_sequence drv260x_erm_cal_regs[] = {
> > { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
> > };
> >
> > +struct drv260x_id_map {
> > + u8 id;
> > + char *name;
> > +};
> > +
> > +static const struct drv260x_id_map drv_260x_devids[] = {
> > + { DRV260X_ID_DRV2605, "DRV2605"},
> > + { DRV260X_ID_DRV2604, "DRV2604"},
> > + { DRV260X_ID_DRV2604L, "DRV2604L"},
> > + { DRV260X_ID_DRV2605L, "DRV2605L"},
> > +};
> > +
> > +static char *drv260x_get_model(u8 id)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < ARRAY_SIZE(drv_260x_devids); i++)
> > + if (id == drv_260x_devids[i].id)
> > + return drv_260x_devids[i].name;
> > +
> > + return NULL;
> > +}
> > +
> > static int drv260x_init(struct drv260x_data *haptics)
> > {
> > int error;
> > unsigned int cal_buf;
> > + u8 id;
> > +
> > + error = regmap_read(haptics->regmap, DRV260X_STATUS, &cal_buf);
> > + if (error) {
> > + dev_err(&haptics->client->dev,
> > + "Failed to read DRV260X_status register: %d\n",
> > + error);
> > + return error;
> > + }
> > +
> > + id = (cal_buf & DRV260X_STATUS_ID_MASK) >> DRV260X_STATUS_ID_SHIFT;
> > +
> > + dev_info(&haptics->client->dev, "ID: %u (%s)\n", id,
> > + drv260x_get_model(id));
> >
> > error = regmap_write(haptics->regmap,
> > DRV260X_RATED_VOLT, haptics->rated_voltage);
>
> If the device is not available this regmap_write() will fail so I am not
> sure why we need all this new code.
Mostly for informational purposes about the detected model. Maybe you are
right, and this is unnecessary.
>
> Thanks.
>
> --
> Dmitry
--
Yauhen Kharuzhy
^ permalink raw reply
* Re: [PATCH 2/5] input: drv260x: Add support for ACPI-enumerated devices
From: Yauhen Kharuzhy @ 2026-02-13 20:48 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <aY4MqXG2zr01Pk4Q@google.com>
On Thu, Feb 12, 2026 at 09:26:24AM -0800, Dmitry Torokhov wrote:
> Hi Yauhen,
>
> On Thu, Feb 12, 2026 at 01:46:52AM +0200, Yauhen Kharuzhy wrote:
> > Add ACPI ids and GPIO lookup mapping for drv2604 haptics device.
> > Found in Lenovo Yoga Book YB1-X91L tablet.
> >
> > Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com>
> > ---
> > drivers/input/misc/drv260x.c | 30 ++++++++++++++++++++++++++++--
> > 1 file changed, 28 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
> > index 18360bdfe877..f613c81fa2ba 100644
> > --- a/drivers/input/misc/drv260x.c
> > +++ b/drivers/input/misc/drv260x.c
> > @@ -15,6 +15,7 @@
> > #include <linux/delay.h>
> > #include <linux/gpio/consumer.h>
> > #include <linux/regulator/consumer.h>
> > +#include <linux/acpi.h>
>
> Sort alphabetically please.
Sure.
>
> >
> > #include <dt-bindings/input/ti-drv260x.h>
> >
> > @@ -419,6 +420,12 @@ static const struct regmap_config drv260x_regmap_config = {
> > .cache_type = REGCACHE_NONE,
> > };
> >
> > +static const struct acpi_gpio_params enable_gpio = { 0, 0, false };
> > +static const struct acpi_gpio_mapping acpi_drv260x_default_gpios[] = {
> > + { "enable-gpio", &enable_gpio, 1 },
> > + { }
> > +};
>
> I'd rather move this ACPI/device-specifin handling into drivers/platform/x86/x86-android-tablets/lenovo.c
I am not sure if this is device-specific, but since there are no other
devices with a DRV260x ACPI entry, I may agree. Will move it.
>
> > +
> > static int drv260x_probe(struct i2c_client *client)
> > {
> > struct device *dev = &client->dev;
> > @@ -426,6 +433,14 @@ static int drv260x_probe(struct i2c_client *client)
> > u32 voltage;
> > int error;
> >
> > + if (has_acpi_companion(dev)) {
> > + error = devm_acpi_dev_add_driver_gpios(dev, acpi_drv260x_default_gpios);
> > + if (error) {
> > + dev_err(dev, "can't add GPIO ACPI mapping\n");
> > + return error;
> > + }
> > + }
> > +
> > haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
> > if (!haptics)
> > return -ENOMEM;
> > @@ -484,8 +499,10 @@ static int drv260x_probe(struct i2c_client *client)
> > return error;
> > }
> >
> > - haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
> > - GPIOD_OUT_HIGH);
> > + haptics->enable_gpio = devm_gpiod_get_optional(dev,
> > + "enable", GPIOD_OUT_HIGH);
>
> Why this change?
A good question. Looks like artifact from previous development
iterations, will remove it.
>
> > +
> > + dev_dbg(dev, "Enable gpio = 0x%p\n", haptics->enable_gpio);
>
> ?
Hmm, looks like a forgotten debug stuff, removing it.
--
Yauhen Kharuzhy
^ permalink raw reply
* Re: [PATCH v2 1/3] dt-bindings: power: reset: qcom-pon: Add new compatible PMM8654AU
From: Dmitry Baryshkov @ 2026-02-13 18:17 UTC (permalink / raw)
To: Rakesh Kota
Cc: Krzysztof Kozlowski, Sebastian Reichel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Dmitry Torokhov,
Courtney Cavin, Bjorn Andersson, Konrad Dybcio, linux-pm,
devicetree, linux-kernel, linux-arm-msm, linux-input
In-Reply-To: <20260210082612.3xakor2yo4h3dbra@hu-kotarake-hyd.qualcomm.com>
On Tue, Feb 10, 2026 at 01:56:12PM +0530, Rakesh Kota wrote:
> On Mon, Feb 09, 2026 at 02:49:24PM +0100, Krzysztof Kozlowski wrote:
> > On 09/02/2026 14:23, Rakesh Kota wrote:
> > > Add the compatible string "qcom,pmm8654au-pon" for the PMM8654AU PMIC.
> > > The PON peripheral on PMM8654AU is compatible with PMK8350, so it is
> > > documented as a fallback to "qcom,pmk8350-pon".
> >
> > Drop everything after ,. Do not explain WHAT you did. We see it.
> >
> > >
> > > While PMM8654AU supports additional registers compared to the baseline,
I can't find PMM8654AU either on Qualcomm.com or in the catalog. Is it
an actual name for the chip?
> >
> > full stop.
> >
> > > there is currently no active use case for these features. This specific
> > > compatible string reserves the identifier for future hardware-specific
> > > handling if required.
> >
> > All the rest is irrelevant or even wrong. We do not reserve identifiers.
> > If you want to reserve something, then I need to reject the patch.
> >
--
With best wishes
Dmitry
^ permalink raw reply
* [PATCH v2 2/2] Input: charlieplex_keypad: add GPIO charlieplex keypad
From: Hugo Villeneuve @ 2026-02-13 17:14 UTC (permalink / raw)
To: hvilleneuve, dmitry.torokhov, robh, krzk+dt, conor+dt
Cc: linux-input, devicetree, linux-kernel, hugo
In-Reply-To: <20260213171431.2228814-1-hugo@hugovil.com>
From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Add support for GPIO-based charlieplex keypad, allowing to control
N^2-N keys using N GPIO lines.
Reuse matrix keypad keymap to simplify, even if there is no concept
of rows and columns in this type of keyboard.
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
---
MAINTAINERS | 7 +
drivers/input/keyboard/Kconfig | 14 ++
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/charlieplex_keypad.c | 213 ++++++++++++++++++++
4 files changed, 235 insertions(+)
create mode 100644 drivers/input/keyboard/charlieplex_keypad.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ed6d11a77466..0b2d71f32b400 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5765,6 +5765,13 @@ S: Maintained
F: Documentation/hwmon/powerz.rst
F: drivers/hwmon/powerz.c
+CHARLIEPLEX KEYPAD DRIVER
+M: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+S: Supported
+W: http://www.mosaic-industries.com/embedded-systems/microcontroller-projects/electronic-circuits/matrix-keypad-scan-decode
+F: Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml
+F: drivers/input/keyboard/charlieplex_keypad.c
+
CHECKPATCH
M: Andy Whitcroft <apw@canonical.com>
M: Joe Perches <joe@perches.com>
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 2ff4fef322c24..ae54b4b7e2d8a 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -289,6 +289,20 @@ config KEYBOARD_MATRIX
To compile this driver as a module, choose M here: the
module will be called matrix_keypad.
+config KEYBOARD_CHARLIEPLEX
+ tristate "GPIO driven chearlieplex keypad support"
+ depends on GPIOLIB || COMPILE_TEST
+ select INPUT_MATRIXKMAP
+ help
+ Enable support for GPIO driven charlieplex keypad. A charlieplex
+ keypad allows to use fewer GPIO lines to interface to key switches.
+ For example, an N lines charlieplex keypad can be used to interface
+ to N^2-N different key switches. However, this type of keypad
+ cannot detect more than one key press at a time.
+
+ To compile this driver as a module, choose M here: the
+ module will be called charlieplex_keypad.
+
config KEYBOARD_HIL_OLD
tristate "HP HIL keyboard support (simple driver)"
depends on GSC || HP300
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 2d906e14f3e27..40b5cf5d374d2 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
+obj-$(CONFIG_KEYBOARD_CHARLIEPLEX) += charlieplex_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7360) += max7360-keypad.o
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
diff --git a/drivers/input/keyboard/charlieplex_keypad.c b/drivers/input/keyboard/charlieplex_keypad.c
new file mode 100644
index 0000000000000..81e8b6b96dab1
--- /dev/null
+++ b/drivers/input/keyboard/charlieplex_keypad.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * GPIO driven charlieplex keypad driver
+ *
+ * Copyright (c) 2025 Hugo Villeneuve <hvilleneuve@dimonoff.com>
+ *
+ * Based on matrix_keyboard.c
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/types.h>
+
+struct charlieplex_keypad {
+ struct input_dev *input_dev;
+ struct gpio_descs *line_gpios;
+ unsigned int nlines;
+ unsigned int line_scan_delay_us;
+ unsigned int debounce_threshold;
+ unsigned int debounce_count;
+ int debounce_code;
+ int current_code;
+};
+
+static void charlieplex_keypad_report_key(struct input_dev *input)
+{
+ struct charlieplex_keypad *keypad = input_get_drvdata(input);
+ const unsigned short *keycodes = input->keycode;
+
+ if (keypad->current_code > 0) {
+ input_event(input, EV_MSC, MSC_SCAN, keypad->current_code);
+ input_report_key(input, keycodes[keypad->current_code], 0);
+ }
+
+ if (keypad->debounce_code) {
+ input_event(input, EV_MSC, MSC_SCAN, keypad->debounce_code);
+ input_report_key(input, keycodes[keypad->debounce_code], 1);
+ }
+
+ input_sync(input);
+ keypad->current_code = keypad->debounce_code;
+}
+
+static void charlieplex_keypad_check_switch_change(struct input_dev *input,
+ int code)
+{
+ struct charlieplex_keypad *keypad = input_get_drvdata(input);
+
+ if (code != keypad->debounce_code) {
+ keypad->debounce_count = 0;
+ keypad->debounce_code = code;
+ } else if (keypad->debounce_count < keypad->debounce_threshold) {
+ keypad->debounce_count++;
+
+ if (keypad->debounce_count >= keypad->debounce_threshold &&
+ keypad->debounce_code != keypad->current_code)
+ charlieplex_keypad_report_key(input);
+ }
+}
+
+static void charlieplex_keypad_poll(struct input_dev *input)
+{
+ struct charlieplex_keypad *keypad = input_get_drvdata(input);
+ int oline;
+ int code;
+
+ for (code = 0, oline = 0; oline < keypad->nlines; oline++) {
+ DECLARE_BITMAP(values, MATRIX_MAX_ROWS);
+ int iline;
+ int rc;
+
+ /* Activate only one line as output at a time. */
+ gpiod_direction_output(keypad->line_gpios->desc[oline], 1);
+
+ if (keypad->line_scan_delay_us)
+ fsleep(keypad->line_scan_delay_us);
+
+ /* Read input on all other lines. */
+ rc = gpiod_get_array_value_cansleep(keypad->line_gpios->ndescs,
+ keypad->line_gpios->desc,
+ keypad->line_gpios->info, values);
+ if (rc)
+ return;
+
+ for (iline = 0; iline < keypad->nlines; iline++) {
+ if (iline == oline)
+ continue; /* Do not read active output line. */
+
+ /* Check if GPIO is asserted. */
+ if (test_bit(iline, values)) {
+ code = MATRIX_SCAN_CODE(oline, iline,
+ get_count_order(keypad->nlines));
+ /*
+ * Exit loop immediately since we cannot detect
+ * more than one key press at a time.
+ */
+ break;
+ }
+ }
+
+ gpiod_direction_input(keypad->line_gpios->desc[oline]);
+
+ if (code)
+ break;
+ }
+
+ charlieplex_keypad_check_switch_change(input, code);
+}
+
+static int charlieplex_keypad_init_gpio(struct platform_device *pdev,
+ struct charlieplex_keypad *keypad)
+{
+ int i;
+
+ keypad->line_gpios = devm_gpiod_get_array(&pdev->dev, "line", GPIOD_IN);
+ if (IS_ERR(keypad->line_gpios))
+ return PTR_ERR(keypad->line_gpios);
+
+ keypad->nlines = keypad->line_gpios->ndescs;
+
+ if (keypad->nlines > MATRIX_MAX_ROWS)
+ return -EINVAL;
+
+ for (i = 0; i < keypad->nlines; i++)
+ gpiod_set_consumer_name(keypad->line_gpios->desc[i], "charlieplex_kbd_line");
+
+ return 0;
+}
+
+static int charlieplex_keypad_probe(struct platform_device *pdev)
+{
+ struct charlieplex_keypad *keypad;
+ unsigned int debounce_interval_ms;
+ unsigned int poll_interval_ms;
+ struct input_dev *input_dev;
+ int err;
+
+ keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
+ if (!keypad)
+ return -ENOMEM;
+
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ keypad->input_dev = input_dev;
+
+ device_property_read_u32(&pdev->dev, "poll-interval", &poll_interval_ms);
+ device_property_read_u32(&pdev->dev, "debounce-delay-ms", &debounce_interval_ms);
+ device_property_read_u32(&pdev->dev, "line-scan-delay-us", &keypad->line_scan_delay_us);
+
+ keypad->current_code = -1;
+ keypad->debounce_code = -1;
+ keypad->debounce_threshold = DIV_ROUND_UP(debounce_interval_ms, poll_interval_ms);
+
+ err = charlieplex_keypad_init_gpio(pdev, keypad);
+ if (err)
+ return err;
+
+ input_dev->name = pdev->name;
+ input_dev->id.bustype = BUS_HOST;
+
+ err = matrix_keypad_build_keymap(NULL, NULL, keypad->nlines,
+ keypad->nlines, NULL, input_dev);
+ if (err)
+ dev_err_probe(&pdev->dev, -ENOMEM, "failed to build keymap\n");
+
+ if (device_property_read_bool(&pdev->dev, "autorepeat"))
+ __set_bit(EV_REP, input_dev->evbit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ err = input_setup_polling(input_dev, charlieplex_keypad_poll);
+ if (err)
+ dev_err_probe(&pdev->dev, err, "unable to set up polling\n");
+
+ input_set_poll_interval(input_dev, poll_interval_ms);
+
+ input_set_drvdata(input_dev, keypad);
+
+ err = input_register_device(keypad->input_dev);
+ if (err)
+ return err;
+
+ platform_set_drvdata(pdev, keypad);
+
+ return 0;
+}
+
+static const struct of_device_id charlieplex_keypad_dt_match[] = {
+ { .compatible = "gpio-charlieplex-keypad" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, charlieplex_keypad_dt_match);
+
+static struct platform_driver charlieplex_keypad_driver = {
+ .probe = charlieplex_keypad_probe,
+ .driver = {
+ .name = "charlieplex-keypad",
+ .of_match_table = of_match_ptr(charlieplex_keypad_dt_match),
+ },
+};
+module_platform_driver(charlieplex_keypad_driver);
+
+MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>");
+MODULE_DESCRIPTION("GPIO driven charlieplex keypad driver");
+MODULE_LICENSE("GPL");
--
2.47.3
^ permalink raw reply related
* [PATCH v2 1/2] dt-bindings: input: add GPIO charlieplex keypad
From: Hugo Villeneuve @ 2026-02-13 17:14 UTC (permalink / raw)
To: hvilleneuve, dmitry.torokhov, robh, krzk+dt, conor+dt
Cc: linux-input, devicetree, linux-kernel, hugo
In-Reply-To: <20260213171431.2228814-1-hugo@hugovil.com>
From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Add DT bindings for GPIO charlieplex keypad.
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
---
.../input/gpio-charlieplex-keypad.yaml | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml
diff --git a/Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml b/Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml
new file mode 100644
index 0000000000000..1672491a75a85
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/input/gpio-charlieplex-keypad.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GPIO charlieplex keypad
+
+maintainers:
+ - Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+description:
+ The charlieplex keypad supports N^2)-N different key combinations (where N is
+ the number of lines). Key presses and releases are detected by configuring
+ only one line as output at a time, and reading other line states. This process
+ is repeated for each line.
+ This mechanism doesn't allow to detect simultaneous key presses.
+
+allOf:
+ - $ref: input.yaml#
+ - $ref: /schemas/input/matrix-keymap.yaml#
+
+properties:
+ compatible:
+ const: gpio-charlieplex-keypad
+
+ autorepeat: true
+
+ line-scan-delay-us:
+ description:
+ Delay, measured in microseconds, that is needed
+ before we can scan keypad after activating one line.
+ default: 0
+
+ line-gpios:
+ description:
+ List of GPIOs used as lines. The gpio specifier for this property
+ depends on the gpio controller to which these lines are connected.
+
+ linux,keymap: true
+
+ debounce-delay-ms:
+ description: Debounce interval in milliseconds.
+ default: 5
+
+ poll-interval: true
+
+ wakeup-source: true
+
+required:
+ - compatible
+ - line-gpios
+ - linux,keymap
+ - poll-interval
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/input/input.h>
+
+ charlieplex-keypad {
+ compatible = "gpio-charlieplex-keypad";
+ debounce-delay-ms = <20>;
+ poll-interval = <5>;
+ line-scan-delay-us = <2>;
+
+ line-gpios = <&gpio2 25 0
+ &gpio2 26 0
+ &gpio2 27 0>;
+
+ /* MATRIX_KEY(output, input, key-code) */
+ linux,keymap = <
+ MATRIX_KEY(0, 1, KEY_F1)
+ MATRIX_KEY(0, 2, KEY_F2)
+ MATRIX_KEY(1, 0, KEY_F3)
+ MATRIX_KEY(1, 2, KEY_F4)
+ MATRIX_KEY(2, 0, KEY_F5)
+ MATRIX_KEY(2, 1, KEY_F6)
+ >;
+ };
--
2.47.3
^ permalink raw reply related
* [PATCH v2 0/2] input: add GPIO-based charlieplex keypad
From: Hugo Villeneuve @ 2026-02-13 17:14 UTC (permalink / raw)
To: hvilleneuve, dmitry.torokhov, robh, krzk+dt, conor+dt
Cc: linux-input, devicetree, linux-kernel, hugo
From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Hello,
this patch series add a new GPIO charlieplex keypad driver.
I have tested the driver on a custom board with a Solidrun RZ/G2LC SOM
with three charlieplex keyboards, all connected thru a a PCA9416 I2C GPIO
expander.
Link: [v1] https://lore.kernel.org/linux-serial/20250924153740.806444-1-hugo@hugovil.com/raw
Changes for v2:
- Fix yamllint error for example
- Remove unused debug variable (nkeys)
- Remove support for custom linux,no-autorepeat DT property
- Remove support for custom gpio-activelow DT property
Thank you.
Hugo Villeneuve (2):
dt-bindings: input: add GPIO charlieplex keypad
Input: charlieplex_keypad: add GPIO charlieplex keypad
.../input/gpio-charlieplex-keypad.yaml | 82 +++++++
MAINTAINERS | 7 +
drivers/input/keyboard/Kconfig | 14 ++
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/charlieplex_keypad.c | 213 ++++++++++++++++++
5 files changed, 317 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml
create mode 100644 drivers/input/keyboard/charlieplex_keypad.c
base-commit: ed8a4ef29da3821ee3155d3b1925fa67fc92aae2
--
2.47.3
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: input: add GPIO charlieplex keypad
From: Hugo Villeneuve @ 2026-02-13 16:26 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: hvilleneuve, robh, krzk+dt, conor+dt, linux-input, devicetree,
linux-kernel
In-Reply-To: <aYRg2vP4Lfqm61qH@google.com>
On Thu, 5 Feb 2026 01:24:05 -0800
Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote:
Hi Dmitry,
> Hi Hugo,
>
> On Tue, Feb 03, 2026 at 10:49:47AM -0500, Hugo Villeneuve wrote:
> > From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> >
> > Add DT bindings for GPIO charlieplex keypad.
> >
>
> ...
>
> > + linux,no-autorepeat:
> > + type: boolean
> > + description: Do not enable autorepeat feature.
>
> Let's use standard "autorepeat" property to enable autorepeat when
> needed.
Ok, I based my binding/driver on gpio-matrix-keypad, which had
linux,no-autorepeat.
I will change that in V2 (along with driver source code changes).
>
> > +
> > + gpio-activelow:
> > + type: boolean
> > + description:
> > + Force GPIO polarity to active low.
> > + In the absence of this property GPIOs are treated as active high.
>
> No, the polarity should be encoded in individual GPIOs, not via a
> separate property.
You are right, again "contamination" from gpio-matrix-keypad :)
I will also change that in V2 (along with driver source code changes).
Thank you,
Hugo.
^ permalink raw reply
* [PATCH v2] bcm5974: recover from failed mode switch
From: Liam Mitchell @ 2026-02-13 9:25 UTC (permalink / raw)
To: Henrik Rydberg, Dmitry Torokhov; +Cc: linux-input, linux-kernel, Liam Mitchell
Mode switches sent before control response are ignored.
On receiving unknown 8-byte packets, assume that mode switch was ignored
and reset by switching to normal mode, waiting then switching back to
wellspring mode.
---
This patch addresses an issue where the bcm5974 driver switches modes
before the device is ready, resulting in an unresponsive trackpad and
"bcm5974: bad trackpad package, length: 8" repeated in logs.
Discussion of issue in the thread:
https://lore.kernel.org/linux-input/CAOQ1CL4+DP1TuLAGNsz5GdFBTHvnTg=5q=Dr2Z1OQc6RXydSYA@mail.gmail.com/
This fix is conservative, avoiding changing existing mode-switch
behavior because I cannot test all variations of hardware.
On receiving an unknown 8-byte packet, we assume the device is not in
wellspring mode and schedule an asynchronous mode reset.
Signed-off-by: Liam Mitchell <mitchell.liam@gmail.com>
Link: https://lore.kernel.org/linux-input/CAOQ1CL4+DP1TuLAGNsz5GdFBTHvnTg=5q=Dr2Z1OQc6RXydSYA@mail.gmail.com/
---
Changes in v2:
- mutex_lock -> guard(mutex)
- dprintk -> dev_err
- msleep -> fsleep
- removed 0 init
- cancel_work_sync -> disable_delayed_work_sync
- work_struct -> delayed_work
- Link to v1: https://lore.kernel.org/r/20260207-bcm5974-reset-v1-1-af7163903fa6@gmail.com
---
drivers/input/mouse/bcm5974.c | 40 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index dfdfb59cc8b5..6ee766ed8402 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -286,6 +286,8 @@ struct bcm5974 {
const struct tp_finger *index[MAX_FINGERS]; /* finger index data */
struct input_mt_pos pos[MAX_FINGERS]; /* position array */
int slots[MAX_FINGERS]; /* slot assignments */
+ struct delayed_work mode_reset_work;
+ unsigned long last_mode_reset;
};
/* trackpad finger block data, le16-aligned */
@@ -696,6 +698,32 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
return retval;
}
+/*
+ * Mode switches sent before the control response are ignored.
+ * Fixing this state requires switching to normal mode and waiting
+ * about 1ms before switching back to wellspring mode.
+ */
+static void bcm5974_mode_reset_work(struct work_struct *work)
+{
+ int error;
+ struct bcm5974 *dev = container_of(work, struct bcm5974, mode_reset_work.work);
+
+ guard(mutex)(&dev->pm_mutex);
+ dev->last_mode_reset = jiffies;
+
+ error = bcm5974_wellspring_mode(dev, false);
+ if (error) {
+ dev_err(&dev->intf->dev, "reset to normal mode failed\n");
+ return;
+ }
+
+ fsleep(1000);
+
+ error = bcm5974_wellspring_mode(dev, true);
+ if (error)
+ dev_err(&dev->intf->dev, "mode switch after reset failed\n");
+}
+
static void bcm5974_irq_button(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
@@ -752,10 +780,18 @@ static void bcm5974_irq_trackpad(struct urb *urb)
if (dev->tp_urb->actual_length == 2)
goto exit;
- if (report_tp_state(dev, dev->tp_urb->actual_length))
+ if (report_tp_state(dev, dev->tp_urb->actual_length)) {
dprintk(1, "bcm5974: bad trackpad package, length: %d\n",
dev->tp_urb->actual_length);
+ /* HID packet means we aren't in wellspring mode */
+ /* If we haven't tried a reset in the last second, try now */
+ if (dev->tp_urb->actual_length == 8 &&
+ time_after(jiffies, dev->last_mode_reset + msecs_to_jiffies(1000))) {
+ schedule_delayed_work(&dev->mode_reset_work, 0);
+ }
+ }
+
exit:
error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
if (error)
@@ -906,6 +942,7 @@ static int bcm5974_probe(struct usb_interface *iface,
dev->intf = iface;
dev->input = input_dev;
dev->cfg = *cfg;
+ INIT_DELAYED_WORK(&dev->mode_reset_work, bcm5974_mode_reset_work);
mutex_init(&dev->pm_mutex);
/* setup urbs */
@@ -998,6 +1035,7 @@ static void bcm5974_disconnect(struct usb_interface *iface)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
+ disable_delayed_work_sync(&dev->mode_reset_work);
usb_set_intfdata(iface, NULL);
input_unregister_device(dev->input);
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20260207-bcm5974-reset-85ccdfca9641
Best regards,
--
Liam Mitchell <mitchell.liam@gmail.com>
^ permalink raw reply related
* Re: [PATCH v2 08/11] dt-bindings: mfd: motorola-cpcap: convert to DT schema
From: Svyatoslav Ryhel @ 2026-02-13 7:23 UTC (permalink / raw)
To: Rob Herring
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
Pavel Machek, Liam Girdwood, Mark Brown, Dixit Parmar,
Tony Lindgren, linux-iio, devicetree, linux-kernel, linux-input,
linux-leds
In-Reply-To: <CAL_JsqLcFAP7oP0KzLp7DfcCpz0DjsjoAW3PcfnWu2nc-dG1CQ@mail.gmail.com>
чт, 12 лют. 2026 р. о 22:19 Rob Herring <robh@kernel.org> пише:
>
> On Wed, Feb 11, 2026 at 11:30 PM Svyatoslav Ryhel <clamor95@gmail.com> wrote:
> >
> >
> >
> > 11 лютого 2026 р. 23:20:16 GMT+02:00, Rob Herring <robh@kernel.org> пише:
> > >On Fri, Feb 06, 2026 at 07:28:42PM +0200, Svyatoslav Ryhel wrote:
> > >> Convert devicetree bindings for the Motorola CPCAP MFD from TXT to YAML.
> > >>
> > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > >> ---
> > >> .../bindings/mfd/motorola,cpcap.yaml | 411 ++++++++++++++++++
> > >> .../bindings/mfd/motorola-cpcap.txt | 78 ----
> > >> 2 files changed, 411 insertions(+), 78 deletions(-)
> > >> create mode 100644 Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
> > >> delete mode 100644 Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
> > >>
> > >> diff --git a/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
> > >> new file mode 100644
> > >> index 000000000000..7e350721d9f6
> > >> --- /dev/null
> > >> +++ b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
> > >> @@ -0,0 +1,411 @@
> > >> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > >> +%YAML 1.2
> > >> +---
> > >> +$id: http://devicetree.org/schemas/mfd/motorola,cpcap.yaml#
> > >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > >> +
> > >> +title: Motorola CPCAP PMIC MFD
> > >> +
> > >> +maintainers:
> > >> + - Svyatoslav Ryhel <clamor95@gmail.com>
> > >> +
> > >> +allOf:
> > >> + - $ref: /schemas/spi/spi-peripheral-props.yaml#
> > >> +
> > >> +properties:
> > >> + compatible:
> > >> + enum:
> > >> + - motorola,cpcap
> > >> + - st,6556002
> > >
> > >This does not match the only user in the kernel .dts files as
> > >"st,6556002" should be a fallback.
> > >
> >
> > Honestly, I would remove st,6556002 since it is not the only cpcap model which can be used, hence it cannot serve as a universal fallback. Some devices use ST produced cpcap chips, others use TI and range of models varies too. I guess I have to multiply commits.
>
> The "cap" name goes way back to at least 2G Motorola phones. There
> were whitecap and redcap chips for different 2G technologies which got
> replaced by patriot (red+white+blue I guess) for 2.5G.
>
> Dropping is fine with me, but then you have to update the .dtsi. If it
> was me, I'd just make the binding match because that's 1 patch instead
> of 2. You can still drop it on the new compatibles you are adding.
>
Yeah, you are right. I will preserve st,6556002 fallback for
motorola,cpcap while Mapphone and Mot would not require this fallback.
Thank you for suggestion and for the cpcap's origin.
> Rob
^ permalink raw reply
* [PATCH v2] HID: winwing: Enable rumble effects
From: Ivan Gorinov @ 2026-02-13 5:30 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input, linux-kernel
Enable rumble motor control on TGRIP-15E and TGRIP-15EX throttle grips
by sending haptic feedback commands (EV_FF events) to the input device.
Signed-off-by: Ivan Gorinov <linux-kernel@altimeter.info>
---
Changes since v1:
- Fix possible NULL pointer dereference
drivers/hid/hid-winwing.c | 184 +++++++++++++++++++++++++++++++++++---
1 file changed, 170 insertions(+), 14 deletions(-)
diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c
index ab65dc12d1e0..b5d0978d81e5 100644
--- a/drivers/hid/hid-winwing.c
+++ b/drivers/hid/hid-winwing.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#define MAX_REPORT 16
@@ -35,10 +36,14 @@ static const struct winwing_led_info led_info[3] = {
struct winwing_drv_data {
struct hid_device *hdev;
- __u8 *report_buf;
- struct mutex lock;
- int map_more_buttons;
- unsigned int num_leds;
+ struct mutex lights_lock;
+ __u8 *report_lights;
+ __u8 *report_rumble;
+ struct work_struct rumble_work;
+ struct ff_rumble_effect rumble;
+ int rumble_left;
+ int rumble_right;
+ int has_grip15;
struct winwing_led leds[];
};
@@ -47,10 +52,10 @@ static int winwing_led_write(struct led_classdev *cdev,
{
struct winwing_led *led = (struct winwing_led *) cdev;
struct winwing_drv_data *data = hid_get_drvdata(led->hdev);
- __u8 *buf = data->report_buf;
+ __u8 *buf = data->report_lights;
int ret;
- mutex_lock(&data->lock);
+ mutex_lock(&data->lights_lock);
buf[0] = 0x02;
buf[1] = 0x60;
@@ -69,7 +74,7 @@ static int winwing_led_write(struct led_classdev *cdev,
ret = hid_hw_output_report(led->hdev, buf, 14);
- mutex_unlock(&data->lock);
+ mutex_unlock(&data->lights_lock);
return ret;
}
@@ -87,9 +92,9 @@ static int winwing_init_led(struct hid_device *hdev,
if (!data)
return -EINVAL;
- data->report_buf = devm_kmalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL);
+ data->report_lights = devm_kzalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL);
- if (!data->report_buf)
+ if (!data->report_lights)
return -ENOMEM;
for (i = 0; i < 3; i += 1) {
@@ -117,7 +122,7 @@ static int winwing_init_led(struct hid_device *hdev,
return ret;
}
-static int winwing_map_button(int button, int map_more_buttons)
+static int winwing_map_button(int button, int has_grip15)
{
if (button < 1)
return KEY_RESERVED;
@@ -141,7 +146,7 @@ static int winwing_map_button(int button, int map_more_buttons)
return (button - 65) + BTN_TRIGGER_HAPPY17;
}
- if (!map_more_buttons) {
+ if (!has_grip15) {
/*
* Not mapping numbers [33 .. 64] which
* are not assigned to any real buttons
@@ -194,13 +199,141 @@ static int winwing_input_mapping(struct hid_device *hdev,
/* Button numbers start with 1 */
button = usage->hid & HID_USAGE;
- code = winwing_map_button(button, data->map_more_buttons);
+ code = winwing_map_button(button, data->has_grip15);
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
return 1;
}
+/*
+ * If x ≤ 0, return 0;
+ * if x is in [1 .. 65535], return a value in [1 .. 255]
+ */
+static inline int convert_magnitude(int x)
+{
+ if (x < 1)
+ return 0;
+
+ return ((x * 255) >> 16) + 1;
+}
+
+static int winwing_haptic_rumble(struct winwing_drv_data *data)
+{
+ __u8 *buf;
+ __u8 m;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!data->hdev)
+ return -EINVAL;
+
+ buf = data->report_rumble;
+
+ if (!buf)
+ return -EINVAL;
+
+ m = convert_magnitude(data->rumble.strong_magnitude);
+ if (m != data->rumble_left) {
+ int ret;
+
+ buf[0] = 0x02;
+ buf[1] = 0x01;
+ buf[2] = 0xbf;
+ buf[3] = 0x00;
+ buf[4] = 0x00;
+ buf[5] = 0x03;
+ buf[6] = 0x49;
+ buf[7] = 0x00;
+ buf[8] = m;
+ buf[9] = 0x00;
+ buf[10] = 0;
+ buf[11] = 0;
+ buf[12] = 0;
+ buf[13] = 0;
+
+ ret = hid_hw_output_report(data->hdev, buf, 14);
+ if (ret < 0) {
+ hid_err(data->hdev, "error %d (%*ph)\n", ret, 14, buf);
+ return ret;
+ }
+ data->rumble_left = m;
+ }
+
+ m = convert_magnitude(data->rumble.weak_magnitude);
+ if (m != data->rumble_right) {
+ int ret;
+
+ buf[0] = 0x02;
+ buf[1] = 0x03;
+ buf[2] = 0xbf;
+ buf[3] = 0x00;
+ buf[4] = 0x00;
+ buf[5] = 0x03;
+ buf[6] = 0x49;
+ buf[7] = 0x00;
+ buf[8] = m;
+ buf[9] = 0x00;
+ buf[10] = 0;
+ buf[11] = 0;
+ buf[12] = 0;
+ buf[13] = 0;
+
+ ret = hid_hw_output_report(data->hdev, buf, 14);
+ if (ret < 0) {
+ hid_err(data->hdev, "error %d (%*ph)\n", ret, 14, buf);
+ return ret;
+ }
+ data->rumble_right = m;
+ }
+
+ return 0;
+}
+
+
+static void winwing_haptic_rumble_cb(struct work_struct *work)
+{
+ struct winwing_drv_data *data;
+
+ data = container_of(work, struct winwing_drv_data, rumble_work);
+ winwing_haptic_rumble(data);
+}
+
+static int winwing_play_effect(struct input_dev *dev, void *context,
+ struct ff_effect *effect)
+{
+ struct winwing_drv_data *data = (struct winwing_drv_data *) context;
+
+ if (effect->type != FF_RUMBLE)
+ return 0;
+
+ if (!data)
+ return -EINVAL;
+
+ data->rumble = effect->u.rumble;
+
+ return schedule_work(&data->rumble_work);
+}
+
+static int winwing_init_ff(struct hid_device *hdev, struct hid_input *hidinput)
+{
+ struct winwing_drv_data *data;
+
+ data = (struct winwing_drv_data *) hid_get_drvdata(hdev);
+ if (!data)
+ return -EINVAL;
+
+ data->report_rumble = devm_kzalloc(&hdev->dev, MAX_REPORT, GFP_KERNEL);
+ data->rumble_left = -1;
+ data->rumble_right = -1;
+
+ input_set_capability(hidinput->input, EV_FF, FF_RUMBLE);
+
+ return input_ff_create_memless(hidinput->input, data,
+ winwing_play_effect);
+}
+
static int winwing_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
@@ -219,10 +352,12 @@ static int winwing_probe(struct hid_device *hdev,
if (!data)
return -ENOMEM;
- data->map_more_buttons = id->driver_data;
-
+ data->hdev = hdev;
+ data->has_grip15 = id->driver_data;
hid_set_drvdata(hdev, data);
+ INIT_WORK(&data->rumble_work, winwing_haptic_rumble_cb);
+
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
@@ -232,19 +367,39 @@ static int winwing_probe(struct hid_device *hdev,
return 0;
}
+static void winwing_remove(struct hid_device *hdev)
+{
+ struct winwing_drv_data *data;
+
+ data = (struct winwing_drv_data *) hid_get_drvdata(hdev);
+
+ if (data)
+ cancel_work_sync(&data->rumble_work);
+
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+}
+
static int winwing_input_configured(struct hid_device *hdev,
struct hid_input *hidinput)
{
+ struct winwing_drv_data *data;
int ret;
+ data = (struct winwing_drv_data *) hid_get_drvdata(hdev);
+
ret = winwing_init_led(hdev, hidinput->input);
if (ret)
hid_err(hdev, "led init failed\n");
+ if (data->has_grip15)
+ winwing_init_ff(hdev, hidinput);
+
return ret;
}
+/* Set driver_data to 1 for grips with rumble motor and more than 32 buttons */
static const struct hid_device_id winwing_devices[] = {
{ HID_USB_DEVICE(0x4098, 0xbd65), .driver_data = 1 }, /* TGRIP-15E */
{ HID_USB_DEVICE(0x4098, 0xbd64), .driver_data = 1 }, /* TGRIP-15EX */
@@ -261,6 +416,7 @@ static struct hid_driver winwing_driver = {
.input_configured = winwing_input_configured,
.input_mapping = winwing_input_mapping,
.probe = winwing_probe,
+ .remove = winwing_remove,
};
module_hid_driver(winwing_driver);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2 08/11] dt-bindings: mfd: motorola-cpcap: convert to DT schema
From: Rob Herring @ 2026-02-12 20:19 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov, Lee Jones,
Pavel Machek, Liam Girdwood, Mark Brown, Dixit Parmar,
Tony Lindgren, linux-iio, devicetree, linux-kernel, linux-input,
linux-leds
In-Reply-To: <E5BC797C-4362-4C75-BCAC-7C32A51C4725@gmail.com>
On Wed, Feb 11, 2026 at 11:30 PM Svyatoslav Ryhel <clamor95@gmail.com> wrote:
>
>
>
> 11 лютого 2026 р. 23:20:16 GMT+02:00, Rob Herring <robh@kernel.org> пише:
> >On Fri, Feb 06, 2026 at 07:28:42PM +0200, Svyatoslav Ryhel wrote:
> >> Convert devicetree bindings for the Motorola CPCAP MFD from TXT to YAML.
> >>
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >> .../bindings/mfd/motorola,cpcap.yaml | 411 ++++++++++++++++++
> >> .../bindings/mfd/motorola-cpcap.txt | 78 ----
> >> 2 files changed, 411 insertions(+), 78 deletions(-)
> >> create mode 100644 Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
> >> delete mode 100644 Documentation/devicetree/bindings/mfd/motorola-cpcap.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
> >> new file mode 100644
> >> index 000000000000..7e350721d9f6
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mfd/motorola,cpcap.yaml
> >> @@ -0,0 +1,411 @@
> >> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> >> +%YAML 1.2
> >> +---
> >> +$id: http://devicetree.org/schemas/mfd/motorola,cpcap.yaml#
> >> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >> +
> >> +title: Motorola CPCAP PMIC MFD
> >> +
> >> +maintainers:
> >> + - Svyatoslav Ryhel <clamor95@gmail.com>
> >> +
> >> +allOf:
> >> + - $ref: /schemas/spi/spi-peripheral-props.yaml#
> >> +
> >> +properties:
> >> + compatible:
> >> + enum:
> >> + - motorola,cpcap
> >> + - st,6556002
> >
> >This does not match the only user in the kernel .dts files as
> >"st,6556002" should be a fallback.
> >
>
> Honestly, I would remove st,6556002 since it is not the only cpcap model which can be used, hence it cannot serve as a universal fallback. Some devices use ST produced cpcap chips, others use TI and range of models varies too. I guess I have to multiply commits.
The "cap" name goes way back to at least 2G Motorola phones. There
were whitecap and redcap chips for different 2G technologies which got
replaced by patriot (red+white+blue I guess) for 2.5G.
Dropping is fine with me, but then you have to update the .dtsi. If it
was me, I'd just make the binding match because that's 1 patch instead
of 2. You can still drop it on the new compatibles you are adding.
Rob
^ permalink raw reply
* Re: [PATCH 1/2] linux/interrupt.h: allow "guard" notation to disable and reenable IRQ with valid IRQ check
From: Dmitry Torokhov @ 2026-02-12 18:44 UTC (permalink / raw)
To: Marek Vasut
Cc: Thomas Gleixner, linux-input, Peter Zijlstra (Intel),
Cheng-Yang Chou, Frank Li, Geert Uytterhoeven, Jinjie Ruan,
Krzysztof Kozlowski, Marc Zyngier, Sebastian Andrzej Siewior,
linux-kernel, linux-renesas-soc
In-Reply-To: <1a2db366-a611-4454-a86e-cf7df9cbc358@mailbox.org>
On Wed, Jan 28, 2026 at 03:33:03PM +0100, Marek Vasut wrote:
> On 1/28/26 2:49 PM, Thomas Gleixner wrote:
> > On Wed, Jan 28 2026 at 13:23, Marek Vasut wrote:
> > > On 1/27/26 10:14 AM, Thomas Gleixner wrote:
> > > > disable_valid_irq is a pretty non-intuitive name if you look at it just
> > > > by reading a usage site. It's not really improving the readability of
> > > > the code, it's in fact obscuring it as the reader has to actually look
> > > > up what the hell this means and then stumble upon a completely
> > > > undocumented lock guard define.
> > > >
> > > > I'm all for using guards, but using guards just for the sake of using
> > > > guards is not a really good approach.
> > > I wouldn't even be opposed to converting the ili2xxx driver (the piece
> > > of code in patch 2/2 of this series) back to simple enable/disable_irq()
> > > . I am not particularly on board even with the disable_irq lock guard,
> > > or more specifically, lock guard used for non-lock things like this.
> >
> > I agree that guard() is a slight misnomer for such usage, but this is
> > about scoped auto cleanups, so using it this way makes a lot of sense
> > when the scope mechanism is sensible.
> It is indeed a misnomer.
>
> Would you prefer this patch be updated with some better function name, or
> dropped outright until there are surely more users of this functionality ?
Maybe call it "disable_irq_if_valid"?
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 5/5] input: drv260x: Don't try to disable dummy regulator
From: Dmitry Torokhov @ 2026-02-12 17:41 UTC (permalink / raw)
To: Yauhen Kharuzhy; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <20260211235902.4156624-6-jekhor@gmail.com>
On Thu, Feb 12, 2026 at 01:46:55AM +0200, Yauhen Kharuzhy wrote:
> Don't use a dummy regulator for 'vbat' because it cannot be disabled
> during suspending.
Why? Dummy regulator is supposed to be a placeholder that allows all the
regular operations (enable/disable/etc) without having actually supply
attached. Optional regulators are supposed to only be users when there
are parts of a chip that are powered separately and may be not in use in
a given design.
This change is counter to the regulator framework.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 4/5] input: drv260x: Stop waiting for GO bit clearing after timeout
From: Dmitry Torokhov @ 2026-02-12 17:34 UTC (permalink / raw)
To: Yauhen Kharuzhy; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <20260211235902.4156624-5-jekhor@gmail.com>
On Thu, Feb 12, 2026 at 01:46:54AM +0200, Yauhen Kharuzhy wrote:
> If something goes wrong during effect playing or calibration, the GO bit
> may not be cleared after some time, and the driver will get stuck.
> To prevent this, add a timeout to the waiting loop.
>
> Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com>
> ---
> drivers/input/misc/drv260x.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
> index f08a3d6c3ed8..f7bfac6d3973 100644
> --- a/drivers/input/misc/drv260x.c
> +++ b/drivers/input/misc/drv260x.c
> @@ -173,6 +173,12 @@
> #define DRV260X_AUTOCAL_TIME_500MS (2 << 4)
> #define DRV260X_AUTOCAL_TIME_1000MS (3 << 4)
>
> +/*
> + * Timeout for waiting for the GO status bit, in seconds. Should be reasonably
> + * large to allow long-duration effects and a calibration cycle
> + */
> +#define DRV260X_GO_TIMEOUT_S 5
> +
> /**
> * struct drv260x_data -
> * @input_dev: Pointer to the input device
> @@ -339,6 +345,7 @@ static int drv260x_init(struct drv260x_data *haptics)
> {
> int error;
> unsigned int cal_buf;
> + unsigned long timeout;
> u8 id;
>
> error = regmap_read(haptics->regmap, DRV260X_STATUS, &cal_buf);
> @@ -442,6 +449,7 @@ static int drv260x_init(struct drv260x_data *haptics)
> return error;
> }
>
> + timeout = jiffies + DRV260X_GO_TIMEOUT_S * HZ;
> do {
> usleep_range(15000, 15500);
> error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
> @@ -451,6 +459,10 @@ static int drv260x_init(struct drv260x_data *haptics)
> error);
> return error;
> }
> + if (jiffies - timeout <= 0) {
time_after()
> + dev_err(&haptics->client->dev, "GO timeout\n");
This should be a warning, not error, since we are continuing.
But actually, shouldn't we signal an error? This is probe path and if
the controller does not ever signal readiness I do not think we should
pretend that it will work.
> + break;
> + }
> } while (cal_buf == DRV260X_GO_BIT);
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 3/5] input: drv260x: Check the device ID at initialization
From: Dmitry Torokhov @ 2026-02-12 17:28 UTC (permalink / raw)
To: Yauhen Kharuzhy; +Cc: linux-input, linux-kernel, Hans de Goede
In-Reply-To: <20260211235902.4156624-4-jekhor@gmail.com>
On Thu, Feb 12, 2026 at 01:46:53AM +0200, Yauhen Kharuzhy wrote:
> To ensure that the device is accessible on the I2C bus, read the status
> register and check the Device ID field in drv260x_init().
>
> Signed-off-by: Yauhen Kharuzhy <jekhor@gmail.com>
> ---
> drivers/input/misc/drv260x.c | 44 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
> index f613c81fa2ba..f08a3d6c3ed8 100644
> --- a/drivers/input/misc/drv260x.c
> +++ b/drivers/input/misc/drv260x.c
> @@ -56,6 +56,13 @@
> #define DRV260X_LRA_RES_PERIOD 0x22
> #define DRV260X_MAX_REG 0x23
>
> +#define DRV260X_STATUS_ID_MASK 0xe0
> +#define DRV260X_STATUS_ID_SHIFT 5
> +#define DRV260X_ID_DRV2605 3
> +#define DRV260X_ID_DRV2604 4
> +#define DRV260X_ID_DRV2604L 6
> +#define DRV260X_ID_DRV2605L 7
> +
> #define DRV260X_GO_BIT 0x01
>
> /* Library Selection */
> @@ -305,10 +312,47 @@ static const struct reg_sequence drv260x_erm_cal_regs[] = {
> { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
> };
>
> +struct drv260x_id_map {
> + u8 id;
> + char *name;
> +};
> +
> +static const struct drv260x_id_map drv_260x_devids[] = {
> + { DRV260X_ID_DRV2605, "DRV2605"},
> + { DRV260X_ID_DRV2604, "DRV2604"},
> + { DRV260X_ID_DRV2604L, "DRV2604L"},
> + { DRV260X_ID_DRV2605L, "DRV2605L"},
> +};
> +
> +static char *drv260x_get_model(u8 id)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(drv_260x_devids); i++)
> + if (id == drv_260x_devids[i].id)
> + return drv_260x_devids[i].name;
> +
> + return NULL;
> +}
> +
> static int drv260x_init(struct drv260x_data *haptics)
> {
> int error;
> unsigned int cal_buf;
> + u8 id;
> +
> + error = regmap_read(haptics->regmap, DRV260X_STATUS, &cal_buf);
> + if (error) {
> + dev_err(&haptics->client->dev,
> + "Failed to read DRV260X_status register: %d\n",
> + error);
> + return error;
> + }
> +
> + id = (cal_buf & DRV260X_STATUS_ID_MASK) >> DRV260X_STATUS_ID_SHIFT;
> +
> + dev_info(&haptics->client->dev, "ID: %u (%s)\n", id,
> + drv260x_get_model(id));
>
> error = regmap_write(haptics->regmap,
> DRV260X_RATED_VOLT, haptics->rated_voltage);
If the device is not available this regmap_write() will fail so I am not
sure why we need all this new code.
Thanks.
--
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