* Re: [PATCH v6 2/2] Input: isa1200 - new driver for Imagis ISA1200
From: sashiko-bot @ 2026-06-17 7:18 UTC (permalink / raw)
To: Svyatoslav Ryhel; +Cc: robh, devicetree, linux-input, conor+dt, dmitry.torokhov
In-Reply-To: <20260617070528.35006-3-clamor95@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] The `ff-memless` timer and input device can outlive the devres-managed driver state upon device unbind, leading to a Use-After-Free (UAF).
- [High] The worker `isa1200_play_work` silently drops force feedback events if it fails to acquire `input->mutex`, potentially leaving the vibrator stuck.
- [Medium] Concurrent access to `isa->level` across different locking contexts causes a data race that can schedule work after the device is closed.
--
commit 2ea8a9b82f2921004386e7307e4e382941aa5611
Author: Linus Walleij <linusw@kernel.org>
Input: isa1200 - new driver for Imagis ISA1200
The ISA1200 is a haptic feedback unit from Imagis Technology using two
motors for haptic feedback in mobile phones. Used in many mobile devices
c. 2012 including Samsung Galxy S Advance GT-I9070 (Janice), Samsung Beam
GT-I8350 (Gavini), LG Optimus 4X P880 and LG Optimus Vu P895.
> diff --git a/drivers/input/misc/isa1200.c b/drivers/input/misc/isa1200.c
> new file mode 100644
> index 0000000000000..f8c4da4a0e088
> --- /dev/null
> +++ b/drivers/input/misc/isa1200.c
[ ... ]
> +static void isa1200_play_work(struct work_struct *work)
> +{
> + struct isa1200 *isa = container_of(work, struct isa1200, play_work);
> + struct input_dev *input = isa->input;
> +
> + scoped_guard(mutex_try, &input->mutex) {
[Severity: High]
Can this cause force feedback events to be silently dropped?
The worker uses scoped_guard(mutex_try, &input->mutex) to acquire the lock.
However, input->mutex is frequently held by the input core for normal
operations like input_open_device, input_close_device, and ioctls
(e.g., EVIOCGABS).
If this worker runs concurrently with any of these operations, the mutex_try
will fail and the worker will exit without updating the hardware. Because
isa->level was already updated locklessly in isa1200_vibrator_play_effect(),
future identical effect updates will be skipped, which could leave the
vibrator stuck in its current state.
> + if (!isa->suspended) {
> + if (isa->level)
> + isa1200_start(isa);
> + else
> + isa1200_stop(isa);
> + }
> + }
> +}
[ ... ]
> +static void isa1200_vibrator_close(struct input_dev *input)
> +{
> + struct isa1200 *isa = input_get_drvdata(input);
> +
> + cancel_work_sync(&isa->play_work);
> + isa1200_stop(isa);
> + isa->level = 0;
[Severity: Medium]
Does this concurrent modification of isa->level create a data race that
can restart the vibrator after the device is closed?
The state variable isa->level is updated in isa1200_vibrator_play_effect()
under the input core's event_lock (timer context). Concurrently, it is reset
to 0 here in isa1200_vibrator_close() under input->mutex, without acquiring
event_lock.
Because the ff-memless timer is not explicitly stopped during close, the
timer can fire concurrently with or immediately after close. If it fires
after cancel_work_sync(&isa->play_work) completes, it can overwrite
isa->level to a non-zero value and re-schedule isa->play_work. This could
re-enable the motor indefinitely.
> +}
[ ... ]
> +static int isa1200_probe(struct i2c_client *client)
> +{
> + struct isa1200 *isa;
> + struct device *dev = &client->dev;
> + int err;
> +
> + isa = devm_kzalloc(dev, sizeof(*isa), GFP_KERNEL);
[Severity: Critical]
Is there a use-after-free risk here during device unbind?
The private isa structure is allocated with devm_kzalloc(), meaning it is
freed immediately when the device unbinds. However, the input device itself
is managed by devm_input_allocate_device(), which keeps the memory alive
as long as userspace holds an open file descriptor.
Because the ff-memless timer (ml_effect_timer) is tied to the input_dev
lifecycle, the timer can continue to fire even after unbind if an effect
was playing. When it fires, isa1200_vibrator_play_effect() retrieves the
freed isa structure via input_get_drvdata() and accesses corrupted memory
to schedule the workqueue.
Additionally, there doesn't appear to be a devm action added to explicitly
cancel isa->play_work on unbind.
> + if (!isa)
> + return -ENOMEM;
> +
> + isa->input = devm_input_allocate_device(dev);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617070528.35006-1-clamor95@gmail.com?part=2
^ permalink raw reply
* [PATCH v2] HID: wacom: avoid copying Bluetooth input reports
From: Ruoyu Wang @ 2026-06-17 7:20 UTC (permalink / raw)
To: Ping Cheng, Jason Gerecke
Cc: Jiri Kosina, Benjamin Tissoires, linux-input, linux-kernel,
Ruoyu Wang
In-Reply-To: <20260606040344.4-1-ruoyuw560@gmail.com>
wacom_intuos_bt_irq() duplicates the received Bluetooth report with
kmemdup() so that it can pass 10-byte input report payloads to the
common Intuos parser. The helper then copies each payload back into
wacom->data before calling wacom_intuos_irq().
Avoid the allocation and copy by temporarily pointing wacom->data at the
current 10-byte payload while the common parser runs, then restoring the
original report pointer. The Bluetooth report parser keeps using the
original report buffer for dispatch and battery parsing, while the common
parser sees the same payload bytes as before.
This also removes the unchecked kmemdup() result from the Bluetooth IRQ
path.
Suggested-by: Jason Gerecke <jason.gerecke@wacom.com>
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
---
Changes in v2:
- Replace the kmemdup()/memcpy() path with temporary wacom->data pointer
substitution, as suggested by Jason.
drivers/hid/wacom_wac.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index da1f0ea85625d..a29bf051ada7c 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1192,8 +1192,11 @@ static int int_dist(int x1, int y1, int x2, int y2)
static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
unsigned char *data)
{
- memcpy(wacom->data, data, 10);
+ u8 *saved_data = wacom->data;
+
+ wacom->data = data;
wacom_intuos_irq(wacom);
+ wacom->data = saved_data;
input_sync(wacom->pen_input);
if (wacom->pad_input)
@@ -1202,7 +1205,7 @@ static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
{
- u8 *data = kmemdup(wacom->data, len, GFP_KERNEL);
+ u8 *data = wacom->data;
int i = 1;
unsigned power_raw, battery_capacity, bat_charging, ps_connected;
@@ -1242,7 +1245,6 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
break;
}
- kfree(data);
return 0;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2] HID: wacom: avoid copying Bluetooth input reports
From: sashiko-bot @ 2026-06-17 7:31 UTC (permalink / raw)
To: Ruoyu Wang; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260617072035.3373487-1-ruoyuw560@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unaligned memory access when parsing Bluetooth input reports.
--
commit 3d01afcf428b29530738d10b1c36a61efcc9ab57
Author: Ruoyu Wang <ruoyuw560@gmail.com>
HID: wacom: avoid copying Bluetooth input reports
This commit avoids duplicating the Bluetooth report with kmemdup() by
temporarily pointing wacom->data at the 10-byte payload while the
common parser runs.
> diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
> index da1f0ea85625d..a29bf051ada7c 100644
> --- a/drivers/hid/wacom_wac.c
> +++ b/drivers/hid/wacom_wac.c
> @@ -1192,8 +1192,11 @@ static int int_dist(int x1, int y1, int x2, int y2)
> static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
> unsigned char *data)
> {
> - memcpy(wacom->data, data, 10);
> + u8 *saved_data = wacom->data;
> +
> + wacom->data = data;
[Severity: High]
Can this lead to unaligned memory accesses on strict-alignment architectures?
In wacom_intuos_bt_irq(), wacom_intuos_bt_process_data() is called with
data + 1 or data + 11. By pointing wacom->data directly to these unaligned
offsets, the common parsers will receive an odd-aligned base pointer.
When wacom_intuos_irq() then calls wacom_intuos_general() or
wacom_intuos_pad(), those functions assume wacom->data is aligned and cast
offsets from it to __be16 *:
drivers/hid/wacom_wac.c:wacom_intuos_general() {
...
x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
...
}
If data is odd-aligned, &data[2] will also be unaligned. Calling
be16_to_cpup() on an unaligned pointer will trigger alignment faults on
architectures that do not support hardware unaligned accesses.
> wacom_intuos_irq(wacom);
> + wacom->data = saved_data;
>
> input_sync(wacom->pen_input);
> if (wacom->pad_input)
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260617072035.3373487-1-ruoyuw560@gmail.com?part=1
^ permalink raw reply
* Re: [PATCH 00/11] HID: iio: warning clean up and prefer kernel coding style
From: Maxwell Doose @ 2026-06-17 7:30 UTC (permalink / raw)
To: Sanjay Chitroda
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Jiri Kosina, Srinivas Pandruvada, linux-iio, linux-kernel,
linux-input, Zhang Lixu
In-Reply-To: <20260616-15-jun-hid-iio-alignment-v1-0-0cd544286575@gmail.com>
On Tue, Jun 16, 2026 at 5:26 AM Sanjay Chitroda
<sanjayembeddedse@gmail.com> wrote:
>
> Hi all,
>
> This series updates HID IIO drivers to resolve checkpatch and
> kernel coding style issue.
>
> This improves readability and follow standard kernel coding style
> No functional changes are introduced.
>
> Testing:
> - Compiled with W=1 for each patch in the series
>
> ---
> Sanjay Chitroda (11):
> iio: hid-sensors: add missing blank line after declarations
> iio: humidity: hid-sensor-humidity: align parenthesis for readability
> iio: gyro: hid-sensor-gyro-3d: align parenthesis for readability
> iio: magnetometer: hid-sensor-magn-3d: align parenthesis for readability
> iio: humidity: hid-sensor-humidity: use common device for devres
> iio: position: hid-sensor-custom-intel-hinge: use common device for devres
> iio: temperature: hid-sensor-temperature: use common device for devres
> iio: hid-sensor-magn-3d: use ! instead of explicit NULL check
> iio: hid-sensor-rotation: use ! instead of explicit NULL check
> iio: hid-sensor-incl-3d: use ! instead of explicit NULL check
> iio: hid-sensor-accel-3d: use ! instead of explicit NULL check
>
> drivers/iio/accel/hid-sensor-accel-3d.c | 2 +-
> .../iio/common/hid-sensors/hid-sensor-trigger.c | 3 +
> drivers/iio/gyro/hid-sensor-gyro-3d.c | 58 ++++++++--------
> drivers/iio/humidity/hid-sensor-humidity.c | 48 ++++++-------
> drivers/iio/magnetometer/hid-sensor-magn-3d.c | 80 +++++++++++-----------
> drivers/iio/orientation/hid-sensor-incl-3d.c | 2 +-
> drivers/iio/orientation/hid-sensor-rotation.c | 2 +-
> .../iio/position/hid-sensor-custom-intel-hinge.c | 2 +-
> drivers/iio/temperature/hid-sensor-temperature.c | 4 +-
> 9 files changed, 102 insertions(+), 99 deletions(-)
Firstly, for all of the style patches (1-4, 8-11):
Reviewed-by: Maxwell Doose <m32285159@gmail.com>
with Andy's comments.
Secondly, the style fixes are all churn. It would honestly be much
much better if you were to squash those (even despite the
one-logical-change-per-patch rule).
--
best regards,
max
^ permalink raw reply
* Re: [PATCH 1/1] HID: core: Fix OOB read in hid_get_report for numbered reports
From: Lee Jones @ 2026-06-17 8:27 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Jiri Kosina, Benjamin Tissoires, Johan Hovold, linux-input,
linux-kernel
In-Reply-To: <2026061649-sphinx-ancient-e3c0@gregkh>
On Tue, 16 Jun 2026, Greg Kroah-Hartman wrote:
> On Tue, Jun 16, 2026 at 11:26:56AM +0000, Lee Jones wrote:
> > When a caller passes a size of 0 to hid_report_raw_event() for a
> > numbered report, the function originally called hid_get_report() before
> > performing any size validation.
> >
> > Inside hid_get_report(), if the report is numbered (report_enum->numbered
> > is true), it unconditionally dereferences data[0] to extract the report ID.
> > With a size of 0, this results in an out-of-bounds read or kernel panic.
> >
> > Fix this by moving the numbered report size validation check before the
> > call to hid_get_report(), ensuring that size is at least 1 before
> > dereferencing the data pointer.
> >
> > Fixes: 2c85c61d1332 ("HID: pass the buffer size to hid_report_raw_event")
> > Signed-off-by: Lee Jones <lee@kernel.org>
> > ---
> > drivers/hid/hid-core.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
>
> Hi,
>
> This is the friendly patch-bot of Greg Kroah-Hartman. You have sent him
> a patch that has triggered this response. He used to manually respond
> to these common problems, but in order to save his sanity (he kept
> writing the same thing over and over, yet to different people), I was
> created. Hopefully you will not take offence and will fix the problem
> in your patch and resubmit it so that it can be accepted into the Linux
> kernel tree.
>
> You are receiving this message because of the following common error(s)
> as indicated below:
>
> - You have marked a patch with a "Fixes:" tag for a commit that is in an
> older released kernel, yet you do not have a cc: stable line in the
> signed-off-by area at all, which means that the patch will not be
> applied to any older kernel releases. To properly fix this, please
> follow the documented rules in the
> Documentation/process/stable-kernel-rules.rst file for how to resolve
> this.
>
> If you wish to discuss this problem further, or you have questions about
> how to resolve this issue, please feel free to respond to this email and
> Greg will reply once he has dug out from the pending patches received
> from other developers.
Sure, why not! :)
Cc: stable@vger.kernel.org
--
Lee Jones
^ permalink raw reply
* Re: [PATCH v4 1/3] HID: wacom: Fix Use-After-Free in wacom_intuos_pad
From: Lee Jones @ 2026-06-17 8:28 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-input, dmitry.torokhov
In-Reply-To: <20260616094526.D380A1F000E9@smtp.kernel.org>
On Tue, 16 Jun 2026, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Use-After-Free in `wacom_mode_change_work()` due to unprotected lockless access of sibling device pointers.
Note that the issues found on this set are all pre-existing.
--
Lee Jones
^ permalink raw reply
* Re: [PATCH 3/4] input: misc: Add Qualcomm SPMI PMIC haptics driver
From: Konrad Dybcio @ 2026-06-17 9:30 UTC (permalink / raw)
To: Fenglin Wu, linux-arm-msm, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lee Jones, Stephen Boyd,
Bjorn Andersson, Konrad Dybcio
Cc: David Collins, Subbaraman Narayanamurthy, Kamal Wadhwa, kernel,
linux-input, devicetree, linux-kernel
In-Reply-To: <1bcf00ae-2558-4c3a-970d-aee1da0c06f9@oss.qualcomm.com>
On 6/17/26 4:31 AM, Fenglin Wu wrote:
>>> + ret = ptn_bulk_write(h, HAP_PTN_FIFO_DIN_0_REG, &data[i], 4);
>>> + if (ret)
>>> + return ret;
>>> + }
>>> +
>>> + for (; i < len; i++) {
>>> + ret = ptn_write(h, HAP_PTN_FIFO_DIN_1B_REG, (u8)data[i]);
>>> + if (ret)
>>> + return ret;
>>> + }
>> So if i'm reading this right, the first loop will always write
>> 4*(len//4) bytes and the second one will be entered at most once,
>> to write len rem 4 bytes.. should this be an if instead?
>
> I should put a comment for clarification. Here’s some background: FIFO data writing supports both 4-byte bulk writes using registers [HAP_PTN_FIFO_DIN_0_REG ... HAP_PTN_FIFO_DIN_3_REG], and 1-byte writes using the HAP_PTN_FIFO_DIN_1B_REG register. The 4-byte bulk write is more efficient, especially for waveform which has several Kb data, and it helps to reduce software latency when loading effects and reduce the delay in triggering vibration. It also helps prevent the FIFO from running dry during data refill in FIFO-empty interrupts. Typically, we use 4-byte writes for the initial 4-byte aligned data, and 1-byte writes for any trailing remainder.
>
> So it still needs a 'for' loop here since the remainder could be more than 1 byte.
Right, I mentioned len rem 4 but failed to notice it's a
single-byte write.. anyway, a comment here would be good
>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/*
>>> + * Configure the hardware FIFO memory boundary.
>>> + * FIFO occupies addresses [0, fifo_len).
>>> + */
>>> +static int haptics_configure_fifo_mmap(struct qcom_haptics *h)
>>> +{
>>> + u32 fifo_len, fifo_units;
>>> +
>>> + /* Config all memory space for FIFO usage for now */
>> What's the not-"for now" endgame for this?
>
> The hardware supports more modes than the two currently supported in the driver. One of these, called 'PAT_MEM' mode, also shares memory space with FIFO mode. However, 'PAT_MEM' requires memory to be pre-reserved and waveform data to be pre-loaded. The entire 8K bytes of memory can be divided into partitions, and it is configurable, with FIFO mode always using the first partition [0, fifo_len], where 'fifo_len' is set via the 'MMAP_FIFO_REG' register. 'PAT_MEM' mode plays waveform using data preloaded in a memory bank defined by the registers 'PATX_MEM_START_ADDR_REG' and 'PATTERN_SPMI_PATX_LEN_REG' (they are not defined in the driver). Since PAT_MEM is mainly intended for hardware-triggered vibrations, such as a signal from a dedicated GPIO triggering a short vibration with a preloaded waveform, and although it also supports software triggers, I haven't found a suitable way to support it well into the driver under input FF framework yet. So, I am currently allocating the
> entire 8K FIFO memory for FIFO mode only. We can adjust this later if we find a better way to incorporate 'PAT_MEM' mode into the driver.
Sounds like a plan.
For the other mode, would that GPIO trigger need any OS intervention?
Could you speak a bit more about how that works?
Konrad
^ permalink raw reply
* Re: [PATCH 3/4] input: misc: Add Qualcomm SPMI PMIC haptics driver
From: Fenglin Wu @ 2026-06-17 10:12 UTC (permalink / raw)
To: Konrad Dybcio, linux-arm-msm, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lee Jones, Stephen Boyd,
Bjorn Andersson, Konrad Dybcio
Cc: David Collins, Subbaraman Narayanamurthy, Kamal Wadhwa, kernel,
linux-input, devicetree, linux-kernel
In-Reply-To: <29806448-0588-4590-8540-a689ccf1e7b0@oss.qualcomm.com>
On 6/17/2026 5:30 PM, Konrad Dybcio wrote:
> On 6/17/26 4:31 AM, Fenglin Wu wrote:
>>>> + ret = ptn_bulk_write(h, HAP_PTN_FIFO_DIN_0_REG, &data[i], 4);
>>>> + if (ret)
>>>> + return ret;
>>>> + }
>>>> +
>>>> + for (; i < len; i++) {
>>>> + ret = ptn_write(h, HAP_PTN_FIFO_DIN_1B_REG, (u8)data[i]);
>>>> + if (ret)
>>>> + return ret;
>>>> + }
>>> So if i'm reading this right, the first loop will always write
>>> 4*(len//4) bytes and the second one will be entered at most once,
>>> to write len rem 4 bytes.. should this be an if instead?
>> I should put a comment for clarification. Here’s some background: FIFO data writing supports both 4-byte bulk writes using registers [HAP_PTN_FIFO_DIN_0_REG ... HAP_PTN_FIFO_DIN_3_REG], and 1-byte writes using the HAP_PTN_FIFO_DIN_1B_REG register. The 4-byte bulk write is more efficient, especially for waveform which has several Kb data, and it helps to reduce software latency when loading effects and reduce the delay in triggering vibration. It also helps prevent the FIFO from running dry during data refill in FIFO-empty interrupts. Typically, we use 4-byte writes for the initial 4-byte aligned data, and 1-byte writes for any trailing remainder.
>>
>> So it still needs a 'for' loop here since the remainder could be more than 1 byte.
> Right, I mentioned len rem 4 but failed to notice it's a
> single-byte write.. anyway, a comment here would be good
>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Configure the hardware FIFO memory boundary.
>>>> + * FIFO occupies addresses [0, fifo_len).
>>>> + */
>>>> +static int haptics_configure_fifo_mmap(struct qcom_haptics *h)
>>>> +{
>>>> + u32 fifo_len, fifo_units;
>>>> +
>>>> + /* Config all memory space for FIFO usage for now */
>>> What's the not-"for now" endgame for this?
>> The hardware supports more modes than the two currently supported in the driver. One of these, called 'PAT_MEM' mode, also shares memory space with FIFO mode. However, 'PAT_MEM' requires memory to be pre-reserved and waveform data to be pre-loaded. The entire 8K bytes of memory can be divided into partitions, and it is configurable, with FIFO mode always using the first partition [0, fifo_len], where 'fifo_len' is set via the 'MMAP_FIFO_REG' register. 'PAT_MEM' mode plays waveform using data preloaded in a memory bank defined by the registers 'PATX_MEM_START_ADDR_REG' and 'PATTERN_SPMI_PATX_LEN_REG' (they are not defined in the driver). Since PAT_MEM is mainly intended for hardware-triggered vibrations, such as a signal from a dedicated GPIO triggering a short vibration with a preloaded waveform, and although it also supports software triggers, I haven't found a suitable way to support it well into the driver under input FF framework yet. So, I am currently allocating the
>> entire 8K FIFO memory for FIFO mode only. We can adjust this later if we find a better way to incorporate 'PAT_MEM' mode into the driver.
> Sounds like a plan.
>
> For the other mode, would that GPIO trigger need any OS intervention?
> Could you speak a bit more about how that works?
>
> Konrad
I'll try to clarify the 'PAT_MEM' mode further. 'PAT_MEM' is useful for
latency-sensitive vibrations because it preloads the waveform into a
fixed memory bank, then it doesn't need to load the data of the effect
in the HW before triggering the play. When playback is triggered, it
plays the waveform from the specified memory address and length. This
memory should be preserved, and the data is preloaded during boot.
Unlike FIFO mode, it doesn't allow data refilling. The trigger can come
from hardware via dedicated GPIOs—currently, three are supported, each
mapping to a memory bank set through specific registers. Software
configuration can be done in the bootloader or in the driver probe, but
the 'fifo_len' should be adjusted accordingly. After setup, software
doesn't need to manage it further, relying on the GPIO signal to
activate the playback (for example, a pressure sensor triggering
vibration to simulate a physical key press). The trigger can also come
from software using SPMI commands by setting the play mode, start
address, and data length. I previously tried using the 'FF_HAPTIC'
effect by mapping 'hid_usage' to a predefined effect in the devicetree,
but later I found it unsuitable since 'FF_HAPTIC' is mainly for USB HID
touch devices and not general vibration usage. If you have any
suggestions for supporting 'PAT_MEM' mode through the input FF
framework, please let me know.
^ permalink raw reply
* Re: [PATCH 1/2] HID: logitech-hidpp: add HID++ 2.0 reprogrammable button support
From: Bastien Nocera @ 2026-06-17 10:28 UTC (permalink / raw)
To: Elliot Douglas, linux-input; +Cc: lains, jikos, bentiss, linux-kernel
In-Reply-To: <20260613175109.44365-2-edouglas7358@gmail.com>
On Sat, 2026-06-13 at 10:51 -0700, Elliot Douglas wrote:
> Some Logitech HID++ 2.0 mice can report diverted reprogrammable
> controls through HID++ feature 0x1b04, SpecialKeysMseButtons /
> REPROG_CONTROLS_V4, instead of the normal HID mouse report.
>
> Add a quirk-gated event path for those controls. The handler temporarily
> diverts verified per-product controls, parses divertedButtonsEvent as the
> current pressed-control list, and reports the corresponding evdev key state
> for every mapped control.
>
> Keep the control mappings in per-product profiles so adding support for
> another mouse does not change the evdev capabilities advertised by
> already-supported devices.
How does this forced setting work/clash with the programmable buttons
in Solaar?
I've added some inline comments below.
>
> Documentation for feature 0x1b04 describes divertedButtonsEvent as a list
> of currently pressed diverted buttons, which is the event format handled
> here.
>
> Link: https://lekensteyn.nl/files/logitech/x1b04_specialkeysmsebuttons.html
>
> Signed-off-by: Elliot Douglas <edouglas7358@gmail.com>
> ---
> drivers/hid/hid-logitech-hidpp.c | 215 +++++++++++++++++++++++++++++++
> 1 file changed, 215 insertions(+)
>
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index 70ba1a5e40d8..24c9cfaa4f37 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -76,6 +76,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
> #define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(28)
> #define HIDPP_QUIRK_WIRELESS_STATUS BIT(29)
> #define HIDPP_QUIRK_RESET_HI_RES_SCROLL BIT(30)
> +#define HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS BIT(31)
>
> /* These are just aliases for now */
> #define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
> @@ -205,6 +206,7 @@ struct hidpp_device {
> struct hidpp_scroll_counter vertical_wheel_counter;
>
> u8 wireless_feature_index;
> + u8 reprog_controls_feature_index;
>
> int hires_wheel_multiplier;
> u8 hires_wheel_feature_index;
> @@ -3601,6 +3603,209 @@ static int hidpp10_extra_mouse_buttons_raw_event(struct hidpp_device *hidpp,
> return 1;
> }
>
> +/* -------------------------------------------------------------------------- */
> +/* HID++2.0 reprogrammable controls */
> +/* -------------------------------------------------------------------------- */
> +
> +#define HIDPP_PAGE_REPROG_CONTROLS_V4 0x1b04
> +
> +#define HIDPP_REPROG_CONTROLS_GET_COUNT 0x00
> +#define HIDPP_REPROG_CONTROLS_GET_CID_INFO 0x10
> +#define HIDPP_REPROG_CONTROLS_SET_CONTROL_REPORTING 0x30
> +
> +#define HIDPP_REPROG_CONTROLS_FLAG_MOUSE BIT(0)
> +#define HIDPP_REPROG_CONTROLS_FLAG_DIVERT BIT(5)
> +
> +#define HIDPP_REPROG_CONTROLS_TEMPORARY_DIVERTED BIT(0)
> +#define HIDPP_REPROG_CONTROLS_CHANGE_TEMPORARY_DIVERT BIT(1)
> +
> +#define HIDPP_REPROG_CONTROLS_EVENT_DIVERTED 0x00
> +
> +struct hidpp_reprog_control_mapping {
> + u16 control;
> + u16 code;
> +};
> +
> +struct hidpp_reprog_controls_profile {
> + const struct hidpp_reprog_control_mapping *mappings;
probably needs a __counted_by(), or maybe as it's static, it might be
better to not require an intermediate struct, and return a NULL-
terminated array instead.
> + unsigned int mapping_count;
> +};
> +
> +static const struct hidpp_reprog_controls_profile *
> +hidpp20_reprog_controls_get_profile(struct hidpp_device *hidpp)
> +{
> + return NULL;
> +}
> +
> +static int hidpp20_reprog_controls_get_count(struct hidpp_device *hidpp)
> +{
> + struct hidpp_report response;
> + u8 feature_index = hidpp->reprog_controls_feature_index;
> + u8 cmd = HIDPP_REPROG_CONTROLS_GET_COUNT;
> + int ret;
> +
> + ret = hidpp_send_fap_command_sync(hidpp, feature_index, cmd, NULL, 0,
> + &response);
> + if (ret > 0)
> + return -EPROTO;
> + if (ret)
> + return ret;
> +
> + return response.fap.params[0];
> +}
> +
> +static int hidpp20_reprog_controls_get_cid_info(struct hidpp_device *hidpp,
> + u8 index, u16 *control,
> + u8 *flags)
> +{
> + struct hidpp_report response;
> + u8 feature_index = hidpp->reprog_controls_feature_index;
> + u8 cmd = HIDPP_REPROG_CONTROLS_GET_CID_INFO;
> + int ret;
> +
> + ret = hidpp_send_fap_command_sync(hidpp, feature_index, cmd, &index,
> + sizeof(index), &response);
> + if (ret > 0)
> + return -EPROTO;
> + if (ret)
> + return ret;
> +
> + *control = get_unaligned_be16(&response.fap.params[0]);
> + *flags = response.fap.params[4];
> +
> + return 0;
> +}
> +
> +static bool hidpp20_reprog_controls_find_control(struct hidpp_device *hidpp,
> + u16 control)
> +{
> + int count, ret;
> + u16 cid;
> + u8 flags;
> + int i;
> +
> + count = hidpp20_reprog_controls_get_count(hidpp);
> + if (count < 0)
> + return false;
> +
> + for (i = 0; i < count; i++) {
> + ret = hidpp20_reprog_controls_get_cid_info(hidpp, i, &cid,
> + &flags);
> + if (ret)
> + return false;
> +
> + if (cid == control)
> + return (flags & HIDPP_REPROG_CONTROLS_FLAG_MOUSE) &&
> + (flags & HIDPP_REPROG_CONTROLS_FLAG_DIVERT);
> + }
> +
> + return false;
> +}
> +
> +static int hidpp20_reprog_controls_set_control_reporting(struct hidpp_device *hidpp,
> + u16 control, u8 flags)
> +{
> + struct hidpp_report response;
> + u8 params[5];
> +
> + put_unaligned_be16(control, ¶ms[0]);
> + params[2] = flags;
> + put_unaligned_be16(control, ¶ms[3]);
> +
> + return hidpp_send_fap_command_sync(hidpp,
> + hidpp->reprog_controls_feature_index,
> + HIDPP_REPROG_CONTROLS_SET_CONTROL_REPORTING,
> + params, sizeof(params), &response);
> +}
> +
> +static void hidpp20_reprog_controls_connect(struct hidpp_device *hidpp)
> +{
> + const struct hidpp_reprog_controls_profile *profile;
> + u8 flags = HIDPP_REPROG_CONTROLS_TEMPORARY_DIVERTED |
> + HIDPP_REPROG_CONTROLS_CHANGE_TEMPORARY_DIVERT;
> + unsigned int i;
> +
> + if (!(hidpp->quirks & HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS))
> + return;
> +
> + profile = hidpp20_reprog_controls_get_profile(hidpp);
Could the profile be cached in the hidpp_device struct?
> + if (!profile)
> + return;
> +
> + if (hidpp_root_get_feature(hidpp, HIDPP_PAGE_REPROG_CONTROLS_V4,
> + &hidpp->reprog_controls_feature_index))
> + return;
> +
> + for (i = 0; i < profile->mapping_count; i++) {
> + u16 control = profile->mappings[i].control;
> +
> + if (!hidpp20_reprog_controls_find_control(hidpp, control))
> + continue;
> +
> + hidpp20_reprog_controls_set_control_reporting(hidpp, control, flags);
> + }
> +}
> +
> +static int hidpp20_reprog_controls_raw_event(struct hidpp_device *hidpp,
> + u8 *data, int size)
> +{
> + const struct hidpp_reprog_controls_profile *profile;
> + const struct hidpp_reprog_control_mapping *mapping;
> + struct hidpp_report *report = (struct hidpp_report *)data;
> + u16 controls[4];
> + bool pressed;
> + unsigned int i, j;
> +
> + if (!(hidpp->quirks & HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS) ||
> + !hidpp->input ||
> + hidpp->reprog_controls_feature_index == 0xff)
> + return 0;
> +
> + profile = hidpp20_reprog_controls_get_profile(hidpp);
> + if (!profile)
> + return 0;
> +
> + if (size < HIDPP_REPORT_LONG_LENGTH ||
> + report->fap.feature_index != hidpp->reprog_controls_feature_index ||
> + report->fap.funcindex_clientid != HIDPP_REPROG_CONTROLS_EVENT_DIVERTED)
> + return 0;
> +
> + for (i = 0; i < ARRAY_SIZE(controls); i++)
> + controls[i] = get_unaligned_be16(&report->fap.params[i * 2]);
> +
> + for (i = 0; i < profile->mapping_count; i++) {
> + mapping = &profile->mappings[i];
> + pressed = false;
> +
> + for (j = 0; j < ARRAY_SIZE(controls); j++) {
> + if (controls[j] == mapping->control) {
> + pressed = true;
> + break;
> + }
> + }
> +
> + input_report_key(hidpp->input, mapping->code, pressed);
> + }
> +
> + input_sync(hidpp->input);
> +
> + return 1;
> +}
> +
> +static void hidpp20_reprog_controls_populate_input(struct hidpp_device *hidpp,
> + struct input_dev *input_dev)
> +{
> + const struct hidpp_reprog_controls_profile *profile;
> + unsigned int i;
> +
> + profile = hidpp20_reprog_controls_get_profile(hidpp);
> + if (!profile)
> + return;
> +
> + for (i = 0; i < profile->mapping_count; i++)
> + input_set_capability(input_dev, EV_KEY, profile->mappings[i].code);
> +}
> +
> static void hidpp10_extra_mouse_buttons_populate_input(
> struct hidpp_device *hidpp, struct input_dev *input_dev)
> {
> @@ -3859,6 +4064,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
>
> if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS)
> hidpp10_extra_mouse_buttons_populate_input(hidpp, input);
> +
> + if (hidpp->quirks & HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS)
> + hidpp20_reprog_controls_populate_input(hidpp, input);
> }
>
> static int hidpp_input_configured(struct hid_device *hdev,
> @@ -3971,6 +4179,10 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
> return ret;
> }
>
> + ret = hidpp20_reprog_controls_raw_event(hidpp, data, size);
> + if (ret != 0)
> + return ret;
> +
> if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) {
> ret = hidpp10_consumer_keys_raw_event(hidpp, data, size);
> if (ret != 0)
> @@ -4264,6 +4476,8 @@ static void hidpp_connect_event(struct work_struct *work)
> return;
> }
>
> + hidpp20_reprog_controls_connect(hidpp);
> +
> if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) {
> ret = hidpp10_consumer_keys_connect(hidpp);
> if (ret)
> @@ -4436,6 +4650,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> hidpp->hid_dev = hdev;
> hidpp->name = hdev->name;
> hidpp->quirks = id->driver_data;
> + hidpp->reprog_controls_feature_index = 0xff;
> hid_set_drvdata(hdev, hidpp);
>
> ret = hid_parse(hdev);
^ permalink raw reply
* Re: [PATCH 2/2] HID: logitech-hidpp: enable reprogrammable buttons on Signature M650
From: Bastien Nocera @ 2026-06-17 10:28 UTC (permalink / raw)
To: Elliot Douglas, linux-input; +Cc: lains, jikos, bentiss, linux-kernel
In-Reply-To: <20260613175109.44365-3-edouglas7358@gmail.com>
Hey Elliot,
I have an m650 on hand on with which I should be able to test your
patch next week, once we've gone through a first round of reviews.
Benjamin, is there something I can capture locally that could make it
into the HID tests for this feature?
Inline comments below
On Sat, 2026-06-13 at 10:51 -0700, Elliot Douglas wrote:
> The Bluetooth Signature M650 exposes its side buttons through the
> normal
> mouse report, but the observed events are short click-like events
> emitted
> around release rather than physical press/release state.
>
> The device appears to use the held side-button state for its built-in
> gesture and side-button + wheel horizontal-scroll mode. As a result,
> holding a side button long enough can prevent the normal mouse report
> from
> emitting a usable button event at all.
>
> HID++ REPROG_CONTROLS_V4 diversion for control IDs 0x0053 and 0x0056
> provides real press and release timing for those same controls.
> Logitech
> documents the Signature M650 side buttons as Back/Forward buttons, so
> report the diverted controls as BTN_BACK and BTN_FORWARD.
>
> Link:
> https://support.logi.com/hc/en-nz/articles/4414473810583-Getting-Started-Signature-M650
>
> Signed-off-by: Elliot Douglas <edouglas7358@gmail.com>
> ---
> drivers/hid/hid-logitech-hidpp.c | 21 ++++++++++++++++++++-
> 1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-
> logitech-hidpp.c
> index 24c9cfaa4f37..80108778ee80 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -3621,6 +3621,9 @@ static int
> hidpp10_extra_mouse_buttons_raw_event(struct hidpp_device *hidpp,
>
> #define HIDPP_REPROG_CONTROLS_EVENT_DIVERTED 0x00
>
> +#define HIDPP_REPROG_CONTROL_M650_BACK 0x0053
> +#define HIDPP_REPROG_CONTROL_M650_FORWARD 0x0056
I read through the 0x1b04 docs, and I'm trying to understand whether
those CID numbers change in different hardware, or if they're hardcoded
(a back button will always have the 83/0x53 value).
Seems to me that it's the latter? The back button is listed in the
Example Control ID table in the 0x1b04 docs.
> +
> struct hidpp_reprog_control_mapping {
> u16 control;
> u16 code;
> @@ -3631,9 +3634,24 @@ struct hidpp_reprog_controls_profile {
> unsigned int mapping_count;
> };
>
> +static const struct hidpp_reprog_control_mapping
> m650_reprog_control_mappings[] = {
> + { HIDPP_REPROG_CONTROL_M650_BACK, BTN_BACK },
> + { HIDPP_REPROG_CONTROL_M650_FORWARD, BTN_FORWARD },
> +};
> +
> +static const struct hidpp_reprog_controls_profile
> m650_reprog_controls_profile = {
> + .mappings = m650_reprog_control_mappings,
> + .mapping_count = ARRAY_SIZE(m650_reprog_control_mappings),
> +};
> +
> static const struct hidpp_reprog_controls_profile *
> hidpp20_reprog_controls_get_profile(struct hidpp_device *hidpp)
> {
> + switch (hidpp->hid_dev->product) {
> + case 0xb02a:
You probably want a define for that constant.
> + return &m650_reprog_controls_profile;
> + }
> +
> return NULL;
> }
>
> @@ -4921,7 +4939,8 @@ static const struct hid_device_id
> hidpp_devices[] = {
> { /* MX Vertical mouse over Bluetooth */
> HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb020) },
> { /* Signature M650 over Bluetooth */
> - HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) },
> + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a),
> + .driver_data = HIDPP_QUIRK_HIDPP_REPROG_CONTROLS_BTNS },
> { /* MX Master 3 mouse over Bluetooth */
> HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
> { /* MX Anywhere 3 mouse over Bluetooth */
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: input: Add binding for Qualcomm SPMI PMIC haptics
From: Krzysztof Kozlowski @ 2026-06-17 10:35 UTC (permalink / raw)
To: Fenglin Wu
Cc: linux-arm-msm, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lee Jones, Stephen Boyd, Bjorn Andersson,
Konrad Dybcio, David Collins, Subbaraman Narayanamurthy,
Kamal Wadhwa, kernel, linux-input, devicetree, linux-kernel
In-Reply-To: <20260616-qcom-spmi-haptics-v1-1-d24e422de6b4@oss.qualcomm.com>
On Tue, Jun 16, 2026 at 03:08:24AM -0700, Fenglin Wu wrote:
> Add binding document for the haptics module inside Qualcomm PMIH010X.
A nit, subject: drop second/last, redundant "binding for". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v7.1-rc7/source/Documentation/devicetree/bindings/submitting-patches.rst#L23
>
> Assisted-by: Claude:claude-4-6-sonnet
> Signed-off-by: Fenglin Wu <fenglin.wu@oss.qualcomm.com>
> ---
> .../bindings/input/qcom,spmi-haptics.yaml | 119 +++++++++++++++++++++
> 1 file changed, 119 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml b/Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml
> new file mode 100644
> index 000000000000..0e26d68563dc
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/qcom,spmi-haptics.yaml
Filenamem should match compatible.
> @@ -0,0 +1,119 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/input/qcom,spmi-haptics.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Haptics device inside Qualcomm Technologies, Inc. PMIH010X
> +
> +maintainers:
> + - Fenglin Wu <fenglin.wu@oss.qualcomm.com>
> +
...
> +properties:
> + compatible:
> + const: qcom,pmih010x-haptics
Don't use Claude. It does not understand DT. Please read writing
bindings document or DTS101 slides. You cannot have wildcards.
> +
> + reg:
> + items:
> + - description: HAP_CFG module base address
> + - description: HAP_PTN module base address
> +
> + reg-names:
> + items:
> + - const: hap-cfg
cfg
> + - const: hap-ptn
ptn
> +
> + interrupts:
> + maxItems: 1
> +
> + interrupt-names:
> + items:
> + - const: fifo-empty
> +
> + qcom,vmax-mv:
And claude did not tell you that this is not correct? If so, please
don't use it. It's crap tool if it cannot get the basics of DT (was
mentioned on talks many times, is documented etc).
You need proper suffix.
> + description:
> + Maximum allowed output driving voltage in millivolts, rounded to the
> + nearest 50 mV step. This is the peak driving voltage in DIRECT_PLAY mode
> + which outputs sinusoidal waveforms. The value should be equal to the square
> + root of 2 times the Vrms voltage of the LRA.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 50
> + maximum: 10000
> +
> + qcom,lra-period-us:
> + description:
> + LRA actuator initial resonance period in microseconds
> + (1,000,000 / resonant_freq_hz). Used to configure T_LRA-based play
> + rates and the auto-resonance zero-crossing window.
This does not feel like static characteristic. Isn't period depending on
intensity of vibration you want to have? Why would that be fixed per
board?
> + minimum: 5
> + maximum: 20475
> +
> +required:
> + - compatible
> + - reg
> + - reg-names
> + - interrupts
> + - interrupt-names
> + - qcom,vmax-mv
> + - qcom,lra-period-us
> +
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 0/4] input: misc: Add an initial driver for haptics inside Qcom PMIH010x PMIC
From: Krzysztof Kozlowski @ 2026-06-17 10:42 UTC (permalink / raw)
To: Fenglin Wu
Cc: linux-arm-msm, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lee Jones, Stephen Boyd, Bjorn Andersson,
Konrad Dybcio, David Collins, Subbaraman Narayanamurthy,
Kamal Wadhwa, kernel, linux-input, devicetree, linux-kernel
In-Reply-To: <20260616-qcom-spmi-haptics-v1-0-d24e422de6b4@oss.qualcomm.com>
On Tue, Jun 16, 2026 at 03:08:23AM -0700, Fenglin Wu wrote:
Here - the first sentence - is where you mention merging
constraints/strategy/dependencies. Your MFD patch depends on ealier
ones.
> Qualcomm PMIH010x PMIC has a haptics module inside and it could drive
> a LRA actuator with several play modes, including: DIRECT_PLAY, FIFO,
> PAT_MEM, SWR, etc. Add an initial driver to support two of the play
> modes using the input force-feedback framework:
>
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: input: Add binding for Qualcomm SPMI PMIC haptics
From: Fenglin Wu @ 2026-06-17 11:02 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: linux-arm-msm, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lee Jones, Stephen Boyd, Bjorn Andersson,
Konrad Dybcio, David Collins, Subbaraman Narayanamurthy,
Kamal Wadhwa, kernel, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617-wakeful-gorilla-of-feminism-75287c@quoll>
On 6/17/2026 6:35 PM, Krzysztof Kozlowski wrote:
> On Tue, Jun 16, 2026 at 03:08:24AM -0700, Fenglin Wu wrote:
>> ....
>> +
>> + qcom,lra-period-us:
>> + description:
>> + LRA actuator initial resonance period in microseconds
>> + (1,000,000 / resonant_freq_hz). Used to configure T_LRA-based play
>> + rates and the auto-resonance zero-crossing window.
> This does not feel like static characteristic. Isn't period depending on
> intensity of vibration you want to have? Why would that be fixed per
> board?
This period is specifically used for playbacks that require
auto-resonance to be enabled, which I referred to as "T_LRA-based" and
"auto-resonance zero-crossing window." It plays a key role in the
"DIRECT_PLAY" mode, which produces a constant vibration effect. To
adjust the vibration intensity during this constant effect, the hardware
does it by scaling the peak voltage of the driver signals, rather than
changing the frequency.
>> + minimum: 5
>> + maximum: 20475
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - reg-names
>> + - interrupts
>> + - interrupt-names
>> + - qcom,vmax-mv
>> + - qcom,lra-period-us
>> +
> Best regards,
> Krzysztof
>
^ permalink raw reply
* [PATCH v3] Input: synaptics - disable InterTouch on ThinkPad T440p (board id 2722)
From: Raphaël Larocque @ 2026-06-17 11:45 UTC (permalink / raw)
To: linux-input; +Cc: linux-kernel, dmitry.torokhov, Raphaël Larocque
In-Reply-To: <20260616171137.19069-1-rlarocque@disroot.org>
The Lenovo ThinkPad T440p (PNP ID LEN0036, board id 2722) has a
Synaptics touchpad whose SMBus companion is not ready at boot and
takes ~200 s to appear. During this window the touchpad
and pointer are completely unresponsive on approximately 50% of
boots, making the machine unusable until the companion finally
registers.
The device is in the topbuttonpad_pnp_ids[] SMBus allowlist, so the
kernel attempts to use SMBus/RMI4 mode by default. When the companion
is not ready, psmouse_smbus_init() leaves breadcrumbs and returns
-EAGAIN, the PS/2 fallback path is taken, but the device does not
function properly until the companion appears and RMI4 takes over.
Disable SMBus InterTouch for PNP ID LEN0036 with board id 2722 so
the touchpad and TrackPoint work immediately via PS/2 from boot.
Users can still force SMBus with psmouse.synaptics_intertouch=1 if
needed.
Tested-by: Raphaël Larocque <rlarocque@disroot.org>
Signed-off-by: Raphaël Larocque <rlarocque@disroot.org>
---
drivers/input/mouse/synaptics.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index c70502e24031..dd11ffdd51ae 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1837,6 +1837,16 @@ static int synaptics_setup_intertouch(struct psmouse *psmouse,
return -ENXIO;
}
+
+ /* Disable intertouch on known-broken board revisions */
+ if (psmouse_matches_pnp_id(psmouse,
+ (const char * const []){"LEN0036", NULL}) &&
+ info->board_id == 2722) {
+ psmouse_info(psmouse,
+ "Disabling intertouch for board id %u\n",
+ info->board_id);
+ return -ENXIO;
+ }
}
psmouse_info(psmouse, "Trying to set up SMBus access\n");
--
2.53.0
^ permalink raw reply related
* hid-lg-g15: possible use-after-free of devm data via work scheduled from a report
From: Maoyi Xie @ 2026-06-17 12:10 UTC (permalink / raw)
To: Hans de Goede, Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
Hi all,
I think the lg-g15 driver can read freed memory on disconnect. I would
appreciate it if you could check my reading before I send a patch.
The per device state is allocated with devm in lg_g15_probe().
g15 = devm_kzalloc(&hdev->dev, sizeof(*g15), GFP_KERNEL);
That struct contains a work item, and the report handlers schedule it
straight from device input. For example in lg_g15_event().
/* Backlight cycle button pressed? */
if (data[1] & 0x80)
schedule_work(&g15->work);
The same schedule_work(&g15->work) call also runs in lg_g15_v2_event() and
lg_g510_leds_event(). The worker lg_g15_leds_changed_work() does a
container_of() back to g15 and dereferences g15->mutex and g15->leds.
The driver has a probe but no remove callback, and there is no
cancel_work_sync() anywhere in the file. So if a report schedules the work
and the keyboard is then removed, devm frees g15 while the work is still
pending or running, and the worker touches the freed object.
The attacker model is a Logitech G15 class keyboard that sends one report
with the backlight cycle bit set and then disconnects. That can be a
malicious device or an unlucky unplug.
I reproduced the freed while pending pattern under KASAN on 7.1-rc7. The
workqueue picked up the orphaned work after the object was freed, and KASAN
reported a slab-use-after-free read.
The fix I tried is a small remove callback that cancels the work before the
devm teardown frees g15.
static void lg_g15_remove(struct hid_device *hdev)
{
struct lg_g15_data *g15 = hid_get_drvdata(hdev);
if (g15)
cancel_work_sync(&g15->work);
hid_hw_stop(hdev);
}
and wiring it up with .remove = lg_g15_remove. The g15 NULL guard mirrors the
existing check in lg_g15_raw_event().
Does this look like a real issue to you, and is the remove plus
cancel_work_sync the approach you would want? If so I am happy to send a
proper patch with a Fixes tag against 97b741aba918.
Thanks,
Maoyi
https://maoyixie.com/
^ permalink raw reply
* Re: [PATCH v4 4/5] HID: asus: add support for xgm led
From: Antheas Kapenekakis @ 2026-06-17 13:45 UTC (permalink / raw)
To: Denis Benato
Cc: linux-kernel, linux-input, Benjamin Tissoires, Jiri Kosina,
Luke D . Jones, Mateusz Schyboll, Denis Benato, Connor Belli
In-Reply-To: <5006ff55-846e-4812-bc89-b270fbef6ccc@linux.dev>
On Wed, 17 Jun 2026 at 02:18, Denis Benato <denis.benato@linux.dev> wrote:
>
>
> On 6/15/26 23:55, Antheas Kapenekakis wrote:
> > On Mon, 15 Jun 2026 at 18:51, Denis Benato <denis.benato@linux.dev> wrote:
> >> XG mobile stations have very bright leds behind the fan that can be
> >> turned either ON or OFF: add a cled interface to allow controlling the
> >> brightness of those red leds.
> >>
> >> Signed-off-by: Denis Benato <denis.benato@linux.dev>
> >> ---
> >> drivers/hid/hid-asus.c | 91 ++++++++++++++++++++++++++++++++++++++++++
> >> 1 file changed, 91 insertions(+)
> >>
> >> diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
> >> index 6896730efafc..e68a6d93369d 100644
> >> --- a/drivers/hid/hid-asus.c
> >> +++ b/drivers/hid/hid-asus.c
> >> @@ -51,6 +51,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
> >> #define FEATURE_KBD_LED_REPORT_ID1 0x5d
> >> #define FEATURE_KBD_LED_REPORT_ID2 0x5e
> >>
> >> +#define ROG_XGM_REPORT_SIZE 300
> >> +
> >> #define ROG_ALLY_REPORT_SIZE 64
> >> #define ROG_ALLY_X_MIN_MCU 313
> >> #define ROG_ALLY_MIN_MCU 319
> >> @@ -143,6 +145,11 @@ struct asus_worker {
> >> bool removed;
> >> };
> >>
> >> +struct asus_xgm_led {
> >> + struct led_classdev cdev;
> >> + struct hid_device *hdev;
> >> +};
> >> +
> >> struct asus_touchpad_info {
> >> int max_x;
> >> int max_y;
> >> @@ -169,6 +176,7 @@ struct asus_drvdata {
> >> unsigned long battery_next_query;
> >> struct asus_hid_listener listener;
> >> bool fn_lock;
> >> + struct asus_xgm_led *xgm_led;
> >> };
> >>
> >> static int asus_report_battery(struct asus_drvdata *, u8 *, int);
> >> @@ -1119,6 +1127,26 @@ static int asus_battery_probe(struct hid_device *hdev)
> >> return ret;
> >> }
> >>
> >> +static int asus_xgm_led_set(struct led_classdev *led_cdev, enum led_brightness value)
> >> +{
> >> + const u8 buf[ROG_XGM_REPORT_SIZE] = {
> >> + FEATURE_KBD_LED_REPORT_ID2, 0xC5, (value) ? 0x50 : 0x00
> >> + };
> >> + struct asus_xgm_led *xgm = container_of(led_cdev, struct asus_xgm_led, cdev);
> >> + int ret;
> >> +
> >> + ret = asus_kbd_set_report(xgm->hdev, buf, ROG_XGM_REPORT_SIZE);
> >> + if (ret < 0) {
> >> + hid_err(xgm->hdev, "Unable to set XG mobile led state: %d\n", ret);
> >> + return ret;
> >> + } else if (ret != ROG_XGM_REPORT_SIZE) {
> >> + hid_err(xgm->hdev, "Unexpected partial transfer to XG mobile: %d\n", ret);
> >> + return -EIO;
> >> + }
> >> +
> >> + return 0;
> >> +}
> >> +
> >> static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
> >> {
> >> struct input_dev *input = hi->input;
> >> @@ -1343,9 +1371,52 @@ static int asus_start_multitouch(struct hid_device *hdev)
> >> return 0;
> >> }
> >>
> >> +static int asus_xgm_init(struct hid_device *hdev, struct asus_drvdata *drvdata)
> >> +{
> >> + const char *name;
> >> + int ret;
> >> +
> >> + drvdata->xgm_led = devm_kzalloc(&hdev->dev, sizeof(*drvdata->xgm_led), GFP_KERNEL);
> >> + if (drvdata->xgm_led == NULL)
> >> + return -ENOMEM;
> >> +
> >> + name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "asus:xgm-%s:led",
> >> + strlen(hdev->uniq) ? hdev->uniq : dev_name(&hdev->dev));
> >> +
> >> + if (name == NULL) {
> >> + ret = -ENOMEM;
> >> + goto asus_xgm_init_err;
> >> + }
> >> +
> >> + drvdata->xgm_led->hdev = hdev;
> >> + drvdata->xgm_led->cdev.name = name;
> >> + drvdata->xgm_led->cdev.brightness = 1;
> >> + drvdata->xgm_led->cdev.max_brightness = 1;
> >> + drvdata->xgm_led->cdev.brightness_set_blocking = asus_xgm_led_set;
> >> +
> >> + /* LED state is arbitrary on boot, set a default */
> >> + ret = asus_xgm_led_set(&drvdata->xgm_led->cdev, drvdata->xgm_led->cdev.brightness);
> >> + if (ret) {
> >> + hid_err(hdev, "Asus failed to set xgm led: %d\n", ret);
> >> + goto asus_xgm_init_err;
> >> + }
> >> +
> >> + ret = devm_led_classdev_register(&hdev->dev, &drvdata->xgm_led->cdev);
> >> + if (ret) {
> >> + hid_err(hdev, "Asus failed to register xgm led: %d\n", ret);
> >> + goto asus_xgm_init_err;
> >> + }
> >> +
> >> + return 0;
> >> +asus_xgm_init_err:
> >> + drvdata->xgm_led = NULL;
> >> + return ret;
> >> +}
> >> +
> >> static int __maybe_unused asus_resume(struct hid_device *hdev)
> >> {
> >> struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
> >> + int ret;
> >>
> >> /*
> >> * If we have a backlight listener registered, restore the previous state,
> >> @@ -1355,7 +1426,17 @@ static int __maybe_unused asus_resume(struct hid_device *hdev)
> >> if (drvdata->listener.brightness_set)
> >> asus_kbd_backlight_set(&drvdata->listener, drvdata->kbd_backlight_brightness);
> >>
> >> + if (drvdata->xgm_led) {
> >> + ret = asus_xgm_led_set(&drvdata->xgm_led->cdev, drvdata->xgm_led->cdev.brightness);
> >> + if (ret) {
> >> + hid_err(hdev, "Asus failed to restore xgm brightness: %d\n", ret);
> >> + goto asus_resume_err;
> >> + }
> >> + }
> >> +
> >> return 0;
> >> +asus_resume_err:
> >> + return ret;
> >> }
> >>
> >> static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
> >> @@ -1484,6 +1565,16 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
> >> }
> >> }
> >>
> >> + if (asus_has_report_id(hdev, FEATURE_KBD_REPORT_ID) &&
> >> + ((hdev->product == USB_DEVICE_ID_ASUSTEK_XGM_2022) ||
> >> + (hdev->product == USB_DEVICE_ID_ASUSTEK_XGM_2023))) {
> >> + ret = asus_xgm_init(hdev, drvdata);
> >> + if (ret) {
> >> + hid_err(hdev, "Failed to initialize xg mobile: %d\n", ret);
> >> + goto err_stop_hw;
> >> + }
> >> + }
> >> +
> > reset_resume has a special meaning and perhaps should not have been
> > used for this driver at all. Check if resume works and if it does use
> > that instead.
> I am not using reset_resume for xgm.
>
> reset_resume will become important to recover the ally,
For that, review the V2 s2idle series I have sent, it should drop that
codepath and work for all ally units
Sorry, misread the hunk again, I was looking at probe and confused it
with the resume check. The patch should be fine, you use resume.
Antheas
> but for xg mobile is unused (and useless).
> > Other than that and the refactor patch I'd rather see separately, the
> > other 4 patches look fine to me.
> Fair, I'll wait for maintainers to tell what they like the most
> and go from there.
>
> I agree there are things not really much related here
> but at least this way the order to apply them is clear.
> > Reviewed-by: Antheas Kapenekakis <lkml@antheas.dev>
> Thanks,
> Denis
> > Best,
> > Antheas
> >
> >> /* Laptops keyboard backlight is always at 0x5a */
> >> if (is_vendor && (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) &&
> >> (asus_has_report_id(hdev, FEATURE_KBD_REPORT_ID)) &&
> >> --
> >> 2.47.3
> >>
> >>
>
^ permalink raw reply
* [PATCH v4 00/10] Input: cap11xx - Add support for CAP1114
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
Patches 1-4 perform driver cleanup and DT binding tweaks.
Patches 5-6 add reset-gpios support for CAP11xx.
Patches 7-10 add support for CAP1114.
Changes in v4:
- Revert cleanup operation for CAP11XX_REG_SENSOR_DELTA.
- Move the LED unit-address update operation to the CAP1114 support patch.
- Limit the CAP1114 LED unit-address range from 0x0 to 0xa.
- Link to v3:
https://lore.kernel.org/all/20260615142103.352163-1-jerrysteve1101@gmail.com/
Changes in v3:
- Simplified the logic of the reset pin operation.
- Adjust linux,keycodes configuration for CAP11xx.
- Drop unnecessary CAP11XX_REG_SENSOR_THRESH(8).
- Checks for the presence of microchip,calib-sensitivity and
microchip,signal-guard properties before processing them.
- Link to v2:
https://lore.kernel.org/all/20260612072237.1177304-1-jerrysteve1101@gmail.com/
Changes in v2:
- Drop LED property tweaks, keep only reg changes and node regex
update in DT bindings.
- Split microchip,cap1126 LED reg constraints into a separate patch.
- Replace usleep_range() with msleep() for 500 ms delay during
reset pin handling.
- Add missing <linux/delay.h> for usleep_range() and msleep().
- Add CAP1114 to unsupported enum for microchip,signal-guard and
microchip,calib-sensitivity
- Add constraint for linux,keycodes to support CAP1114.
- When reading CAP1114 button status, mask STATUS1 to bits 0-5
and OR with STATUS2.
- Adjust code style.
- Link to v1:
https://lore.kernel.org/all/20260606150458.250606-1-jerrysteve1101@gmail.com
Jun Yan (10):
Input: cap11xx - clean up duplicate log and add probe error logs
Input: cap11xx - remove unused register macros
dt-bindings: input: microchip,cap11xx: Update datasheet URL and LED
reg range
dt-bindings: input: microchip,cap11xx: Add microchip,cap1126 LED reg
constraints
dt-bindings: input: microchip,cap11xx: Add reset-gpios property
Input: cap11xx - add reset gpio support
Input: cap11xx - refactor code for better CAP1114 support.
Input: cap11xx - guard unsupported DT properties before parsing
dt-bindings: input: microchip,cap11xx: Add CAP1114 support
Input: cap11xx - add support for CAP1114
.../bindings/input/microchip,cap11xx.yaml | 90 +++++-
drivers/input/keyboard/cap11xx.c | 274 +++++++++++-------
2 files changed, 254 insertions(+), 110 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH v4 02/10] Input: cap11xx - remove unused register macros
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Remove unused register address macros and unused definitions in
the cap11xx_reg_defaults array and cap11xx_volatile_reg.
This cleanup reduces code clutter and makes the driver easier to
maintain without affecting functionality.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 51 --------------------------------
1 file changed, 51 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 485d8ba97723..fae26f035186 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -20,53 +20,24 @@
#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
#define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
#define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4)
-#define CAP11XX_REG_GENERAL_STATUS 0x02
#define CAP11XX_REG_SENSOR_INPUT 0x03
-#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a
#define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X))
#define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f
#define CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK 0x70
-#define CAP11XX_REG_CONFIG 0x20
-#define CAP11XX_REG_SENSOR_ENABLE 0x21
-#define CAP11XX_REG_SENSOR_CONFIG 0x22
-#define CAP11XX_REG_SENSOR_CONFIG2 0x23
-#define CAP11XX_REG_SAMPLING_CONFIG 0x24
-#define CAP11XX_REG_CALIBRATION 0x26
-#define CAP11XX_REG_INT_ENABLE 0x27
#define CAP11XX_REG_REPEAT_RATE 0x28
#define CAP11XX_REG_SIGNAL_GUARD_ENABLE 0x29
-#define CAP11XX_REG_MT_CONFIG 0x2a
-#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b
-#define CAP11XX_REG_MT_PATTERN 0x2d
-#define CAP11XX_REG_RECALIB_CONFIG 0x2f
#define CAP11XX_REG_SENSOR_THRESH(X) (0x30 + (X))
-#define CAP11XX_REG_SENSOR_NOISE_THRESH 0x38
-#define CAP11XX_REG_STANDBY_CHANNEL 0x40
-#define CAP11XX_REG_STANDBY_CONFIG 0x41
-#define CAP11XX_REG_STANDBY_SENSITIVITY 0x42
-#define CAP11XX_REG_STANDBY_THRESH 0x43
#define CAP11XX_REG_CONFIG2 0x44
#define CAP11XX_REG_CONFIG2_ALT_POL BIT(6)
-#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
-#define CAP11XX_REG_LED_POLARITY 0x73
#define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74
#define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG 0x80
#define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG2 0x81
-
-#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90
-#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91
-#define CAP11XX_REG_LED_DUTY_CYCLE_3 0x92
#define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93
-#define CAP11XX_REG_LED_DUTY_MIN_MASK (0x0f)
-#define CAP11XX_REG_LED_DUTY_MIN_MASK_SHIFT (0)
#define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0)
#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4)
#define CAP11XX_REG_LED_DUTY_MAX_VALUE (15)
-#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X))
-#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9
-#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba
#define CAP11XX_REG_PRODUCT_ID 0xfd
#define CAP11XX_REG_MANUFACTURER_ID 0xfe
#define CAP11XX_REG_REVISION 0xff
@@ -111,37 +82,15 @@ struct cap11xx_hw_model {
static const struct reg_default cap11xx_reg_defaults[] = {
{ CAP11XX_REG_MAIN_CONTROL, 0x00 },
- { CAP11XX_REG_GENERAL_STATUS, 0x00 },
- { CAP11XX_REG_SENSOR_INPUT, 0x00 },
- { CAP11XX_REG_NOISE_FLAG_STATUS, 0x00 },
{ CAP11XX_REG_SENSITIVITY_CONTROL, 0x2f },
- { CAP11XX_REG_CONFIG, 0x20 },
- { CAP11XX_REG_SENSOR_ENABLE, 0x3f },
- { CAP11XX_REG_SENSOR_CONFIG, 0xa4 },
- { CAP11XX_REG_SENSOR_CONFIG2, 0x07 },
- { CAP11XX_REG_SAMPLING_CONFIG, 0x39 },
- { CAP11XX_REG_CALIBRATION, 0x00 },
- { CAP11XX_REG_INT_ENABLE, 0x3f },
{ CAP11XX_REG_REPEAT_RATE, 0x3f },
- { CAP11XX_REG_MT_CONFIG, 0x80 },
- { CAP11XX_REG_MT_PATTERN_CONFIG, 0x00 },
- { CAP11XX_REG_MT_PATTERN, 0x3f },
- { CAP11XX_REG_RECALIB_CONFIG, 0x8a },
{ CAP11XX_REG_SENSOR_THRESH(0), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(1), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(2), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(3), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(4), 0x40 },
{ CAP11XX_REG_SENSOR_THRESH(5), 0x40 },
- { CAP11XX_REG_SENSOR_NOISE_THRESH, 0x01 },
- { CAP11XX_REG_STANDBY_CHANNEL, 0x00 },
- { CAP11XX_REG_STANDBY_CONFIG, 0x39 },
- { CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 },
- { CAP11XX_REG_STANDBY_THRESH, 0x40 },
{ CAP11XX_REG_CONFIG2, 0x40 },
- { CAP11XX_REG_LED_POLARITY, 0x00 },
- { CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 },
- { CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 },
};
static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
--
2.54.0
^ permalink raw reply related
* [PATCH v4 03/10] dt-bindings: input: microchip,cap11xx: Update datasheet URL and LED reg range
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, Conor Dooley, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
- Add datasheet links for all supported CAP11xx variants.
- Update LED node regex and replace enum constraints with minimum/maximum
for LED reg ranges in preparation for CAP1114 support.
CAP1114 has 11 LED channels. minimum/maximum constraints are easier to
maintain than long enum lists when expanding channel count later.
Drop unnecessary led unit-address pattern.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/input/microchip,cap11xx.yaml | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index 7ade03f1b32b..eabf06a1163e 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -10,6 +10,15 @@ description: |
The Microchip CAP1xxx Family of RightTouchTM multiple-channel capacitive
touch controllers and LED drivers. The device communication via I2C only.
+ For more product information please see the links below:
+ CAP1106: https://ww1.microchip.com/downloads/en/DeviceDoc/00001624B.pdf
+ CAP1126: https://ww1.microchip.com/downloads/en/DeviceDoc/00001623B.pdf
+ CAP1188: https://ww1.microchip.com/downloads/en/DeviceDoc/00001620C.pdf
+ CAP1203: https://ww1.microchip.com/downloads/en/DeviceDoc/00001572B.pdf
+ CAP1206: https://ww1.microchip.com/downloads/en/DeviceDoc/00001567B.pdf
+ CAP1293: https://ww1.microchip.com/downloads/en/DeviceDoc/00001566B.pdf
+ CAP1298: https://ww1.microchip.com/downloads/en/DeviceDoc/00001571B.pdf
+
maintainers:
- Rob Herring <robh@kernel.org>
@@ -131,7 +140,9 @@ patternProperties:
properties:
reg:
- enum: [0, 1, 2, 3, 4, 5, 6, 7]
+ description: LED channel number
+ minimum: 0
+ maximum: 7
label: true
@@ -158,7 +169,7 @@ allOf:
- microchip,cap1298
then:
patternProperties:
- "^led@[0-7]$": false
+ "^led@": false
- if:
properties:
--
2.54.0
^ permalink raw reply related
* [PATCH v4 04/10] dt-bindings: input: microchip,cap11xx: Add microchip,cap1126 LED reg constraints
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, Conor Dooley, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Apply per-chip LED channel limits:
- CAP1126: max 2 channels (0-1)
- CAP1188: max 8 channels (0-7)
- CAP1106, CAP12xx: no LED support
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/input/microchip,cap11xx.yaml | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index eabf06a1163e..798035e942af 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -171,6 +171,19 @@ allOf:
patternProperties:
"^led@": false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1126
+ then:
+ patternProperties:
+ "^led@":
+ properties:
+ reg:
+ maximum: 1
+
- if:
properties:
compatible:
--
2.54.0
^ permalink raw reply related
* [PATCH v4 05/10] dt-bindings: input: microchip,cap11xx: Add reset-gpios property
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, Conor Dooley, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Add support for the optional reset-gpios property to describe
the active-high reset pin for CAP1126/CAP1188 devices.
Driving the GPIO high asserts reset and deep sleep, while driving
it low releases reset for normal operation.
Restrict this property to be available only on CAP1126 and CAP1188
chips, as other CAP11xx variants do not have a hardware reset pin.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/input/microchip,cap11xx.yaml | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index 798035e942af..b97e5b2735f1 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -49,6 +49,13 @@ properties:
device's ALERT#/CM_IRQ# pin is connected to.
The device only has one interrupt source.
+ reset-gpios:
+ description: |
+ GPIO connected to the active-high RESET pin of the chip;
+ driving it high asserts reset and deep sleep, while driving
+ it low releases reset for normal operation.
+ maxItems: 1
+
autorepeat:
description: |
Enables the Linux input system's autorepeat feature on the input device.
@@ -157,6 +164,20 @@ patternProperties:
allOf:
- $ref: input.yaml
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1106
+ - microchip,cap1203
+ - microchip,cap1206
+ - microchip,cap1293
+ - microchip,cap1298
+ then:
+ properties:
+ reset-gpios: false
+
- if:
properties:
compatible:
@@ -207,6 +228,8 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
+
i2c {
#address-cells = <1>;
#size-cells = <0>;
@@ -228,6 +251,8 @@ examples:
<109>, /* KEY_PAGEDOWN */
<104>; /* KEY_PAGEUP */
+ reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+
#address-cells = <1>;
#size-cells = <0>;
--
2.54.0
^ permalink raw reply related
* [PATCH v4 06/10] Input: cap11xx - add reset gpio support
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Some CAP11xx devices (CAP1126/CAP1188) have a dedicated RESET pin.
Add hardware reset operation to improve device reliability and
ensure proper initialization on probe.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index fae26f035186..1db4a9090705 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -5,6 +5,7 @@
* (c) 2014 Daniel Mack <linux@zonque.org>
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -44,6 +45,9 @@
#define CAP11XX_MANUFACTURER_ID 0x5d
+#define CAP11XX_T_RST_FILT_MIN_US 10000
+#define CAP11XX_T_RST_ON_MIN_MS 400
+
#ifdef CONFIG_LEDS_CLASS
struct cap11xx_led {
struct cap11xx_priv *priv;
@@ -56,6 +60,7 @@ struct cap11xx_priv {
struct regmap *regmap;
struct device *dev;
struct input_dev *idev;
+ struct gpio_desc *reset_gpio;
const struct cap11xx_hw_model *model;
struct cap11xx_led *leds;
@@ -459,6 +464,17 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get 'reset' GPIO\n");
+
+ if (priv->reset_gpio) {
+ usleep_range(CAP11XX_T_RST_FILT_MIN_US, CAP11XX_T_RST_FILT_MIN_US * 2);
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+ msleep(CAP11XX_T_RST_ON_MIN_MS);
+ }
+
error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val);
if (error)
return dev_err_probe(dev, error, "Failed to read product ID\n");
--
2.54.0
^ permalink raw reply related
* [PATCH v4 07/10] Input: cap11xx - refactor code for better CAP1114 support.
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Extend cap11xx_hw_model structure to support CAP1114 with
different register offsets and hardware characteristics:
- led_output_control_reg_base: different address on CAP1114
- sensor_input_reg_base: different address on CAP1114
- num_sensor_thresholds: separate value from num_channels for CAP1114
- has_repeat_en: repeat enable support, disabled by default on CAP1114
Include linux/bits.h, update the register operations related to LEDs.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 73 +++++++++++++++++++++++---------
1 file changed, 53 insertions(+), 20 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 1db4a9090705..0f19ee036e78 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -5,6 +5,7 @@
* (c) 2014 Daniel Mack <linux@zonque.org>
*/
+#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -36,7 +37,6 @@
#define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93
#define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0)
-#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4)
#define CAP11XX_REG_LED_DUTY_MAX_VALUE (15)
#define CAP11XX_REG_PRODUCT_ID 0xfd
@@ -77,10 +77,14 @@ struct cap11xx_priv {
struct cap11xx_hw_model {
u8 product_id;
+ u8 led_output_control_reg_base;
+ u8 sensor_input_reg_base;
unsigned int num_channels;
unsigned int num_leds;
+ unsigned int num_sensor_thresholds;
bool has_gain;
bool has_irq_config;
+ bool has_repeat_en;
bool has_sensitivity_control;
bool has_signal_guard;
};
@@ -211,8 +215,8 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
}
if (!of_property_read_u32_array(node, "microchip,input-threshold",
- priv->thresholds, priv->model->num_channels)) {
- for (i = 0; i < priv->model->num_channels; i++) {
+ priv->thresholds, priv->model->num_sensor_thresholds)) {
+ for (i = 0; i < priv->model->num_sensor_thresholds; i++) {
if (priv->thresholds[i] > 127) {
dev_err(dev, "Invalid input-threshold value %u\n",
priv->thresholds[i]);
@@ -286,10 +290,12 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
of_property_read_u32_array(node, "linux,keycodes",
priv->keycodes, priv->model->num_channels);
- /* Disable autorepeat. The Linux input system has its own handling. */
- error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
- if (error)
- return error;
+ if (priv->model->has_repeat_en) {
+ /* Disable autorepeat. The Linux input system has its own handling. */
+ error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
+ if (error)
+ return error;
+ }
return 0;
}
@@ -308,7 +314,7 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
if (ret < 0)
goto out;
- ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status);
+ ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base, &status);
if (ret < 0)
goto out;
@@ -362,7 +368,7 @@ static int cap11xx_led_set(struct led_classdev *cdev,
* 0 (OFF) and 1 (ON).
*/
return regmap_update_bits(priv->regmap,
- CAP11XX_REG_LED_OUTPUT_CONTROL,
+ priv->model->led_output_control_reg_base,
BIT(led->reg),
value ? BIT(led->reg) : 0);
}
@@ -374,6 +380,7 @@ static int cap11xx_init_leds(struct device *dev,
struct cap11xx_led *led;
int cnt = of_get_child_count(node);
int error;
+ u32 duty_val;
if (!num_leds || !cnt)
return 0;
@@ -387,15 +394,18 @@ static int cap11xx_init_leds(struct device *dev,
priv->leds = led;
+ /* Set all LEDs to off */
error = regmap_update_bits(priv->regmap,
- CAP11XX_REG_LED_OUTPUT_CONTROL, 0xff, 0);
+ priv->model->led_output_control_reg_base,
+ GENMASK(min(num_leds, 8) - 1, 0), 0);
if (error)
return error;
+ duty_val = FIELD_PREP(CAP11XX_REG_LED_DUTY_MAX_MASK,
+ CAP11XX_REG_LED_DUTY_MAX_VALUE);
+
error = regmap_update_bits(priv->regmap, CAP11XX_REG_LED_DUTY_CYCLE_4,
- CAP11XX_REG_LED_DUTY_MAX_MASK,
- CAP11XX_REG_LED_DUTY_MAX_VALUE <<
- CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT);
+ CAP11XX_REG_LED_DUTY_MAX_MASK, duty_val);
if (error)
return error;
@@ -561,41 +571,64 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
}
static const struct cap11xx_hw_model cap1106_model = {
- .product_id = 0x55, .num_channels = 6, .num_leds = 0,
+ .product_id = 0x55,
+ .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
.has_gain = true,
.has_irq_config = true,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1126_model = {
- .product_id = 0x53, .num_channels = 6, .num_leds = 2,
+ .product_id = 0x53,
+ .num_channels = 6, .num_leds = 2, .num_sensor_thresholds = 6,
+ .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
.has_gain = true,
.has_irq_config = true,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1188_model = {
- .product_id = 0x50, .num_channels = 8, .num_leds = 8,
+ .product_id = 0x50,
+ .num_channels = 8, .num_leds = 8, .num_sensor_thresholds = 8,
+ .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
.has_gain = true,
.has_irq_config = true,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1203_model = {
- .product_id = 0x6d, .num_channels = 3, .num_leds = 0,
+ .product_id = 0x6d,
+ .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1206_model = {
- .product_id = 0x67, .num_channels = 6, .num_leds = 0,
+ .product_id = 0x67,
+ .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
+ .has_repeat_en = true,
};
static const struct cap11xx_hw_model cap1293_model = {
- .product_id = 0x6f, .num_channels = 3, .num_leds = 0,
+ .product_id = 0x6f,
+ .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
.has_gain = true,
+ .has_repeat_en = true,
.has_sensitivity_control = true,
.has_signal_guard = true,
};
static const struct cap11xx_hw_model cap1298_model = {
- .product_id = 0x71, .num_channels = 8, .num_leds = 0,
+ .product_id = 0x71,
+ .num_channels = 8, .num_leds = 0, .num_sensor_thresholds = 8,
+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT,
.has_gain = true,
+ .has_repeat_en = true,
.has_sensitivity_control = true,
.has_signal_guard = true,
};
--
2.54.0
^ permalink raw reply related
* [PATCH v4 08/10] Input: cap11xx - guard unsupported DT properties before parsing
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
Check of_property_present() before parsing microchip,calib-sensitivity
and microchip,signal-guard, so that models which do not support these
properties (e.g. CAP1114) skip the parsing entirely.
This prevents a potential buffer overflow in calib_sensitivities[8] and
signal_guard_inputs_mask when a model with more than 8 channels
(CAP1114 has 14) would otherwise call of_property_read_u32_array()
with num_channels as the element count.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
---
drivers/input/keyboard/cap11xx.c | 52 +++++++++++++++++---------------
1 file changed, 27 insertions(+), 25 deletions(-)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 0f19ee036e78..275eb79a7193 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -231,10 +231,13 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
}
}
- if (!of_property_read_u32_array(node, "microchip,calib-sensitivity",
- priv->calib_sensitivities,
- priv->model->num_channels)) {
- if (priv->model->has_sensitivity_control) {
+ if (of_property_present(node, "microchip,calib-sensitivity")) {
+ if (!priv->model->has_sensitivity_control) {
+ dev_warn(dev,
+ "This model doesn't support 'calib-sensitivity'\n");
+ } else if (!of_property_read_u32_array(node, "microchip,calib-sensitivity",
+ priv->calib_sensitivities,
+ priv->model->num_channels)) {
for (i = 0; i < priv->model->num_channels; i++) {
if (!is_power_of_2(priv->calib_sensitivities[i]) ||
priv->calib_sensitivities[i] > 4) {
@@ -254,32 +257,31 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
if (error)
return error;
}
- } else {
- dev_warn(dev,
- "This model doesn't support 'calib-sensitivity'\n");
}
}
- for (i = 0; i < priv->model->num_channels; i++) {
- if (!of_property_read_u32_index(node, "microchip,signal-guard",
- i, &u32_val)) {
- if (u32_val > 1)
- return -EINVAL;
- if (u32_val)
- priv->signal_guard_inputs_mask |= 0x01 << i;
- }
- }
-
- if (priv->signal_guard_inputs_mask) {
- if (priv->model->has_signal_guard) {
- error = regmap_write(priv->regmap,
- CAP11XX_REG_SIGNAL_GUARD_ENABLE,
- priv->signal_guard_inputs_mask);
- if (error)
- return error;
- } else {
+ if (of_property_present(node, "microchip,signal-guard")) {
+ if (!priv->model->has_signal_guard) {
dev_warn(dev,
"This model doesn't support 'signal-guard'\n");
+ } else {
+ for (i = 0; i < priv->model->num_channels; i++) {
+ if (!of_property_read_u32_index(node, "microchip,signal-guard",
+ i, &u32_val)) {
+ if (u32_val > 1)
+ return -EINVAL;
+ if (u32_val)
+ priv->signal_guard_inputs_mask |= 0x01 << i;
+ }
+ }
+
+ if (priv->signal_guard_inputs_mask) {
+ error = regmap_write(priv->regmap,
+ CAP11XX_REG_SIGNAL_GUARD_ENABLE,
+ priv->signal_guard_inputs_mask);
+ if (error)
+ return error;
+ }
}
}
--
2.54.0
^ permalink raw reply related
* [PATCH v4 09/10] dt-bindings: input: microchip,cap11xx: Add CAP1114 support
From: Jun Yan @ 2026-06-17 15:02 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Jun Yan, Conor Dooley, linux-input, devicetree, linux-kernel
In-Reply-To: <20260617150318.753148-1-jerrysteve1101@gmail.com>
CAP1114 is a 14-channel capacitive touch sensor with 11 LED outputs
and hardware reset support.
Add the compatible string for CAP1114, add its datasheet URL,
update the maximum of LED channel reg, and add constraint for
linux,keycodes.
Previously, the LED reg property had a default maximum of 7 for CAP1188.
With the addition of CAP1114, the default maximum is now 11.
An if-then constraint is added to limit the LED count for CAP1188.
Update description for microchip,input-threshold: CAP1114 only provides
eight threshold entries, which does not match its total channel count.
CAP1114 does not support microchip,signal-guard and
microchip,calib-sensitivity.
Add CAP1114 to the unsupported enum list.
Signed-off-by: Jun Yan <jerrysteve1101@gmail.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/input/microchip,cap11xx.yaml | 39 +++++++++++++++++--
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
index b97e5b2735f1..2a37ac252c37 100644
--- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
+++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml
@@ -12,6 +12,7 @@ description: |
For more product information please see the links below:
CAP1106: https://ww1.microchip.com/downloads/en/DeviceDoc/00001624B.pdf
+ CAP1114: https://ww1.microchip.com/downloads/en/DeviceDoc/00002444A.pdf
CAP1126: https://ww1.microchip.com/downloads/en/DeviceDoc/00001623B.pdf
CAP1188: https://ww1.microchip.com/downloads/en/DeviceDoc/00001620C.pdf
CAP1203: https://ww1.microchip.com/downloads/en/DeviceDoc/00001572B.pdf
@@ -26,6 +27,7 @@ properties:
compatible:
enum:
- microchip,cap1106
+ - microchip,cap1114
- microchip,cap1126
- microchip,cap1188
- microchip,cap1203
@@ -62,7 +64,7 @@ properties:
linux,keycodes:
minItems: 3
- maxItems: 8
+ maxItems: 14
description: |
Specifies an array of numeric keycode values to
be used for the channels. If this property is
@@ -122,6 +124,8 @@ properties:
is required for a touch to be registered, making the touch sensor less
sensitive.
The number of entries must correspond to the number of channels.
+ CAP1114 is an exception where channels 8~14 reuse the eighth entry's
+ threshold, so counts differ.
microchip,calib-sensitivity:
$ref: /schemas/types.yaml#/definitions/uint32-array
@@ -140,7 +144,7 @@ properties:
The number of entries must correspond to the number of channels.
patternProperties:
- "^led@[0-7]$":
+ "^led@[0-9a]$":
type: object
description: CAP11xx LEDs
$ref: /schemas/leds/common.yaml#
@@ -149,7 +153,7 @@ patternProperties:
reg:
description: LED channel number
minimum: 0
- maximum: 7
+ maximum: 10
label: true
@@ -178,6 +182,21 @@ allOf:
properties:
reset-gpios: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1114
+ then:
+ properties:
+ linux,keycodes:
+ minItems: 14
+ else:
+ properties:
+ linux,keycodes:
+ maxItems: 8
+
- if:
properties:
compatible:
@@ -205,12 +224,26 @@ allOf:
reg:
maximum: 1
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - microchip,cap1188
+ then:
+ patternProperties:
+ "^led@":
+ properties:
+ reg:
+ maximum: 7
+
- if:
properties:
compatible:
contains:
enum:
- microchip,cap1106
+ - microchip,cap1114
- microchip,cap1126
- microchip,cap1188
- microchip,cap1203
--
2.54.0
^ permalink raw reply related
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