Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH 6.1 061/969] HID: core: clamp report_size in s32ton() to avoid undefined shift
From: Greg Kroah-Hartman @ 2026-05-30 15:53 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, stable, Jiri Kosina,
	Benjamin Tissoires, linux-input, Jiri Kosina
In-Reply-To: <20260530160300.485627683@linuxfoundation.org>

6.1-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit 69c02ffde6ed4d535fa4e693a9e572729cad3d0d upstream.

s32ton() shifts by n-1 where n is the field's report_size, a value that
comes directly from a HID device.  The HID parser bounds report_size
only to <= 256, so a broken HID device can supply a report descriptor
with a wide field that triggers shift exponents up to 256 on a 32-bit
type when an output report is built via hid_output_field() or
hid_set_field().

Commit ec61b41918587 ("HID: core: fix shift-out-of-bounds in
hid_report_raw_event") added the same n > 32 clamp to the function
snto32(), but s32ton() was never given the same fix as I guess syzbot
hadn't figured out how to fuzz a device the same way.

Fix this up by just clamping the max value of n, just like snto32()
does.

Cc: stable <stable@kernel.org>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-core.c |    3 +++
 1 file changed, 3 insertions(+)

--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1358,6 +1358,9 @@ static u32 s32ton(__s32 value, unsigned
 	if (!value || !n)
 		return 0;
 
+	if (n > 32)
+		n = 32;
+
 	a = value >> (n - 1);
 
 	if (a && a != -1)



^ permalink raw reply

* [PATCH 5.15 056/776] HID: alps: fix NULL pointer dereference in alps_raw_event()
From: Greg Kroah-Hartman @ 2026-05-30 15:56 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, stable, Jiri Kosina,
	Benjamin Tissoires, Masaki Ota, linux-input, Jiri Kosina
In-Reply-To: <20260530160240.228940103@linuxfoundation.org>

5.15-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit 1badfc4319224820d5d890f8eab6aa52e4e83339 upstream.

Commit ecfa6f34492c ("HID: Add HID_CLAIMED_INPUT guards in raw_event
callbacks missing them") attempted to fix up the HID drivers that had
missed the previous fix that was done in 2ff5baa9b527 ("HID: appleir:
Fix potential NULL dereference at raw event handle"), but the alps
driver was missed.

Fix this up by properly checking in the hid-alps driver that it had been
claimed correctly before attempting to process the raw event.

Fixes: 73196ebe134d ("HID: alps: add support for Alps T4 Touchpad device")
Cc: stable <stable@kernel.org>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: Masaki Ota <masaki.ota@jp.alps.com>
Cc: linux-input@vger.kernel.org
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-alps.c |    3 +++
 1 file changed, 3 insertions(+)

--- a/drivers/hid/hid-alps.c
+++ b/drivers/hid/hid-alps.c
@@ -437,6 +437,9 @@ static int alps_raw_event(struct hid_dev
 	int ret = 0;
 	struct alps_dev *hdata = hid_get_drvdata(hdev);
 
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !hdata->input)
+		return 0;
+
 	switch (hdev->product) {
 	case HID_PRODUCT_ID_T4_BTNLESS:
 		ret = t4_raw_event(hdata, data, size);



^ permalink raw reply

* [PATCH 5.15 057/776] HID: core: clamp report_size in s32ton() to avoid undefined shift
From: Greg Kroah-Hartman @ 2026-05-30 15:56 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, stable, Jiri Kosina,
	Benjamin Tissoires, linux-input, Jiri Kosina
In-Reply-To: <20260530160240.228940103@linuxfoundation.org>

5.15-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit 69c02ffde6ed4d535fa4e693a9e572729cad3d0d upstream.

s32ton() shifts by n-1 where n is the field's report_size, a value that
comes directly from a HID device.  The HID parser bounds report_size
only to <= 256, so a broken HID device can supply a report descriptor
with a wide field that triggers shift exponents up to 256 on a 32-bit
type when an output report is built via hid_output_field() or
hid_set_field().

Commit ec61b41918587 ("HID: core: fix shift-out-of-bounds in
hid_report_raw_event") added the same n > 32 clamp to the function
snto32(), but s32ton() was never given the same fix as I guess syzbot
hadn't figured out how to fuzz a device the same way.

Fix this up by just clamping the max value of n, just like snto32()
does.

Cc: stable <stable@kernel.org>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-core.c |    3 +++
 1 file changed, 3 insertions(+)

--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1354,6 +1354,9 @@ static u32 s32ton(__s32 value, unsigned
 	if (!value || !n)
 		return 0;
 
+	if (n > 32)
+		n = 32;
+
 	a = value >> (n - 1);
 	if (a && a != -1)
 		return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;



^ permalink raw reply

* Re: [PATCH 2/4] HID: core: introduce hid_safe_input_report()
From: Carlos Llamas @ 2026-05-30 17:43 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Bastien Nocera, Benjamin Tissoires, Jiri Kosina,
	Filipe Laíns, Ping Cheng, Jason Gerecke, Viresh Kumar,
	Johan Hovold, Alex Elder, Greg Kroah-Hartman, Lee Jones,
	linux-input, linux-kernel, greybus-dev, linux-staging, linux-usb,
	stable
In-Reply-To: <CAO-hwJ+EgC0pM6L6vGFEaRFt2Nwj5b-CCf_5e5VkvrXgdHrjNg@mail.gmail.com>

On Thu, Apr 16, 2026 at 04:46:28PM +0200, Benjamin Tissoires wrote:
> On Thu, Apr 16, 2026 at 11:41 AM Bastien Nocera <hadess@hadess.net> wrote:
> >
> > On Wed, 2026-04-15 at 11:38 +0200, Benjamin Tissoires wrote:
> > > hid_input_report() is used in too many places to have a commit that
> > > doesn't cross subsystem borders. Instead of changing the API,
> > > introduce
> > > a new one when things matters in the transport layers:
> > > - usbhid
> > > - i2chid
> > >
> > > This effectively revert to the old behavior for those two transport
> > > layers.
> > >
> > > Fixes: 0a3fe972a7cb ("HID: core: Mitigate potential OOB by removing
> > > bogus memset()")
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
> > > ---
> > >  drivers/hid/hid-core.c             | 21 +++++++++++++++++++++
> > >  drivers/hid/i2c-hid/i2c-hid-core.c |  7 ++++---
> > >  drivers/hid/usbhid/hid-core.c      | 11 ++++++-----
> > >  include/linux/hid.h                |  2 ++
> > >  4 files changed, 33 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> > > index a806820df7e5..cb0ad99e7a0a 100644
> > > --- a/drivers/hid/hid-core.c
> > > +++ b/drivers/hid/hid-core.c
> > > @@ -2191,6 +2191,27 @@ int hid_input_report(struct hid_device *hid,
> > > enum hid_report_type type, u8 *data
> > >  }
> > >  EXPORT_SYMBOL_GPL(hid_input_report);
> > >
> > > +/**
> > > + * hid_safe_input_report - report data from lower layer (usb, bt...)
> > > + *
> > > + * @hid: hid device
> > > + * @type: HID report type (HID_*_REPORT)
> > > + * @data: report contents
> > > + * @bufsize: allocated size of the data buffer
> > > + * @size: useful size of data parameter
> > > + * @interrupt: distinguish between interrupt and control transfers
> > > + *
> > > + * This is data entry for lower layers.
> >
> > You probably want to explain why it should be used instead of
> > hid_input_report() in this doc blurb, and modify the hid_input_report()
> > docs to mention that this should be used.
> 
> Good point. Sending v2 ASAP.
> 
> >
> > Maybe hid_input_report() should also be marked as deprecated somehow,
> > to avoid new users?
> 
> Well, it's not entirely deprecated because, for instance, in uhid we
> only have the buffer with the provided size around. So we can't be
> less restrictive in that precise case, and then switching to _safe
> will not change a bit.
> 
> Cheers,
> Benjamin

Hi Benjamin, our CI started failing with commit 0a3fe972a7cb ("HID:
core: Mitigate potential OOB by removing bogus memset()"), so I was
hoping your patchset would fix this.

However, I just realized our call path goes through uhid precisely,
which still triggers the EINVAL error since uhid as not converted to
hid_safe_input_report().

My vague understanding though, is that uhid_event uses a static buffer
in ev->data[UHID_DATA_MAX], so maybe we can use that through
uhid_dev_input{2}()?

I ran the following path through our CI and it fixed our issue, so I
wanted to get your thoughts on this.

Carlos Llamas

---
 drivers/hid/uhid.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 524b53a3c87b..37b60c3aaf66 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -595,8 +595,8 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
 	if (!READ_ONCE(uhid->running))
 		return -EINVAL;
 
-	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
-			 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+	hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data, UHID_DATA_MAX,
+			      min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
 
 	return 0;
 }
@@ -606,8 +606,8 @@ static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
 	if (!READ_ONCE(uhid->running))
 		return -EINVAL;
 
-	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
-			 min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
+	hid_safe_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, UHID_DATA_MAX,
+			      min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
 
 	return 0;
 }

^ permalink raw reply related

* [PATCH 5.10 047/589] HID: alps: fix NULL pointer dereference in alps_raw_event()
From: Greg Kroah-Hartman @ 2026-05-30 15:58 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, stable, Jiri Kosina,
	Benjamin Tissoires, Masaki Ota, linux-input, Jiri Kosina
In-Reply-To: <20260530160224.570625122@linuxfoundation.org>

5.10-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit 1badfc4319224820d5d890f8eab6aa52e4e83339 upstream.

Commit ecfa6f34492c ("HID: Add HID_CLAIMED_INPUT guards in raw_event
callbacks missing them") attempted to fix up the HID drivers that had
missed the previous fix that was done in 2ff5baa9b527 ("HID: appleir:
Fix potential NULL dereference at raw event handle"), but the alps
driver was missed.

Fix this up by properly checking in the hid-alps driver that it had been
claimed correctly before attempting to process the raw event.

Fixes: 73196ebe134d ("HID: alps: add support for Alps T4 Touchpad device")
Cc: stable <stable@kernel.org>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: Masaki Ota <masaki.ota@jp.alps.com>
Cc: linux-input@vger.kernel.org
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-alps.c |    3 +++
 1 file changed, 3 insertions(+)

--- a/drivers/hid/hid-alps.c
+++ b/drivers/hid/hid-alps.c
@@ -437,6 +437,9 @@ static int alps_raw_event(struct hid_dev
 	int ret = 0;
 	struct alps_dev *hdata = hid_get_drvdata(hdev);
 
+	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !hdata->input)
+		return 0;
+
 	switch (hdev->product) {
 	case HID_PRODUCT_ID_T4_BTNLESS:
 		ret = t4_raw_event(hdata, data, size);



^ permalink raw reply

* [PATCH 5.10 048/589] HID: core: clamp report_size in s32ton() to avoid undefined shift
From: Greg Kroah-Hartman @ 2026-05-30 15:58 UTC (permalink / raw)
  To: stable
  Cc: Greg Kroah-Hartman, patches, stable, Jiri Kosina,
	Benjamin Tissoires, linux-input, Jiri Kosina
In-Reply-To: <20260530160224.570625122@linuxfoundation.org>

5.10-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

commit 69c02ffde6ed4d535fa4e693a9e572729cad3d0d upstream.

s32ton() shifts by n-1 where n is the field's report_size, a value that
comes directly from a HID device.  The HID parser bounds report_size
only to <= 256, so a broken HID device can supply a report descriptor
with a wide field that triggers shift exponents up to 256 on a 32-bit
type when an output report is built via hid_output_field() or
hid_set_field().

Commit ec61b41918587 ("HID: core: fix shift-out-of-bounds in
hid_report_raw_event") added the same n > 32 clamp to the function
snto32(), but s32ton() was never given the same fix as I guess syzbot
hadn't figured out how to fuzz a device the same way.

Fix this up by just clamping the max value of n, just like snto32()
does.

Cc: stable <stable@kernel.org>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Benjamin Tissoires <bentiss@kernel.org>
Cc: linux-input@vger.kernel.org
Assisted-by: gregkh_clanker_t1000
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/hid/hid-core.c |    3 +++
 1 file changed, 3 insertions(+)

--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1354,6 +1354,9 @@ static u32 s32ton(__s32 value, unsigned
 	if (!value || !n)
 		return 0;
 
+	if (n > 32)
+		n = 32;
+
 	a = value >> (n - 1);
 	if (a && a != -1)
 		return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;



^ permalink raw reply

* Re: [PATCH v5 2/3] HID: nintendo: Add rumble support for Switch 2 controllers
From: Silvan Jegen @ 2026-05-30 20:03 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Vicki Pfau, dmitry.torokhov, linux-input
In-Reply-To: <20260514005353.EF8D8C19425@smtp.kernel.org>

sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
> - [High] Mixing jiffies and milliseconds in delayed work scheduling logic causes an integer underflow, permanently stalling the haptic rumble.
> - [High] A guaranteed NULL pointer dereference occurs in the error logging path of switch2_rumble_work, as well as a TOCTOU race condition.
> - [Medium] `ns2->ctlr_type` is checked before it is dynamically initialized, causing union corruption for GameCube controllers.
> - [Low] Implicit type promotion in the max() macro causes a compiler warning.
> - [Low] Kconfig documentation claims individual motor control for the Pro Controller, but the implementation identicalizes the rumble data for both motors.
> --
> 
> commit d72f0f8e0dadde2cacc27050b92088c2e5cbea0e
> Author: Vicki Pfau <vi@endrift.com>
> Subject: HID: nintendo: Add rumble support for Switch 2 controllers
> 
> This commit introduces rumble support for Switch 2 controllers, handling both HD
> Rumble linear resonant actuators and eccentric rotating mass haptics. It adds
> state machines for rumble scheduling and output reporting via hdev.
> 
> > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> > index 26ef589f652c6..a7fe74d982475 100644
> > --- a/drivers/hid/Kconfig
> > +++ b/drivers/hid/Kconfig
> > @@ -850,10 +850,10 @@ config NINTENDO_FF
> >  	depends on HID_NINTENDO
> >  	select INPUT_FF_MEMLESS
> >  	help
> > -	Say Y here if you have a Nintendo Switch controller and want to enable
> > -	force feedback support for it. This works for both joy-cons, the pro
> > -	controller, and the NSO N64 controller. For the pro controller, both
> > -	rumble motors can be controlled individually.
> > +	Say Y here if you have a Nintendo Switch or Switch 2 controller and want
> > +	to enable force feedback support for it. This works for Joy-Cons, the Pro
> > +	Controllers, and the NSO N64 and GameCube controller. For the Pro
> > +	Controller, both rumble motors can be controlled individually.
> 
> This isn't a bug, but is the help text accurate regarding individual motor
> control? The implementation in switch2_rumble_work() appears to encode the
> exact same rumble configuration to both the left and right motor offsets,
> which would make both motors vibrate identically.

As pointers to different offsets into the rumble_buffer are passed,
I assume that the vibrations will actually not be identical.

> 
> > diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
> > index 2193afcdefabc..9801799a90758 100644
> > --- a/drivers/hid/hid-nintendo.c
> > +++ b/drivers/hid/hid-nintendo.c
> 
> [ ... ]
> 
> > @@ -3103,6 +3155,107 @@ static inline bool switch2_ctlr_is_joycon(enum switch2_ctlr_type type)
> >  	return type == NS2_CTLR_TYPE_JCL || type == NS2_CTLR_TYPE_JCR;
> >  }
> >  
> > +#if IS_ENABLED(CONFIG_NINTENDO_FF)
> > +static void switch2_encode_rumble(struct switch2_hd_rumble *rumble, uint8_t buffer[5])
> > +{
> > +	buffer[0] = rumble->hi_freq;
> > +	buffer[1] = (rumble->hi_freq >> 8) | (rumble->hi_amp << 2);
> > +	buffer[2] = (rumble->hi_amp >> 6) | (rumble->lo_freq << 4);
> > +	buffer[3] = (rumble->lo_freq >> 4) | (rumble->lo_amp << 6);
> > +	buffer[4] = rumble->lo_amp >> 2;
> > +}
> > +
> > +static int switch2_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
> > +{
> > +	struct switch2_controller *ns2 = input_get_drvdata(dev);
> > +
> > +	if (effect->type != FF_RUMBLE)
> > +		return 0;
> > +
> > +	guard(spinlock_irqsave)(&ns2->rumble_lock);
> > +	if (ns2->ctlr_type == NS2_CTLR_TYPE_GC) {
> > +		ns2->rumble.sd.amplitude = max(effect->u.rumble.strong_magnitude,
> > +			effect->u.rumble.weak_magnitude >> 1);
> 
> Will this max calculation trigger a compiler warning? The strict type checking
> in the max macro might fail because effect->u.rumble.weak_magnitude >> 1
> promotes to an int, while strong_magnitude is a u16.

Apparently it is not strict enough to emit a warning on my machine at
least ...

> 
> > +	} else {
> > +		ns2->rumble.hd.hi_amp = effect->u.rumble.weak_magnitude * RUMBLE_MAX >> 16;
> > +		ns2->rumble.hd.lo_amp = effect->u.rumble.strong_magnitude * RUMBLE_MAX >> 16;
> > +	}
> > +
> > +	if (ns2->hdev)
> > +		schedule_delayed_work(&ns2->rumble_work, 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static void switch2_rumble_work(struct work_struct *work)
> > +{
> > +	struct switch2_controller *ns2 = container_of(to_delayed_work(work),
> > +						      struct switch2_controller, rumble_work);
> > +	unsigned long current_ms = jiffies_to_msecs(get_jiffies_64());
> > +	unsigned long flags;
> > +	bool active;
> > +	int ret;
> 
> [ ... ]
> 
> > +	if (active) {
> > +		unsigned long interval = msecs_to_jiffies(4);
> > +
> > +		if (!ns2->last_rumble_work)
> > +			ns2->last_rumble_work = current_ms;
> > +		else
> > +			ns2->last_rumble_work += interval;
> > +		schedule_delayed_work(&ns2->rumble_work,
> > +			ns2->last_rumble_work + interval - current_ms);
> 
> Does this code underflow the scheduled delay?
> 
> The current_ms variable is retrieved in milliseconds using jiffies_to_msecs(),
> but interval is calculated in jiffies using msecs_to_jiffies(). Since
> ns2->last_rumble_work is initialized to milliseconds but incremented by
> jiffies, subtracting current_ms could yield a negative value.
> 
> On systems where HZ is not 1000, could this underflow the delay parameter and
> schedule the next work millions of jiffies in the future?

It's definitely suspicious that we are adding jiffies to milliseconds. We
should probably fix that.

> 
> > +	} else {
> > +		ns2->last_rumble_work = 0;
> > +	}
> > +	spin_unlock_irqrestore(&ns2->rumble_lock, flags);
> > +
> > +	if (!ns2->hdev) {
> > +		cancel_delayed_work(&ns2->rumble_work);
> > +		ret = -ENODEV;
> > +	} else {
> > +		ret = hid_hw_output_report(ns2->hdev, ns2->rumble_buffer, 64);
> > +	}
> > +
> > +	if (ret < 0)
> > +		hid_dbg(ns2->hdev, "Failed to send output report ret=%d\n", ret);
> 
> If ns2->hdev is NULL, we set ret = -ENODEV and then reach this hid_dbg call.
> Could this result in a NULL pointer dereference, as the hid_dbg macro passes
> ns2->hdev to dev_dbg()?

Since we set `ret = -ENODEV` when ns2->hdev is NULL we would indeed end
up calling hid_dbg() with a NULL argument.


> 
> Also, since ns2->hdev is accessed locklessly and without READ_ONCE(), is there
> a time-of-check to time-of-use race where the compiler might reload the pointer
> between the check and hid_hw_output_report()?
> 
> [ ... ]
> 
> > @@ -3881,6 +4048,14 @@ static int switch2_probe(struct hid_device *hdev, const struct hid_device_id *id
> >  
> >  	switch2_leds_create(ns2);
> >  
> > +#if IS_ENABLED(CONFIG_NINTENDO_FF)
> > +	if (ns2->ctlr_type != NS2_CTLR_TYPE_GC) {
> > +		ns2->rumble.hd.hi_freq = RUMBLE_HI_FREQ;
> > +		ns2->rumble.hd.lo_freq = RUMBLE_LO_FREQ;
> > +	}
> 
> Are we checking ns2->ctlr_type before it is dynamically initialized?
> 
> During probe, ns2->ctlr_type appears to be 0 since the struct is freshly
> allocated and the type is discovered later during the init state machine.
> This would cause the high and low frequencies to always be written.

As switch2_init_controller is called from the other driver's probe
function, this might be fine. To avoid writing these values if the
initialisation has not happened yet, we should probably guard against
a 0 value.

Cheers,
Silvan

> 
> Since hd and sd share a union, could this corrupt the sd.error and
> sd.amplitude fields for actual GameCube controllers?
> 
> > +	spin_lock_init(&ns2->rumble_lock);
> > +	INIT_DELAYED_WORK(&ns2->rumble_work, switch2_rumble_work);
> > +#endif
> >  	hid_set_drvdata(hdev, ns2);

^ permalink raw reply

* [PATCH] HID: logitech-hidpp: remove excess kernel-doc member in hidpp_scroll_counter
From: Rosen Penev @ 2026-05-31  0:01 UTC (permalink / raw)
  To: linux-input
  Cc: Filipe Laíns, Bastien Nocera, Jiri Kosina,
	Benjamin Tissoires, Hans de Goede, open list

The @dev member described in the kernel-doc does not exist in the
struct. Remove the stale entry.

Fixes: 0610430e3dea ("HID: logitech-hidpp: add input_device ptr to struct
hidpp_device")
Assisted-by: opencode:big-pickle

Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/hid/hid-logitech-hidpp.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index ccbf28869a96..1990ba5b26ea 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -164,7 +164,6 @@ struct hidpp_battery {
 /**
  * struct hidpp_scroll_counter - Utility class for processing high-resolution
  *                             scroll events.
- * @dev: the input device for which events should be reported.
  * @wheel_multiplier: the scalar multiplier to be applied to each wheel event
  * @remainder: counts the number of high-resolution units moved since the last
  *             low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH] HID: wacom: use GFP_ATOMIC in wacom_wac_queue_flush()
From: Dmitry Torokhov @ 2026-05-31  4:25 UTC (permalink / raw)
  To: Jinmo Yang
  Cc: Ping Cheng, Jason Gerecke, Jiri Kosina, Benjamin Tissoires,
	linux-input, linux-kernel, stable
In-Reply-To: <20260530155930.128183-1-jinmo44.yang@gmail.com>

Hi Jinmo,

On Sun, May 31, 2026 at 12:59:30AM +0900, Jinmo Yang wrote:
> wacom_wac_queue_flush() is called via the .raw_event callback
> (wacom_raw_event → wacom_wac_pen_serial_enforce → wacom_wac_queue_flush).
> For USB HID devices, this callback is invoked from hid_irq_in(), which
> is a URB completion handler running in atomic context. Using GFP_KERNEL
> in this path can sleep, leading to a "scheduling while atomic" bug.
> 
> Use GFP_ATOMIC instead. The existing code already handles allocation
> failure by skipping the fifo entry and continuing.
> 
> Suggested-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

If you want to give credit this should be "Reported-by: Sashiko-bot <...>".

> Fixes: 5e013ad20689 ("HID: wacom: Remove static WACOM_PKGLEN_MAX limit")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
> ---
>  drivers/hid/wacom_sys.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
> index a32320b35..2e237bdd2 100644
> --- a/drivers/hid/wacom_sys.c
> +++ b/drivers/hid/wacom_sys.c
> @@ -74,7 +74,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
>  		unsigned int count;
>  		int err;
>  
> -		buf = kzalloc(size, GFP_KERNEL);
> +		buf = kzalloc(size, GFP_ATOMIC);
>  		if (!buf) {
>  			kfifo_skip(fifo);
>  			continue;

Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

As a followup please consider changing 'buf' management to use cleanup
facilities:

		u8 *buf __free(kfree) = kzalloc(size, GFP_ATOMIC);
		if (!buf) {
			kfifo_skiip(fifo);
			continue;
		}
		...

Thanks.

-- 
Dmitry

^ permalink raw reply

* [git pull] Input updates for v7.1-rc5
From: Dmitry Torokhov @ 2026-05-31  5:09 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, linux-input

Hi Linus,

Please pull from:

	git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git tags/input-for-v7.1-rc5

to receive updates for the input subsystem. You will get:

- updates to Elan I2C touchpad driver to handle a new IC type and to
  validate size of supplied firmware to prevent OOB access

- updates to Xpad controller driver to recognize ASUS ROG RAIKIRI II and
  "Nova 2 Lite" from GameSir controllers as well as a fix to prevent a
  potential OOB access when handling "Share" button

- an update to Synaptics touchpad driver to use RMI mode for touchpad in
  Thinkpad E490

- updates to Atmel MXT driver adding checks to prevent potential OOB
  accesses

- a fix to IMS PCU driver to free correct amount of memory when
  tearing it down

- a fixup to the recent change to Atlas buttons driver

- a small cleanup in fm801-fp for PCI IDs table initialisation.

Changelog:
---------

Dmitriy Zharov (1):
      Input: xpad - add support for ASUS ROG RAIKIRI II

Dmitry Torokhov (4):
      Input: xpad - fix out-of-bounds access for Share button
      Input: elan_i2c - validate firmware size before use
      Input: atmel_mxt_ts - fix boundary check in mxt_prepare_cfg_mem
      Input: atmel_mxt_ts - check mem_size before calculating config memory size

Greg Kroah-Hartman (1):
      Input: usbtouchscreen - clamp NEXIO data_len/x_len to URB buffer size

Jingle Wu 吳金國 (2):
      Input: elan_i2c - add ic type 0x19
      Input: elan_i2c - increase device reset wait timeout after update FW

Nicolás Bazaes (1):
      Input: synaptics - add LEN2058 to SMBus passlist for ThinkPad E490

Qbeliw Tanaka (1):
      Input: xpad - add "Nova 2 Lite" from GameSir

Rafael J. Wysocki (1):
      Input: atlas - check ACPI_COMPANION() against NULL

Thomas Fourier (1):
      Input: ims-pcu - fix usb_free_coherent() size in ims_pcu_buffers_free()

Uwe Kleine-König (The Capable Hub) (1):
      Input: fm801-gp - simplify initialisation of pci_device_id array

Diffstat:
--------

 drivers/input/gameport/fm801-gp.c          |  4 ++--
 drivers/input/joystick/xpad.c              | 14 ++++++++++----
 drivers/input/misc/atlas_btns.c            |  6 +++++-
 drivers/input/misc/ims-pcu.c               |  2 +-
 drivers/input/mouse/elan_i2c_core.c        |  8 ++++++++
 drivers/input/mouse/elan_i2c_i2c.c         |  2 +-
 drivers/input/mouse/synaptics.c            |  1 +
 drivers/input/touchscreen/atmel_mxt_ts.c   | 13 ++++++++++---
 drivers/input/touchscreen/usbtouchscreen.c |  5 +++++
 9 files changed, 43 insertions(+), 12 deletions(-)

Thanks.


-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v1] Input: Use named initializers for arrays of i2c_device_data
From: Dmitry Torokhov @ 2026-05-31  5:13 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Anshul Dalal, Michael Hennerich, Yassine Oudjana, Linus Walleij,
	Nicolas Ferre, Alexandre Belloni, Claudiu Beznea,
	Support Opensource, Nick Dyer, Hans de Goede, Job Noorman,
	Mika Penttilä, Maxime Coquelin, Alexandre Torgue, Kees Cook,
	bui duc phuc, Thorsten Blum, Yauhen Kharuzhy, Sakari Ailus,
	Marco Crivellari, Minseong Kim, Ingo Molnar, Thomas Gleixner,
	Oleh Kuzhylnyi, Marek Vasut, Krzysztof Kozlowski,
	Geert Uytterhoeven, Josua Mayer, Michael Tretter, Jeff LaBundy,
	Javier Carrasco, David Heidelberg, Petr Hodina, Svyatoslav Ryhel,
	Johannes Kirchmair, Andy Shevchenko, Xichao Zhao, linux-input,
	linux-kernel, linux-arm-kernel, platform-driver-x86, linux-stm32
In-Reply-To: <ahrP4STTFdUsBp0O@monoceros>

On Sat, May 30, 2026 at 02:02:20PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> Hello Dmitry,
> 
> On Fri, May 29, 2026 at 10:56:48PM -0700, Dmitry Torokhov wrote:
> > I like the ability to properly set up pointers for driver data, however
> > I do not think we should use named initializers for name field. As long
> > as we are not planning on moving its position I like the brevity of just
> > saying
> > 
> > 	{ "ili210x", .driver_data_ptr = &ili210x_chip },
> > 
> > Can we keep the old style for the name field?
> 
> I have no strong opinion here, my patch introduces the named initializer
> for both members for consistency. Note that my patches for all the other
> subsystems (and also other *_device_id) do the same and you're the first
> maintainer with that expressed preference.
> 
> I even sent a few patches that adapt initializers without .driver_data
> (e.g.
> https://lore.kernel.org/all/177932943265.3832404.360063047381979287.git-patchwork-notify@kernel.org/)
> that got positive feedback so far.
> 
> So if you're ok with having input differ in style from (up to now) all
> other subsystems, I can rework the patch.

OK, I guess I am too late to voice my opinion. I do not want to have
different style, in this particular case at least, so I applied the
patch.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] Input: iqs5xx - Drop unused i2c driver_data
From: Dmitry Torokhov @ 2026-05-31  5:14 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Andrew Morton, Randy Dunlap, Andy Shevchenko, linux-input,
	linux-kernel
In-Reply-To: <20260515165135.498505-2-u.kleine-koenig@baylibre.com>

On Fri, May 15, 2026 at 06:51:34PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> The driver doesn't make use of the value that was explicitly assigned to
> the .driver_data members. Drop the assignment. While touching the array,
> convert it to use named initialization which is easier to understand.
> 
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>

Applied, thank you.

-- 
Dmitry

^ permalink raw reply

* [PATCH v2 2/4] soc: mediatek: pwrap: Add support for MT6735 and MT6328 SoC/PMIC pair
From: Yassine Oudjana via B4 Relay @ 2026-05-31  9:10 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Flora Fu, Alexandre Mergnat,
	Liam Girdwood, Mark Brown, Dmitry Torokhov
  Cc: Yassine Oudjana, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-input
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com>

From: Yassine Oudjana <y.oudjana@protonmail.com>

Add register definitions and configuration for the MT6735 SoC and the
MT6328 PMIC which are commonly paired and communicate through the PMIC
wrapper.

Note that the PMIC wrapper on MT6735M has a slightly different register
map and is therefore NOT compatible with MT6735.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
---
 drivers/soc/mediatek/mtk-pmic-wrap.c | 177 ++++++++++++++++++++++++++++++++++-
 1 file changed, 174 insertions(+), 3 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index 0bcd85826375..0f14dca5609d 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2014 MediaTek Inc.
  * Author: Flora Fu, MediaTek
  */
+
 #include <linux/clk.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -100,7 +101,7 @@ enum dew_regs {
 	PWRAP_DEW_CIPHER_MODE,
 	PWRAP_DEW_CIPHER_SWRST,
 
-	/* MT6323 only regs */
+	/* MT6323 and MT6328 only regs */
 	PWRAP_DEW_CIPHER_EN,
 	PWRAP_DEW_RDDMY_NO,
 
@@ -121,8 +122,10 @@ enum dew_regs {
 	PWRAP_RG_SPI_CON13,
 	PWRAP_SPISLV_KEY,
 
-	/* MT6359 only regs */
+	/* MT6359 and MT6328 only regs */
 	PWRAP_DEW_CRC_SWRST,
+
+	/* MT6359 only regs */
 	PWRAP_DEW_RG_EN_RECORD,
 	PWRAP_DEW_RECORD_CMD0,
 	PWRAP_DEW_RECORD_CMD1,
@@ -171,6 +174,23 @@ static const u32 mt6323_regs[] = {
 	[PWRAP_DEW_RDDMY_NO] =		0x01a4,
 };
 
+static const u32 mt6328_regs[] = {
+	[PWRAP_DEW_DIO_EN] =		0x02d4,
+	[PWRAP_DEW_READ_TEST] =		0x02d6,
+	[PWRAP_DEW_WRITE_TEST] =	0x02d8,
+	[PWRAP_DEW_CRC_SWRST] =		0x02da,
+	[PWRAP_DEW_CRC_EN] =		0x02dc,
+	[PWRAP_DEW_CRC_VAL] =		0x02de,
+	[PWRAP_DEW_MON_GRP_SEL] =	0x02e0,
+	[PWRAP_DEW_CIPHER_KEY_SEL] =	0x02e2,
+	[PWRAP_DEW_CIPHER_IV_SEL] =	0x02e4,
+	[PWRAP_DEW_CIPHER_EN] =		0x02e6,
+	[PWRAP_DEW_CIPHER_RDY] =	0x02e8,
+	[PWRAP_DEW_CIPHER_MODE] =	0x02ea,
+	[PWRAP_DEW_CIPHER_SWRST] =	0x02ec,
+	[PWRAP_DEW_RDDMY_NO] =		0x02ee,
+};
+
 static const u32 mt6331_regs[] = {
 	[PWRAP_DEW_DIO_EN] =		0x018c,
 	[PWRAP_DEW_READ_TEST] =		0x018e,
@@ -394,7 +414,7 @@ enum pwrap_regs {
 	PWRAP_ADC_RDATA_ADDR1,
 	PWRAP_ADC_RDATA_ADDR2,
 
-	/* MT7622 only regs */
+	/* MT7622 and MT6735 only regs */
 	PWRAP_STA,
 	PWRAP_CLR,
 	PWRAP_DVFS_ADR8,
@@ -417,6 +437,8 @@ enum pwrap_regs {
 	PWRAP_ADC_RDATA_ADDR,
 	PWRAP_GPS_STA,
 	PWRAP_SW_RST,
+
+	/* MT7622 only regs */
 	PWRAP_DVFS_STEP_CTRL0,
 	PWRAP_DVFS_STEP_CTRL1,
 	PWRAP_DVFS_STEP_CTRL2,
@@ -481,6 +503,13 @@ enum pwrap_regs {
 	/* MT8516 only regs */
 	PWRAP_OP_TYPE,
 	PWRAP_MSB_FIRST,
+
+	/* MT6735 only regs */
+	PWRAP_WACS3_EN,
+	PWRAP_INIT_DONE3,
+	PWRAP_WACS3_CMD,
+	PWRAP_WACS3_RDATA,
+	PWRAP_WACS3_VLDCLR,
 };
 
 static const int mt2701_regs[] = {
@@ -569,6 +598,119 @@ static const int mt2701_regs[] = {
 	[PWRAP_ADC_RDATA_ADDR2] =	0x154,
 };
 
+static const int mt6735_regs[] = {
+	[PWRAP_MUX_SEL] =			0x0,
+	[PWRAP_WRAP_EN] =			0x4,
+	[PWRAP_DIO_EN] =			0x8,
+	[PWRAP_SIDLY] =				0xc,
+	[PWRAP_RDDMY] =				0x10,
+	[PWRAP_SI_CK_CON] =			0x14,
+	[PWRAP_CSHEXT_WRITE] =			0x18,
+	[PWRAP_CSHEXT_READ] =			0x1c,
+	[PWRAP_CSLEXT_START] =			0x20,
+	[PWRAP_CSLEXT_END] =			0x24,
+	[PWRAP_STAUPD_PRD] =			0x28,
+	[PWRAP_STAUPD_GRPEN] =			0x2c,
+	[PWRAP_EINT_STA0_ADR] =			0x30,
+	[PWRAP_EINT_STA1_ADR] =			0x34,
+	[PWRAP_STA] =				0x38,
+	[PWRAP_CLR] =				0x3c,
+	[PWRAP_STAUPD_MAN_TRIG] =		0x40,
+	[PWRAP_STAUPD_STA] =			0x44,
+	[PWRAP_WRAP_STA] =			0x48,
+	[PWRAP_HARB_INIT] =			0x4c,
+	[PWRAP_HARB_HPRIO] =			0x50,
+	[PWRAP_HIPRIO_ARB_EN] =			0x54,
+	[PWRAP_HARB_STA0] =			0x58,
+	[PWRAP_HARB_STA1] =			0x5c,
+	[PWRAP_MAN_EN] =			0x60,
+	[PWRAP_MAN_CMD] =			0x64,
+	[PWRAP_MAN_RDATA] =			0x68,
+	[PWRAP_MAN_VLDCLR] =			0x6c,
+	[PWRAP_WACS0_EN] =			0x70,
+	[PWRAP_INIT_DONE0] =			0x74,
+	[PWRAP_WACS0_CMD] =			0x78,
+	[PWRAP_WACS0_RDATA] =			0x7c,
+	[PWRAP_WACS0_VLDCLR] =			0x80,
+	[PWRAP_WACS1_EN] =			0x84,
+	[PWRAP_INIT_DONE1] =			0x88,
+	[PWRAP_WACS1_CMD] =			0x8c,
+	[PWRAP_WACS1_RDATA] =			0x90,
+	[PWRAP_WACS1_VLDCLR] =			0x94,
+	[PWRAP_WACS2_EN] =			0x98,
+	[PWRAP_INIT_DONE2] =			0x9c,
+	[PWRAP_WACS2_CMD] =			0xa0,
+	[PWRAP_WACS2_RDATA] =			0xa4,
+	[PWRAP_WACS2_VLDCLR] =			0xa8,
+	[PWRAP_WACS3_EN] =			0xac,
+	[PWRAP_INIT_DONE3] =			0xb0,
+	[PWRAP_WACS3_CMD] =			0xb4,
+	[PWRAP_WACS3_RDATA] =			0xb8,
+	[PWRAP_WACS3_VLDCLR] =			0xbc,
+	[PWRAP_INT_EN] =			0xc0,
+	[PWRAP_INT_FLG_RAW] =			0xc4,
+	[PWRAP_INT_FLG] =			0xc8,
+	[PWRAP_INT_CLR] =			0xcc,
+	[PWRAP_SIG_ADR] =			0xd0,
+	[PWRAP_SIG_MODE] =			0xd4,
+	[PWRAP_SIG_VALUE] =			0xd8,
+	[PWRAP_SIG_ERRVAL] =			0xdc,
+	[PWRAP_CRC_EN] =			0xe0,
+	[PWRAP_TIMER_EN] =			0xe4,
+	[PWRAP_TIMER_STA] =			0xe8,
+	[PWRAP_WDT_UNIT] =			0xec,
+	[PWRAP_WDT_SRC_EN] =			0xf0,
+	[PWRAP_WDT_FLG] =			0xf4,
+	[PWRAP_DEBUG_INT_SEL] =			0xf8,
+	[PWRAP_DVFS_ADR0] =			0xfc,
+	[PWRAP_DVFS_WDATA0] =			0x100,
+	[PWRAP_DVFS_ADR1] =			0x104,
+	[PWRAP_DVFS_WDATA1] =			0x108,
+	[PWRAP_DVFS_ADR2] =			0x10c,
+	[PWRAP_DVFS_WDATA2] =			0x110,
+	[PWRAP_DVFS_ADR3] =			0x114,
+	[PWRAP_DVFS_WDATA3] =			0x118,
+	[PWRAP_DVFS_ADR4] =			0x11c,
+	[PWRAP_DVFS_WDATA4] =			0x120,
+	[PWRAP_DVFS_ADR5] =			0x124,
+	[PWRAP_DVFS_WDATA5] =			0x128,
+	[PWRAP_DVFS_ADR6] =			0x12c,
+	[PWRAP_DVFS_WDATA6] =			0x130,
+	[PWRAP_DVFS_ADR7] =			0x134,
+	[PWRAP_DVFS_WDATA7] =			0x138,
+	[PWRAP_DVFS_ADR8] =			0x13c,
+	[PWRAP_DVFS_WDATA8] =			0x140,
+	[PWRAP_DVFS_ADR9] =			0x144,
+	[PWRAP_DVFS_WDATA9] =			0x148,
+	[PWRAP_DVFS_ADR10] =			0x14c,
+	[PWRAP_DVFS_WDATA10] =			0x150,
+	[PWRAP_DVFS_ADR11] =			0x154,
+	[PWRAP_DVFS_WDATA11] =			0x158,
+	[PWRAP_DVFS_ADR12] =			0x15c,
+	[PWRAP_DVFS_WDATA12] =			0x160,
+	[PWRAP_DVFS_ADR13] =			0x164,
+	[PWRAP_DVFS_WDATA13] =			0x168,
+	[PWRAP_DVFS_ADR14] =			0x16c,
+	[PWRAP_DVFS_WDATA14] =			0x170,
+	[PWRAP_DVFS_ADR15] =			0x174,
+	[PWRAP_DVFS_WDATA15] =			0x178,
+	[PWRAP_SPMINF_STA] =			0x17c,
+	[PWRAP_CIPHER_KEY_SEL] =		0x180,
+	[PWRAP_CIPHER_IV_SEL] =			0x184,
+	[PWRAP_CIPHER_EN] =			0x188,
+	[PWRAP_CIPHER_RDY] =			0x18c,
+	[PWRAP_CIPHER_MODE] =			0x190,
+	[PWRAP_CIPHER_SWRST] =			0x194,
+	[PWRAP_DCM_EN] =			0x198,
+	[PWRAP_DCM_DBC_PRD] =			0x19c,
+	[PWRAP_EXT_CK] =			0x1a0,
+	[PWRAP_ADC_CMD_ADDR] =			0x1a4,
+	[PWRAP_PWRAP_ADC_CMD] =			0x1a8,
+	[PWRAP_ADC_RDATA_ADDR] =		0x1ac,
+	[PWRAP_GPS_STA] =			0x1b0,
+	[PWRAP_SW_RST] =			0x1b4,
+};
+
 static const int mt6765_regs[] = {
 	[PWRAP_MUX_SEL] =		0x0,
 	[PWRAP_WRAP_EN] =		0x4,
@@ -1302,6 +1444,7 @@ static const int mt8186_regs[] = {
 
 enum pmic_type {
 	PMIC_MT6323,
+	PMIC_MT6328,
 	PMIC_MT6331,
 	PMIC_MT6332,
 	PMIC_MT6351,
@@ -1314,6 +1457,7 @@ enum pmic_type {
 
 enum pwrap_type {
 	PWRAP_MT2701,
+	PWRAP_MT6735,
 	PWRAP_MT6765,
 	PWRAP_MT6779,
 	PWRAP_MT6795,
@@ -1733,6 +1877,10 @@ static void pwrap_init_chip_select_ext(struct pmic_wrapper *wrp, u8 hext_write,
 static int pwrap_common_init_reg_clock(struct pmic_wrapper *wrp)
 {
 	switch (wrp->master->type) {
+	case PWRAP_MT6735:
+		pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_RDDMY_NO], 0x8);
+		pwrap_init_chip_select_ext(wrp, 0, 6, 0, 0);
+		break;
 	case PWRAP_MT6795:
 		if (wrp->slave->type == PMIC_MT6331) {
 			const u32 *dew_regs = wrp->slave->dew_regs;
@@ -1839,6 +1987,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
 		pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
 		break;
 	case PWRAP_MT2701:
+	case PWRAP_MT6735:
 	case PWRAP_MT6765:
 	case PWRAP_MT6779:
 	case PWRAP_MT6795:
@@ -2194,6 +2343,14 @@ static const struct pwrap_slv_type pmic_mt6323 = {
 		PWRAP_SLV_CAP_SECURITY,
 };
 
+static const struct pwrap_slv_type pmic_mt6328 = {
+	.dew_regs = mt6328_regs,
+	.type = PMIC_MT6328,
+	.regops = &pwrap_regops16,
+	.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
+		PWRAP_SLV_CAP_SECURITY,
+};
+
 static const struct pwrap_slv_type pmic_mt6331 = {
 	.dew_regs = mt6331_regs,
 	.type = PMIC_MT6331,
@@ -2249,6 +2406,7 @@ static const struct pwrap_slv_type pmic_mt6397 = {
 
 static const struct of_device_id of_slave_match_tbl[] = {
 	{ .compatible = "mediatek,mt6323", .data = &pmic_mt6323 },
+	{ .compatible = "mediatek,mt6328", .data = &pmic_mt6328 },
 	{ .compatible = "mediatek,mt6331", .data = &pmic_mt6331 },
 	{ .compatible = "mediatek,mt6351", .data = &pmic_mt6351 },
 	{ .compatible = "mediatek,mt6357", .data = &pmic_mt6357 },
@@ -2277,6 +2435,18 @@ static const struct pmic_wrapper_type pwrap_mt2701 = {
 	.init_soc_specific = pwrap_mt2701_init_soc_specific,
 };
 
+static const struct pmic_wrapper_type pwrap_mt6735 = {
+	.regs = mt6735_regs,
+	.type = PWRAP_MT6735,
+	.arb_en_all = GENMASK(9, 0),
+	.int_en_all = GENMASK(31, 0),
+	.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+	.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+	.caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+	.init_reg_clock = pwrap_common_init_reg_clock,
+	.init_soc_specific = NULL,
+};
+
 static const struct pmic_wrapper_type pwrap_mt6765 = {
 	.regs = mt6765_regs,
 	.type = PWRAP_MT6765,
@@ -2446,6 +2616,7 @@ static const struct pmic_wrapper_type pwrap_mt8186 = {
 
 static const struct of_device_id of_pwrap_match_tbl[] = {
 	{ .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701 },
+	{ .compatible = "mediatek,mt6735-pwrap", .data = &pwrap_mt6735 },
 	{ .compatible = "mediatek,mt6765-pwrap", .data = &pwrap_mt6765 },
 	{ .compatible = "mediatek,mt6779-pwrap", .data = &pwrap_mt6779 },
 	{ .compatible = "mediatek,mt6795-pwrap", .data = &pwrap_mt6795 },

-- 
2.54.0



^ permalink raw reply related

* [PATCH v2 0/4] MediaTek MT6735+MT6328 SoC/PMIC pair base support
From: Yassine Oudjana via B4 Relay @ 2026-05-31  9:10 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Flora Fu, Alexandre Mergnat,
	Liam Girdwood, Mark Brown, Dmitry Torokhov
  Cc: Yassine Oudjana, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-input

These patches are part of a larger effort to support the MT6735 SoC family in
mainline Linux. More patches (unsent or sent and pending review or revision)
can be found here[1].

This series adds base support for the MediaTek MT6735 SoC and MT6328 PMIC pair.
This includes PMIC wrapper support on the SoC side and regulators and keys on
the PMIC side. The PMIC has other blocks such as an audio codec and battery
charger which can be supported in the future.

Changes since v1:
- Fit regulator definitions in 2 lines and 100 characters whenever possible.
- Remove get_mode and set_mode ops for regulators that don't support them.

[1] https://gitlab.com/mt6735-mainline/linux/-/commits/mt6735-staging

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
---
Yassine Oudjana (4):
      dt-bindings: mediatek: pwrap: Add MT6735 compatible
      soc: mediatek: pwrap: Add support for MT6735 and MT6328 SoC/PMIC pair
      regulator: Add driver for MediaTek MT6328 PMIC regulators
      Input: mtk-pmic-keys - Add support for MT6328

 .../bindings/soc/mediatek/mediatek,pwrap.yaml      |   1 +
 drivers/input/keyboard/mtk-pmic-keys.c             |  15 +
 drivers/regulator/Kconfig                          |   9 +
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/mt6328-regulator.c               | 500 +++++++++++++++++++++
 drivers/soc/mediatek/mtk-pmic-wrap.c               | 177 +++++++-
 include/linux/regulator/mt6328-regulator.h         |  49 ++
 7 files changed, 749 insertions(+), 3 deletions(-)
---
base-commit: 7da7f07112610a520567421dd2ffcb51beaefbcc
change-id: 20260531-mt6735-pwrap-mt6328-pmic-de481d5c5e89

Best regards,
--  
Yassine Oudjana <y.oudjana@protonmail.com>



^ permalink raw reply

* [PATCH v2 1/4] dt-bindings: mediatek: pwrap: Add MT6735 compatible
From: Yassine Oudjana via B4 Relay @ 2026-05-31  9:10 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Flora Fu, Alexandre Mergnat,
	Liam Girdwood, Mark Brown, Dmitry Torokhov
  Cc: Yassine Oudjana, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-input
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com>

From: Yassine Oudjana <y.oudjana@protonmail.com>

Add a compatible string for MT6735 PMIC wrapper.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml
index e7c4a3984c60..3a5fd46ce282 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml
+++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml
@@ -31,6 +31,7 @@ properties:
       - items:
           - enum:
               - mediatek,mt2701-pwrap
+              - mediatek,mt6735-pwrap
               - mediatek,mt6765-pwrap
               - mediatek,mt6779-pwrap
               - mediatek,mt6795-pwrap

-- 
2.54.0



^ permalink raw reply related

* [PATCH v2 3/4] regulator: Add driver for MediaTek MT6328 PMIC regulators
From: Yassine Oudjana via B4 Relay @ 2026-05-31  9:10 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Flora Fu, Alexandre Mergnat,
	Liam Girdwood, Mark Brown, Dmitry Torokhov
  Cc: Yassine Oudjana, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-input
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com>

From: Yassine Oudjana <y.oudjana@protonmail.com>

Add a driver for the regulators on the MT6328 PMIC.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
---
 drivers/regulator/Kconfig                  |   9 +
 drivers/regulator/Makefile                 |   1 +
 drivers/regulator/mt6328-regulator.c       | 500 +++++++++++++++++++++++++++++
 include/linux/regulator/mt6328-regulator.h |  49 +++
 4 files changed, 559 insertions(+)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a54a549196fe..a4f0c21aa6ea 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -919,6 +919,15 @@ config REGULATOR_MT6323
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6328
+	tristate "MediaTek MT6328 PMIC"
+	depends on MFD_MT6397
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6328 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6331
 	tristate "MediaTek MT6331 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 134eee274dbf..4d1e40f0f911 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o
 obj-$(CONFIG_REGULATOR_MT6315)  += mt6316-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323)	+= mt6323-regulator.o
+obj-$(CONFIG_REGULATOR_MT6328)	+= mt6328-regulator.o
 obj-$(CONFIG_REGULATOR_MT6331)	+= mt6331-regulator.o
 obj-$(CONFIG_REGULATOR_MT6332)	+= mt6332-regulator.o
 obj-$(CONFIG_REGULATOR_MT6357)	+= mt6357-regulator.o
diff --git a/drivers/regulator/mt6328-regulator.c b/drivers/regulator/mt6328-regulator.c
new file mode 100644
index 000000000000..a0e4226ffe37
--- /dev/null
+++ b/drivers/regulator/mt6328-regulator.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek MT6328 regulator driver
+ * Based on MT6323 driver.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6328/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6328-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6328_LDO_TABLE_MODE_NORMAL	0
+#define MT6328_LDO_TABLE_MODE_LP	1
+
+/*
+ * MT6328 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6328_regulator_info {
+	struct regulator_desc desc;
+	u32 qi;
+	u32 vselon_reg;
+	u32 vselctrl_reg;
+	u32 vselctrl_mask;
+	u32 modeset_reg;
+	u32 modeset_mask;
+};
+
+#define MT6328_BUCK(match, vreg, min, max, step, volt_ranges, enreg,	\
+		    vosel, vosel_mask, voselon, vosel_ctrl)		\
+[MT6328_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6328_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6328_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min)/step + 1,			\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(0),					\
+	},								\
+	.qi = BIT(13),							\
+	.vselon_reg = voselon,						\
+	.vselctrl_reg = vosel_ctrl,					\
+	.vselctrl_mask = BIT(1),					\
+}
+
+#define MT6328_LDO_RANGE(match, vreg, min, max, step, volt_ranges,	\
+			 enreg, enbit, vosel, vosel_mask, _modeset_reg,	\
+			 _modeset_mask)					\
+[MT6328_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6328_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6328_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = (max - min)/step + 1,			\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6328_LDO_TABLE(match, vreg, ldo_volt_table, enreg, enbit,	\
+			 vosel, vosel_mask, _modeset_reg, _modeset_mask)\
+[MT6328_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6328_volt_table_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6328_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6328_LDO_TABLE_SINGLE_MODE(match, vreg, ldo_volt_table, enreg,\
+				     enbit, vosel, vosel_mask)		\
+[MT6328_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6328_volt_table_single_mode_ops,		\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6328_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = vosel,					\
+		.vsel_mask = vosel_mask,				\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = 0,						\
+	.modeset_mask = 0,						\
+}
+
+#define MT6328_REG_FIXED(match, vreg, enreg, enbit, volt,		\
+		_modeset_reg, _modeset_mask)				\
+[MT6328_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6328_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6328_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+		.min_uV = volt,						\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+#define MT6328_REG_FIXED_SINGLE_MODE(match, vreg, enreg, enbit, volt,	\
+				     _modeset_reg, _modeset_mask)	\
+[MT6328_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.of_match = of_match_ptr(match),			\
+		.ops = &mt6328_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6328_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.enable_reg = enreg,					\
+		.enable_mask = BIT(enbit),				\
+		.min_uV = volt,						\
+	},								\
+	.qi = BIT(15),							\
+	.modeset_reg = _modeset_reg,					\
+	.modeset_mask = _modeset_mask,					\
+}
+
+static const struct linear_range buck_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000)
+};
+
+static const struct linear_range buck_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(600000, 0, 0x7f, 6250)
+};
+
+static const struct linear_range buck_volt_range3[] = {
+	REGULATOR_LINEAR_RANGE(1200000, 0, 0x7f, 6250)
+};
+
+static const unsigned int ldo_volt_table1[] = {
+	1500000, 1800000, 2500000, 2800000
+};
+
+static const unsigned int ldo_volt_table2[] = {
+	3300000, 3400000, 3500000, 3600000
+};
+
+static const unsigned int ldo_volt_table3[] = {
+	0, 0, 0, 1800000, 1900000, 2000000, 2100000, 2200000
+};
+
+static const unsigned int ldo_volt_table4[] = {
+	1700000, 1800000, 1860000, 2760000, 3000000, 3100000
+};
+
+static const unsigned int ldo_volt_table5[] = {
+	1800000, 2900000, 3000000, 3300000
+};
+
+static const unsigned int ldo_volt_table6[] = {
+	2900000, 3000000, 3300000
+};
+
+static const unsigned int ldo_volt_table7[] = {
+	2500000, 2900000, 3000000, 3300000
+};
+
+static const unsigned int ldo_volt_table8[] = {
+	1300000, 1800000, 2900000, 3300000
+};
+
+static const unsigned int ldo_volt_table9[] = {
+	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000
+};
+
+static const unsigned int ldo_volt_table10[] = {
+	1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000
+};
+
+static const unsigned int ldo_volt_table11[] = {
+	900000, 1000000, 1100000, 1200000, 1300000, 1500000
+};
+
+static const unsigned int ldo_volt_table12[] = {
+	1200000, 1300000, 1500000, 1800000, 1825000
+};
+
+static const unsigned int ldo_volt_table13[] = {
+	1200000, 1300000, 1500000, 1800000
+};
+
+static const unsigned int ldo_volt_table14[] = {
+	1240000, 1390000, 1540000
+};
+
+static const struct linear_range ldo_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250)
+};
+
+static int mt6328_get_status(struct regulator_dev *rdev)
+{
+	int ret;
+	u32 regval;
+	struct mt6328_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6328_ldo_table_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6328_regulator_info *info = rdev_get_drvdata(rdev);
+
+	switch (mode) {
+	case REGULATOR_MODE_STANDBY:
+		val = MT6328_LDO_TABLE_MODE_LP;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = MT6328_LDO_TABLE_MODE_NORMAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+				  info->modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6328_ldo_table_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6328_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->modeset_mask;
+	val >>= ffs(info->modeset_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_STANDBY;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static const struct regulator_ops mt6328_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6328_get_status,
+};
+
+static const struct regulator_ops mt6328_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6328_get_status,
+	.set_mode = mt6328_ldo_table_set_mode,
+	.get_mode = mt6328_ldo_table_get_mode,
+};
+
+static const struct regulator_ops mt6328_volt_table_single_mode_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6328_get_status,
+};
+
+static const struct regulator_ops mt6328_volt_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6328_get_status,
+	.set_mode = mt6328_ldo_table_set_mode,
+	.get_mode = mt6328_ldo_table_get_mode,
+};
+
+/* The array is indexed by id(MT6328_ID_XXX) */
+static struct mt6328_regulator_info mt6328_regulators[] = {
+	MT6328_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, buck_volt_range1, MT6328_VPA_CON9,
+		    MT6328_VPA_CON11, 0x3f, MT6328_VPA_CON12, MT6328_VPA_CON7),
+	MT6328_BUCK("buck_vproc", VPROC, 600000, 1393750, 6250, buck_volt_range2, MT6328_VPROC_CON9,
+		    MT6328_VPA_CON11, 0x7f, MT6328_VPROC_CON12, MT6328_VPROC_CON7),
+	MT6328_BUCK("buck_vcore1", VCORE1, 600000, 1393750, 6250, buck_volt_range2,
+		    MT6328_VCORE1_CON9, MT6328_VCORE1_CON11, 0x7f, MT6328_VCORE1_CON12,
+		    MT6328_VCORE1_CON7),
+	MT6328_BUCK("buck_vsys22", VSYS22, 1200000, 1993750, 6250, buck_volt_range3,
+		    MT6328_VSYS22_CON9, MT6328_VSYS22_CON11, 0x7f, MT6328_VSYS22_CON12,
+		    MT6328_VSYS22_CON7),
+	MT6328_BUCK("buck_vlte", VLTE, 600000, 1393750, 6250, buck_volt_range2, MT6328_VLTE_CON9,
+		    MT6328_VLTE_CON11, 0x7f, MT6328_VLTE_CON12, MT6328_VLTE_CON7),
+	MT6328_REG_FIXED("ldo_vaux18", VAUX18, MT6328_VAUX18_CON0, 1, 1800000, MT6328_VAUX18_CON0,
+			 BIT(0)),
+	MT6328_REG_FIXED("ldo_vtcxo_0", VTCXO_0, MT6328_VTCXO_0_CON0, 1, 2800000,
+			 MT6328_VTCXO_0_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vtcxo_1", VTCXO_1, MT6328_VTCXO_1_CON0, 1, 2800000,
+			 MT6328_VTCXO_1_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vaud28", VAUD28, MT6328_VAUD28_CON0, 1, 2800000, MT6328_VAUD28_CON0,
+			 BIT(0)),
+	MT6328_REG_FIXED("ldo_vcn28", VCN28, MT6328_VCN28_CON0, 1, 2800000, MT6328_VCN28_CON0,
+			 BIT(0)),
+	MT6328_LDO_TABLE_SINGLE_MODE("ldo_vcama", VCAMA, ldo_volt_table1, MT6328_VCAMA_CON0, 1,
+				     MT6328_ADLDO_ANA_CON5, 0x30),
+	MT6328_LDO_TABLE("ldo_vcn33_bt", VCN33_BT, ldo_volt_table2, MT6328_VCN33_CON2, 1,
+			 MT6328_ADLDO_ANA_CON6, 0x70, MT6328_VCN33_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table2, MT6328_VCN33_CON1, 1,
+			 MT6328_ADLDO_ANA_CON6, 0x70, MT6328_VCN33_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vusb33", VUSB33, MT6328_VUSB33_CON0, 1, 3300000, MT6328_VUSB33_CON0,
+			 BIT(0)),
+	MT6328_LDO_TABLE("ldo_vefuse", VEFUSE, ldo_volt_table3, MT6328_VEFUSE_CON0, 1,
+			 MT6328_ADLDO_ANA_CON8, 0x70, MT6328_VEFUSE_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vsim1", VSIM1, ldo_volt_table4, MT6328_VSIM1_CON0, 1,
+			 MT6328_ADLDO_ANA_CON9, 0x70, MT6328_VSIM1_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vsim2", VSIM2, ldo_volt_table4, MT6328_VSIM2_CON0, 1,
+			 MT6328_ADLDO_ANA_CON10, 0x70, MT6328_VSIM2_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vemc_3v3", VEMC_3V3, ldo_volt_table5, MT6328_VEMC_3V3_CON0, 1,
+			 MT6328_ADLDO_ANA_CON11, 0x30, MT6328_VEMC_3V3_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vmch", VMCH, ldo_volt_table6, MT6328_VMCH_CON0, 1,
+			 MT6328_ADLDO_ANA_CON12, 0x30, MT6328_VMCH_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vtref", VTREF, MT6328_VTREF_CON0, 1, 1800000, 0, 0),
+	MT6328_LDO_TABLE("ldo_vmc", VMC, ldo_volt_table5, MT6328_VMC_CON0, 1, MT6328_DLDO_ANA_CON0,
+			 0x30, MT6328_VMC_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vcamaf", VCAMAF, ldo_volt_table9, MT6328_VCAMAF_CON0, 1,
+			 MT6328_DLDO_ANA_CON1, 0x70, MT6328_VCAMAF_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vibr", VIBR, ldo_volt_table9, MT6328_VIBR_CON0, 1,
+			 MT6328_DLDO_ANA_CON2, 0x70, MT6328_VIBR_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vio28", VIO28, MT6328_VIO28_CON0, 1, 2800000, MT6328_VIO28_CON0,
+			 BIT(0)),
+	MT6328_LDO_TABLE("ldo_vgp1", VGP1, ldo_volt_table10, MT6328_VGP1_CON0, 1,
+			 MT6328_DLDO_ANA_CON4, 0x70, MT6328_VGP1_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vcamd", VCAMD, ldo_volt_table11, MT6328_VCAM_CON0, 1,
+			 MT6328_SLDO_ANA_CON2, 0x70, MT6328_VCAM_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vrf18_0", VRF18_0, MT6328_VRF18_0_CON0, 1, 1825000,
+			 MT6328_VRF18_0_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vrf18_1", VRF18_1, ldo_volt_table12, MT6328_VRF18_1_CON0, 1,
+			 MT6328_SLDO_ANA_CON4, 0x30, MT6328_VRF18_1_CON0, BIT(0)),
+	MT6328_REG_FIXED("ldo_vio18", VIO18, MT6328_VIO18_CON0, 1, 1800000, MT6328_VIO18_CON0,
+			 BIT(0)),
+	MT6328_REG_FIXED("ldo_vcn18", VCN18, MT6328_VCN18_CON0, 1, 1800000, MT6328_VCN18_CON0,
+			 BIT(0)),
+	MT6328_LDO_TABLE("ldo_vcamio", VCAMIO, ldo_volt_table13, MT6328_VCAMIO_CON0, 1,
+			 MT6328_SLDO_ANA_CON7, 0x30, MT6328_VCAMIO_CON0, BIT(0)),
+	MT6328_LDO_TABLE("ldo_vcamio", VCAMIO, ldo_volt_table13, MT6328_VCAMIO_CON0, 1,
+			 MT6328_SLDO_ANA_CON7, 0x30, MT6328_VCAMIO_CON0, BIT(0)),
+	MT6328_LDO_RANGE("ldo_vsram", VSRAM, 700000, 1493750, 6250, ldo_volt_range1,
+			 MT6328_VSRAM_CON9, 1, MT6328_SLDO_ANA_CON9, 0x7f, MT6328_LDO_VSRAM_CON0,
+			 BIT(0)),
+	MT6328_LDO_TABLE("ldo_vm", VM, ldo_volt_table14, MT6328_VM_CON0, 1, MT6328_SLDO_ANA_CON0,
+			 0x3, MT6328_VM_CON0, BIT(0)),
+};
+
+static int mt6328_set_buck_vosel_reg(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6328 = dev_get_drvdata(pdev->dev.parent);
+	int i;
+	u32 regval;
+
+	for (i = 0; i < MT6328_MAX_REGULATOR; i++) {
+		if (mt6328_regulators[i].vselctrl_reg) {
+			if (regmap_read(mt6328->regmap,
+				mt6328_regulators[i].vselctrl_reg,
+				&regval) < 0) {
+				dev_err(&pdev->dev,
+					"Failed to read buck ctrl\n");
+				return -EIO;
+			}
+
+			if (regval & mt6328_regulators[i].vselctrl_mask) {
+				mt6328_regulators[i].desc.vsel_reg =
+				mt6328_regulators[i].vselon_reg;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mt6328_regulator_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6328 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	int i;
+
+	/* Query buck controller to select activated voltage register part */
+	if (mt6328_set_buck_vosel_reg(pdev))
+		return -EIO;
+
+	for (i = 0; i < MT6328_MAX_REGULATOR; i++) {
+		config.dev = &pdev->dev;
+		config.driver_data = &mt6328_regulators[i];
+		config.regmap = mt6328->regmap;
+		rdev = devm_regulator_register(&pdev->dev,
+				&mt6328_regulators[i].desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev, "failed to register %s\n",
+				mt6328_regulators[i].desc.name);
+			return PTR_ERR(rdev);
+		}
+	}
+	return 0;
+}
+
+static const struct platform_device_id mt6328_platform_ids[] = {
+	{ "mt6328-regulator" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6328_platform_ids);
+
+static struct platform_driver mt6328_regulator_driver = {
+	.driver = {
+		.name = "mt6328-regulator",
+	},
+	.probe = mt6328_regulator_probe,
+	.id_table = mt6328_platform_ids,
+};
+
+module_platform_driver(mt6328_regulator_driver);
+
+MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6328 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6328-regulator.h b/include/linux/regulator/mt6328-regulator.h
new file mode 100644
index 000000000000..0f82aa88493b
--- /dev/null
+++ b/include/linux/regulator/mt6328-regulator.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
+ */
+
+#ifndef __LINUX_REGULATOR_MT6328_H
+#define __LINUX_REGULATOR_MT6328_H
+
+enum {
+	MT6328_ID_VPA = 0,
+	MT6328_ID_VPROC,
+	MT6328_ID_VCORE1,
+	MT6328_ID_VSYS22,
+	MT6328_ID_VLTE,
+	MT6328_ID_VAUX18,
+	MT6328_ID_VTCXO_0,
+	MT6328_ID_VTCXO_1,
+	MT6328_ID_VAUD28,
+	MT6328_ID_VCN28,
+	MT6328_ID_VCAMA,
+	MT6328_ID_VCN33_BT,
+	MT6328_ID_VCN33_WIFI,
+	MT6328_ID_VUSB33,
+	MT6328_ID_VEFUSE,
+	MT6328_ID_VSIM1,
+	MT6328_ID_VSIM2,
+	MT6328_ID_VEMC_3V3,
+	MT6328_ID_VMCH,
+	MT6328_ID_VTREF,
+	MT6328_ID_VMC,
+	MT6328_ID_VCAMAF,
+	MT6328_ID_VIBR,
+	MT6328_ID_VIO28,
+	MT6328_ID_VGP1,
+	MT6328_ID_VCAMD,
+	MT6328_ID_VRF18_0,
+	MT6328_ID_VRF18_1,
+	MT6328_ID_VIO18,
+	MT6328_ID_VCN18,
+	MT6328_ID_VCAMIO,
+	MT6328_ID_VSRAM,
+	MT6328_ID_VM,
+	MT6328_ID_RG_MAX,
+};
+
+#define MT6328_MAX_REGULATOR	MT6328_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6328_H */

-- 
2.54.0



^ permalink raw reply related

* [PATCH v2 4/4] Input: mtk-pmic-keys - Add support for MT6328
From: Yassine Oudjana via B4 Relay @ 2026-05-31  9:10 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Flora Fu, Alexandre Mergnat,
	Liam Girdwood, Mark Brown, Dmitry Torokhov
  Cc: Yassine Oudjana, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-input
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com>

From: Yassine Oudjana <y.oudjana@protonmail.com>

Add a compatible string and related data for the PMIC keys on the
MT6328 PMIC.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/input/keyboard/mtk-pmic-keys.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index c78d9f6d97c4..6aaca67e7703 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -9,6 +9,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mfd/mt6323/registers.h>
+#include <linux/mfd/mt6328/registers.h>
 #include <linux/mfd/mt6331/registers.h>
 #include <linux/mfd/mt6357/registers.h>
 #include <linux/mfd/mt6358/registers.h>
@@ -80,6 +81,17 @@ static const struct mtk_pmic_regs mt6323_regs = {
 	.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
 };
 
+static const struct mtk_pmic_regs mt6328_regs = {
+	.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+		MTK_PMIC_KEYS_REGS(MT6328_TOPSTATUS,
+		0x2, MT6328_INT_MISC_CON, 0x4, MTK_PMIC_PWRKEY_RST),
+	.keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+		MTK_PMIC_KEYS_REGS(MT6328_TOPSTATUS,
+		0x4, MT6328_INT_MISC_CON, 0x2, MTK_PMIC_HOMEKEY_RST),
+	.pmic_rst_reg = MT6328_TOP_RST_MISC,
+	.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+};
+
 static const struct mtk_pmic_regs mt6331_regs = {
 	.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
 		MTK_PMIC_KEYS_REGS(MT6331_TOPSTATUS, 0x2,
@@ -304,6 +316,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
 	}, {
 		.compatible = "mediatek,mt6323-keys",
 		.data = &mt6323_regs,
+	}, {
+		.compatible = "mediatek,mt6328-keys",
+		.data = &mt6328_regs,
 	}, {
 		.compatible = "mediatek,mt6331-keys",
 		.data = &mt6331_regs,

-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v2 0/4] MediaTek MT6735+MT6328 SoC/PMIC pair base support
From: Yassine Oudjana @ 2026-05-31  9:16 UTC (permalink / raw)
  To: y.oudjana
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Flora Fu, Alexandre Mergnat,
	Liam Girdwood, Mark Brown, Dmitry Torokhov, devicetree,
	linux-kernel, linux-arm-kernel, linux-mediatek, linux-input
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com>

On Sunday, May 31st, 2026 at 11:10 AM, Yassine Oudjana via B4 Relay <devnull+y.oudjana.protonmail.com@kernel.org> wrote:

> These patches are part of a larger effort to support the MT6735 SoC family in
> mainline Linux. More patches (unsent or sent and pending review or revision)
> can be found here[1].
> 
> This series adds base support for the MediaTek MT6735 SoC and MT6328 PMIC pair.
> This includes PMIC wrapper support on the SoC side and regulators and keys on
> the PMIC side. The PMIC has other blocks such as an audio codec and battery
> charger which can be supported in the future.
> 
> Changes since v1:
> - Fit regulator definitions in 2 lines and 100 characters whenever possible.
> - Remove get_mode and set_mode ops for regulators that don't support them.

Forgot to mention:
- Remove MD register definitions.

> 
> [1] https://gitlab.com/mt6735-mainline/linux/-/commits/mt6735-staging
> 
> Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
> ---
> Yassine Oudjana (4):
>       dt-bindings: mediatek: pwrap: Add MT6735 compatible
>       soc: mediatek: pwrap: Add support for MT6735 and MT6328 SoC/PMIC pair
>       regulator: Add driver for MediaTek MT6328 PMIC regulators
>       Input: mtk-pmic-keys - Add support for MT6328
> 
>  .../bindings/soc/mediatek/mediatek,pwrap.yaml      |   1 +
>  drivers/input/keyboard/mtk-pmic-keys.c             |  15 +
>  drivers/regulator/Kconfig                          |   9 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/mt6328-regulator.c               | 500 +++++++++++++++++++++
>  drivers/soc/mediatek/mtk-pmic-wrap.c               | 177 +++++++-
>  include/linux/regulator/mt6328-regulator.h         |  49 ++
>  7 files changed, 749 insertions(+), 3 deletions(-)
> ---
> base-commit: 7da7f07112610a520567421dd2ffcb51beaefbcc
> change-id: 20260531-mt6735-pwrap-mt6328-pmic-de481d5c5e89
> 
> Best regards,
> --
> Yassine Oudjana <y.oudjana@protonmail.com>
> 
> 
>

^ permalink raw reply

* Re: [PATCH v2 2/4] soc: mediatek: pwrap: Add support for MT6735 and MT6328 SoC/PMIC pair
From: sashiko-bot @ 2026-05-31 11:26 UTC (permalink / raw)
  To: Yassine Oudjana via B4 Relay
  Cc: conor+dt, devicetree, robh, dmitry.torokhov, linux-input
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-2-dac37bf92894@protonmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] PMIC_MT6328 is missing from the slave cipher initialization switch statement, which will cause the driver probe to time out and fail.
- [Medium] Unsafe write to PMIC register 0x0 if MT6735 is paired with a PMIC lacking `PWRAP_DEW_RDDMY_NO`.
--

commit 21ea916ac0163eee8daf299b310759cc6d675f2a
Author: Yassine Oudjana <y.oudjana@protonmail.com>

soc: mediatek: pwrap: Add support for MT6735 and MT6328 SoC/PMIC pair

This commit adds register definitions and configuration for the MT6735 SoC
and the MT6328 PMIC to the MediaTek PMIC wrapper driver. It defines their
specific register layouts and capabilities to enable communication between
the two chips.

> diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
> index 0bcd858263755..0f14dca5609d1 100644
> --- a/drivers/soc/mediatek/mtk-pmic-wrap.c
> +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
[ ... ]
> @@ -1733,6 +1877,10 @@ static void pwrap_init_chip_select_ext(struct pmic_wrapper *wrp, u8 hext_write,
>  static int pwrap_common_init_reg_clock(struct pmic_wrapper *wrp)
>  {
>  	switch (wrp->master->type) {
> +	case PWRAP_MT6735:
> +		pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_RDDMY_NO], 0x8);

[Severity: Medium]
Will this write to register 0x0 if MT6735 is paired with a PMIC that lacks
PWRAP_DEW_RDDMY_NO?

If MT6735 is paired with a PMIC like MT6397 that doesn't define this register
in its array, the read will return 0 and the driver will write 0x8 to PMIC
register 0x0. Should this verify the PMIC type first, similar to how it is
handled for MT6795 below?

> +		pwrap_init_chip_select_ext(wrp, 0, 6, 0, 0);
> +		break;
>  	case PWRAP_MT6795:
>  		if (wrp->slave->type == PMIC_MT6331) {
[ ... ]
> @@ -2194,6 +2343,14 @@ static const struct pwrap_slv_type pmic_mt6323 = {
>  		PWRAP_SLV_CAP_SECURITY,
>  };
>  
> +static const struct pwrap_slv_type pmic_mt6328 = {
> +	.dew_regs = mt6328_regs,
> +	.type = PMIC_MT6328,
> +	.regops = &pwrap_regops16,
> +	.caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
> +		PWRAP_SLV_CAP_SECURITY,

[Severity: High]
Does pwrap_init_cipher() need to be updated to handle PMIC_MT6328?

Since PMIC_MT6328 has PWRAP_SLV_CAP_SECURITY, pwrap_init_cipher() will run.
However, PMIC_MT6328 is missing from the switch (wrp->slave->type) block in
pwrap_init_cipher().

Without writing 1 to PWRAP_DEW_CIPHER_EN for this PMIC, the cipher engine
remains disabled, which will cause the subsequent readx_poll_timeout() for
pwrap_is_pmic_cipher_ready to time out and fail the driver probe.

> +};
> +
>  static const struct pwrap_slv_type pmic_mt6331 = {

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com?part=2

^ permalink raw reply

* Re: [PATCH v2 3/4] regulator: Add driver for MediaTek MT6328 PMIC regulators
From: sashiko-bot @ 2026-05-31 11:35 UTC (permalink / raw)
  To: Yassine Oudjana via B4 Relay
  Cc: devicetree, dmitry.torokhov, linux-input, robh, conor+dt
In-Reply-To: <20260531-mt6735-pwrap-mt6328-pmic-v2-3-dac37bf92894@protonmail.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Undefined behavior (negative bitwise shift) in LDO mode accessors for fixed regulators.
- [High] Hardware logic error: `buck_vproc` is incorrectly assigned the voltage selection register for `VPA`.
- [High] Mismatch between voltage table size and hardware mask for `ldo_vrf18_1` leads to silent undervolting.
- [Medium] The driver destructively mutates the global static `mt6328_regulators` array during device probe.
- [Low] The `MT6328_LDO_RANGE` macro assigns mode registers but uses an ops struct lacking mode accessors.
- [Low] Duplicate definition of `ldo_vcamio` regulator in initialization array.
- [Low] Unused static voltage tables `ldo_volt_table7` and `ldo_volt_table8`.
--

commit 1a95db9b71950cc46e1f082052c7c441b06a008e
Author: Yassine Oudjana <y.oudjana@protonmail.com>

regulator: Add driver for MediaTek MT6328 PMIC regulators

This commit adds a new driver for the regulators found on the MT6328 PMIC.
It supports various bucks and LDOs using the regulator framework.

> diff --git a/drivers/regulator/mt6328-regulator.c b/drivers/regulator/mt6328-regulator.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/regulator/mt6328-regulator.c

[ ... ]

> +static const unsigned int ldo_volt_table6[] = {
> +	2900000, 3000000, 3300000
> +};
> +
> +static const unsigned int ldo_volt_table7[] = {
> +	2500000, 2900000, 3000000, 3300000
> +};
> +
> +static const unsigned int ldo_volt_table8[] = {
> +	1300000, 1800000, 2900000, 3300000
> +};

[Severity: Low]
Are these static voltage tables used anywhere in the driver? It looks like
ldo_volt_table7 and ldo_volt_table8 are defined here but are never
referenced in the mt6328_regulators array.

[ ... ]

> +static int mt6328_ldo_table_set_mode(struct regulator_dev *rdev, unsigned int mode)
> +{
> +	int ret, val = 0;
> +	struct mt6328_regulator_info *info = rdev_get_drvdata(rdev);
> +
> +	switch (mode) {
> +	case REGULATOR_MODE_STANDBY:
> +		val = MT6328_LDO_TABLE_MODE_LP;
> +		break;
> +	case REGULATOR_MODE_NORMAL:
> +		val = MT6328_LDO_TABLE_MODE_NORMAL;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	val <<= ffs(info->modeset_mask) - 1;
> +
> +	ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
> +				  info->modeset_mask, val);

[Severity: High]
Could this bitwise shift result in undefined behavior? If modeset_mask is 0,
ffs(0) evaluates to 0, resulting in a shift by -1.

I noticed ldo_vtref is initialized with a modeset_mask of 0 down in the
mt6328_regulators array, but it uses mt6328_volt_fixed_ops which exposes
both the set_mode and get_mode callbacks.

[ ... ]

> +static const struct regulator_ops mt6328_volt_range_ops = {
> +	.list_voltage = regulator_list_voltage_linear_range,
> +	.map_voltage = regulator_map_voltage_linear_range,
> +	.set_voltage_sel = regulator_set_voltage_sel_regmap,
> +	.get_voltage_sel = regulator_get_voltage_sel_regmap,
> +	.set_voltage_time_sel = regulator_set_voltage_time_sel,
> +	.enable = regulator_enable_regmap,
> +	.disable = regulator_disable_regmap,
> +	.is_enabled = regulator_is_enabled_regmap,
> +	.get_status = mt6328_get_status,
> +};

[Severity: Low]
Should this operations structure include the .set_mode and .get_mode callbacks?

Down below, ldo_vsram is initialized using the MT6328_LDO_RANGE macro which
sets up modeset_reg and modeset_mask, but since it is mapped to
mt6328_volt_range_ops, the mode data will be silently ignored by the
regulator core.

[ ... ]

> +/* The array is indexed by id(MT6328_ID_XXX) */
> +static struct mt6328_regulator_info mt6328_regulators[] = {
> +	MT6328_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, buck_volt_range1, MT6328_VPA_CON9,
> +		    MT6328_VPA_CON11, 0x3f, MT6328_VPA_CON12, MT6328_VPA_CON7),
> +	MT6328_BUCK("buck_vproc", VPROC, 600000, 1393750, 6250, buck_volt_range2, MT6328_VPROC_CON9,
> +		    MT6328_VPA_CON11, 0x7f, MT6328_VPROC_CON12, MT6328_VPROC_CON7),

[Severity: High]
Does buck_vproc use the wrong voltage selection register here?

It looks like MT6328_VPA_CON11 was accidentally copied from buck_vpa. This
would cause voltage scaling for the processor to write to the VPA's voltage
selection register instead, breaking voltage scaling for both regulators.

[ ... ]

> +	MT6328_REG_FIXED("ldo_vrf18_0", VRF18_0, MT6328_VRF18_0_CON0, 1, 1825000,
> +			 MT6328_VRF18_0_CON0, BIT(0)),
> +	MT6328_LDO_TABLE("ldo_vrf18_1", VRF18_1, ldo_volt_table12, MT6328_VRF18_1_CON0, 1,
> +			 MT6328_SLDO_ANA_CON4, 0x30, MT6328_VRF18_1_CON0, BIT(0)),

[Severity: High]
Does this 2-bit mask (0x30) conflict with the size of ldo_volt_table12?

That voltage table contains 5 entries, which requires at least a 3-bit mask.
If the core requests the highest voltage (1.825V, index 4), it will be masked
to 0 when updated, which could silently undervolt the regulator to 1.2V instead.

[ ... ]

> +	MT6328_REG_FIXED("ldo_vcn18", VCN18, MT6328_VCN18_CON0, 1, 1800000, MT6328_VCN18_CON0,
> +			 BIT(0)),
> +	MT6328_LDO_TABLE("ldo_vcamio", VCAMIO, ldo_volt_table13, MT6328_VCAMIO_CON0, 1,
> +			 MT6328_SLDO_ANA_CON7, 0x30, MT6328_VCAMIO_CON0, BIT(0)),
> +	MT6328_LDO_TABLE("ldo_vcamio", VCAMIO, ldo_volt_table13, MT6328_VCAMIO_CON0, 1,
> +			 MT6328_SLDO_ANA_CON7, 0x30, MT6328_VCAMIO_CON0, BIT(0)),

[Severity: Low]
Is this duplicate definition of ldo_vcamio intentional? It appears this
entry was accidentally listed twice.

[ ... ]

> +static int mt6328_set_buck_vosel_reg(struct platform_device *pdev)
> +{
> +	struct mt6397_chip *mt6328 = dev_get_drvdata(pdev->dev.parent);
> +	int i;
> +	u32 regval;
> +
> +	for (i = 0; i < MT6328_MAX_REGULATOR; i++) {
> +		if (mt6328_regulators[i].vselctrl_reg) {
> +			if (regmap_read(mt6328->regmap,
> +				mt6328_regulators[i].vselctrl_reg,
> +				&regval) < 0) {
> +				dev_err(&pdev->dev,
> +					"Failed to read buck ctrl\n");
> +				return -EIO;
> +			}
> +
> +			if (regval & mt6328_regulators[i].vselctrl_mask) {
> +				mt6328_regulators[i].desc.vsel_reg =
> +				mt6328_regulators[i].vselon_reg;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}

[Severity: Medium]
Does modifying mt6328_regulators[i].desc.vsel_reg permanently alter the
global static array?

If the driver is unbound and rebound later, and the hardware condition is no
longer met, the driver will incorrectly retain the mutated vsel_reg value
since there is no restore path for the original value.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260531-mt6735-pwrap-mt6328-pmic-v2-0-dac37bf92894@protonmail.com?part=3

^ permalink raw reply

* Re: [PATCH v5 3/3] HID: nintendo: Add unified report format support
From: Silvan Jegen @ 2026-05-31 17:57 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Vicki Pfau, linux-input, dmitry.torokhov
In-Reply-To: <20260514010628.28F7CC19425@smtp.kernel.org>

sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Insufficient bounds checking for NS2_REPORT_UNIFIED payload leads to out-of-bounds reads.
> - [High] Divide-by-zero kernel panic in switch2_report_trigger() caused by attacker-controlled calibration data.
> --
> 
> commit 6e45b564fde8014fc6ade8452a1b793097b3bee4
> Author: Vicki Pfau <vi@endrift.com>
> Subject: HID: nintendo: Add unified report format support
> 
> This commit adds support for the "unified" report format to the nintendo hid
> driver. It introduces new mappings for overlapping button and axis fields
> across different controller types.
> 
> > diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
> > index 9801799a90758..9e7eda7b70bfb 100644
> > --- a/drivers/hid/hid-nintendo.c
> > +++ b/drivers/hid/hid-nintendo.c
> [ ... ]
> > @@ -3690,11 +3791,48 @@ static int switch2_event(struct hid_device *hdev, struct hid_report *report, uin
> >  
> >  	switch (report->id) {
> >  	case NS2_REPORT_UNIFIED:
> > -		/*
> > -		 * TODO
> > -		 * This won't be sent unless the report type gets changed via command
> > -		 * 03-0A, but we should support it at some point regardless.
> > -		 */
> > +		switch (ns2->ctlr_type) {
> > +		case NS2_CTLR_TYPE_JCL:
> > +			switch2_report_stick(input, &ns2->stick_calib[0],
> > +				ABS_X, false, ABS_Y, true, &raw_data[11]);
> > +			switch2_report_buttons(input, &raw_data[5],
> > +				ns2_left_joycon_button_unified_mappings);
> > +			break;
> > +		case NS2_CTLR_TYPE_JCR:
> > +			switch2_report_stick(input, &ns2->stick_calib[0],
> > +				ABS_X, false, ABS_Y, true, &raw_data[14]);
> 
> Is this safe if the report size is exactly 15 bytes?
> 
> Earlier in switch2_event(), there is a global size check:
> 
>     if (size < 15)
>         return -EINVAL;
> 
> However, switch2_report_stick() reads up to 3 bytes from the provided data
> pointer (indices 0, 1, and 2). Passing &raw_data[14] means it will read
> raw_data[14], raw_data[15], and raw_data[16].
> 
> Could this cause an out-of-bounds read if an undersized report is sent?

Yes, I assume we would have to check for a bigger size here.

> 
> > +			switch2_report_buttons(input, &raw_data[5],
> > +				ns2_right_joycon_button_unified_mappings);
> > +			break;
> > +		case NS2_CTLR_TYPE_GC:
> > +			input_report_abs(input, ABS_HAT0X,
> > +				!!(raw_data[7] & NS2_BTN_U3_RIGHT) -
> > +				!!(raw_data[7] & NS2_BTN_U3_LEFT));
> > +			input_report_abs(input, ABS_HAT0Y,
> > +				!!(raw_data[7] & NS2_BTN_U3_DOWN) -
> > +				!!(raw_data[7] & NS2_BTN_U3_UP));
> > +			switch2_report_buttons(input, &raw_data[5], ns2_gccon_unified_mappings);
> > +			switch2_report_stick(input, &ns2->stick_calib[0],
> > +				ABS_X, false, ABS_Y, true, &raw_data[11]);
> > +			switch2_report_stick(input, &ns2->stick_calib[1],
> > +				ABS_RX, false, ABS_RY, true, &raw_data[14]);
> > +			switch2_report_trigger(input, ns2->lt_zero, ABS_Z, raw_data[0x3d]);
> > +			switch2_report_trigger(input, ns2->rt_zero, ABS_RZ, raw_data[0x3e]);
> 
> Similarly, does this code read past the end of the buffer?
> 
> Accessing raw_data[0x3d] (index 61) and raw_data[0x3e] (index 62) requires
> the report size to be at least 63 bytes, but the global check only guarantees
> 15 bytes.

Same here.


>
> Additionally, could this new path trigger a divide-by-zero panic?
> 
> While this issue pre-dates this commit, switch2_report_trigger() contains the
> following calculation:
> 
>     int value = (NS2_TRIGGER_RANGE + 1) * (data - zero) / (232 - zero);
> 
> The zero parameter here comes from the device's factory calibration data
> (ns2->lt_zero and ns2->rt_zero). If a device advertises 232 as its zero
> calibration point, this division evaluates to 0.
> 
> Since this patch exposes a new way to call switch2_report_trigger(), might it
> be worth adding validation to prevent a zero divisor?

This one has been reported already in one of the earlier emails.

Cheers,
Silvan

> 
> > +			break;
> > +		case NS2_CTLR_TYPE_PRO:
> [ ... ]



^ permalink raw reply

* [dtor-input:next] BUILD SUCCESS 332fbc03e1a8cb4c0ce6891cae2c286ddf031aca
From: kernel test robot @ 2026-05-31 18:42 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: 332fbc03e1a8cb4c0ce6891cae2c286ddf031aca  Input: iqs5xx - drop unused i2c driver_data

elapsed time: 800m

configs tested: 252
configs skipped: 43

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

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

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

^ permalink raw reply

* Re: [git pull] Input updates for v7.1-rc5
From: pr-tracker-bot @ 2026-05-31 21:13 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Linus Torvalds, linux-kernel, linux-input
In-Reply-To: <ahvBdJ_vd3xuf-Rd@google.com>

The pull request you sent on Sat, 30 May 2026 22:09:55 -0700:

> git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git tags/input-for-v7.1-rc5

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/227abb780c68687d6800cf9eafaff0cbeca4bf45

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ permalink raw reply

* [PATCH] HID: steelseries: Add MSI Raider A18 HX A9WJG RGB support
From: David Glushkov @ 2026-05-31 21:52 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Benjamin Tissoires, linux-input, linux-kernel

The MSI Raider A18 HX A9WJG exposes two internal SteelSeries USB HID
devices for RGB lighting: KLC (1038:1122) for the keyboard and ALC
(1038:1161) for the lightbar/logo zones.

Add DMI-gated support for these devices and expose them as multicolor
LED class devices. The driver sends the same HID class SET_REPORT
control transfer as the tested userspace implementation for this
machine and writes a uniform RGB value to all known keyboard keys or
ALC zones.

Limit binding to USB interface 0 and the tested DMI system because the
KLC product ID is shared across MSI laptop designs and the key layout
mapping is model-specific.

Tested on MSI Raider A18 HX A9WJG. Both internal SteelSeries ALC
(1038:1161) and KLC (1038:1122) HID devices bind on interface 0 and
create steelseries::lightbar and steelseries::kbd_backlight. Setting
multi_intensity and brightness changes the keyboard and lightbar
colors.

Signed-off-by: David Glushkov <david.glushkov@sntiq.com>
---
 drivers/hid/hid-ids.h         |   2 +
 drivers/hid/hid-steelseries.c | 176 +++++++++++++++++++++++++++++++++-
 2 files changed, 176 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 426ff78..83599bd 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -1368,6 +1368,8 @@
 #define USB_DEVICE_ID_STEELSERIES_SRWS1	0x1410
 #define USB_DEVICE_ID_STEELSERIES_ARCTIS_1  0x12b6
 #define USB_DEVICE_ID_STEELSERIES_ARCTIS_9  0x12c2
+#define USB_DEVICE_ID_STEELSERIES_MSI_KLC   0x1122
+#define USB_DEVICE_ID_STEELSERIES_MSI_ALC   0x1161
 
 #define USB_VENDOR_ID_SUN		0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
index f984356..0492814 100644
--- a/drivers/hid/hid-steelseries.c
+++ b/drivers/hid/hid-steelseries.c
@@ -10,16 +10,23 @@
  */
 
 #include <linux/device.h>
+#include <linux/dmi.h>
 #include <linux/hid.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/leds.h>
+#include <linux/led-class-multicolor.h>
 
 #include "hid-ids.h"
 
 #define STEELSERIES_SRWS1		BIT(0)
 #define STEELSERIES_ARCTIS_1		BIT(1)
 #define STEELSERIES_ARCTIS_9		BIT(2)
+#define STEELSERIES_MSI_RGB		BIT(3)
+
+#define STEELSERIES_HAS_LEDS_MULTICOLOR \
+	(IS_BUILTIN(CONFIG_LEDS_CLASS_MULTICOLOR) || \
+	 (IS_MODULE(CONFIG_LEDS_CLASS_MULTICOLOR) && IS_MODULE(CONFIG_HID_STEELSERIES)))
 
 struct steelseries_device {
 	struct hid_device *hdev;
@@ -34,6 +41,13 @@ struct steelseries_device {
 	uint8_t battery_capacity;
 	bool headset_connected;
 	bool battery_charging;
+
+#if STEELSERIES_HAS_LEDS_MULTICOLOR
+	struct led_classdev_mc mc_cdev;
+	struct mc_subled subled_info[3];
+	struct mutex rgb_lock; /* protects rgb_buf */
+	u8 *rgb_buf;
+#endif
 };
 
 #if IS_BUILTIN(CONFIG_LEDS_CLASS) || \
@@ -528,6 +542,140 @@ static bool steelseries_is_vendor_usage_page(struct hid_device *hdev, uint8_t us
 		hdev->rdesc[2] == 0xff;
 }
 
+static const struct dmi_system_id steelseries_msi_rgb_dmi_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Raider A18 HX A9WJG"),
+			DMI_MATCH(DMI_BOARD_NAME, "MS-182L"),
+		},
+	},
+	{ }
+};
+
+static struct usb_device *steelseries_hid_to_usb_dev(struct hid_device *hdev)
+{
+	return interface_to_usbdev(to_usb_interface(hdev->dev.parent));
+}
+
+static bool steelseries_msi_rgb_is_interface0(struct hid_device *hdev)
+{
+	return to_usb_interface(hdev->dev.parent) ==
+	       usb_ifnum_to_if(steelseries_hid_to_usb_dev(hdev), 0);
+}
+
+#if STEELSERIES_HAS_LEDS_MULTICOLOR
+
+static int steelseries_msi_rgb_set_blocking(struct led_classdev *led_cdev,
+					    enum led_brightness brightness)
+{
+	struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(led_cdev);
+	struct steelseries_device *sd = container_of(mc_cdev, struct steelseries_device, mc_cdev);
+	struct hid_device *hdev = sd->hdev;
+	struct usb_device *udev = steelseries_hid_to_usb_dev(hdev);
+	int i, ret;
+	u8 r, g, b;
+
+	static const u8 keys[] = {
+		0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+		0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+		0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+		0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+		0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x33, 0x34,
+		0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+		0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
+		0x45, 0x46, 0x47, 0x49, 0x4b, 0x4c, 0x4e, 0x4f,
+		0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+		0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+		0x60, 0x61, 0x62, 0x63, 0x64, 0x66, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xf0
+	};
+	static const u8 alc_zones[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+	mutex_lock(&sd->rgb_lock);
+
+	led_mc_calc_color_components(mc_cdev, brightness);
+
+	r = mc_cdev->subled_info[0].brightness;
+	g = mc_cdev->subled_info[1].brightness;
+	b = mc_cdev->subled_info[2].brightness;
+
+	memset(sd->rgb_buf, 0, 524);
+	sd->rgb_buf[0] = 0x0c;
+	sd->rgb_buf[1] = 0x00;
+	sd->rgb_buf[3] = 0x00;
+
+	if (hdev->product == USB_DEVICE_ID_STEELSERIES_MSI_KLC) {
+		sd->rgb_buf[2] = 0x66;
+		for (i = 0; i < ARRAY_SIZE(keys); i++) {
+			sd->rgb_buf[4 + i * 4] = keys[i];
+			sd->rgb_buf[5 + i * 4] = r;
+			sd->rgb_buf[6 + i * 4] = g;
+			sd->rgb_buf[7 + i * 4] = b;
+		}
+	} else {
+		sd->rgb_buf[2] = 0x06;
+		for (i = 0; i < ARRAY_SIZE(alc_zones); i++) {
+			sd->rgb_buf[4 + i * 4] = alc_zones[i];
+			sd->rgb_buf[5 + i * 4] = r;
+			sd->rgb_buf[6 + i * 4] = g;
+			sd->rgb_buf[7 + i * 4] = b;
+		}
+	}
+
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      HID_REQ_SET_REPORT,
+			      USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			      0x0300, 0,
+			      sd->rgb_buf, 524, USB_CTRL_SET_TIMEOUT);
+
+	mutex_unlock(&sd->rgb_lock);
+	return ret < 0 ? ret : 0;
+}
+
+static int steelseries_msi_rgb_register(struct steelseries_device *sd)
+{
+	struct hid_device *hdev = sd->hdev;
+	struct led_classdev *led_cdev;
+
+	sd->rgb_buf = devm_kzalloc(&hdev->dev, 524, GFP_KERNEL);
+	if (!sd->rgb_buf)
+		return -ENOMEM;
+
+	mutex_init(&sd->rgb_lock);
+
+	sd->subled_info[0].color_index = LED_COLOR_ID_RED;
+	sd->subled_info[1].color_index = LED_COLOR_ID_GREEN;
+	sd->subled_info[2].color_index = LED_COLOR_ID_BLUE;
+	sd->subled_info[0].intensity = 255;
+	sd->subled_info[1].intensity = 255;
+	sd->subled_info[2].intensity = 255;
+	sd->subled_info[0].channel = 0;
+	sd->subled_info[1].channel = 1;
+	sd->subled_info[2].channel = 2;
+
+	sd->mc_cdev.subled_info = sd->subled_info;
+	sd->mc_cdev.num_colors = 3;
+
+	led_cdev = &sd->mc_cdev.led_cdev;
+	if (hdev->product == USB_DEVICE_ID_STEELSERIES_MSI_KLC)
+		led_cdev->name = "steelseries::kbd_backlight";
+	else
+		led_cdev->name = "steelseries::lightbar";
+
+	led_cdev->max_brightness = 255;
+	led_cdev->brightness_set_blocking = steelseries_msi_rgb_set_blocking;
+
+	return devm_led_classdev_multicolor_register(&hdev->dev, &sd->mc_cdev);
+}
+#else
+static int steelseries_msi_rgb_register(struct steelseries_device *sd)
+{
+	return -ENODEV;
+}
+#endif
+
 static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	struct steelseries_device *sd;
@@ -549,6 +697,12 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id
 	sd->hdev = hdev;
 	sd->quirks = id->driver_data;
 
+	if (sd->quirks & STEELSERIES_MSI_RGB) {
+		if (!dmi_check_system(steelseries_msi_rgb_dmi_table) ||
+		    !steelseries_msi_rgb_is_interface0(hdev))
+			return -ENODEV;
+	}
+
 	ret = hid_parse(hdev);
 	if (ret)
 		return ret;
@@ -567,7 +721,15 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id
 	if (ret)
 		return ret;
 
-	if (steelseries_headset_battery_register(sd) < 0)
+	if (sd->quirks & STEELSERIES_MSI_RGB) {
+		ret = steelseries_msi_rgb_register(sd);
+		if (ret)
+			hid_err(hdev, "Failed to register MSI RGB LEDs: %d\n", ret);
+		return ret;
+	}
+
+	if (sd->quirks & (STEELSERIES_ARCTIS_1 | STEELSERIES_ARCTIS_9) &&
+	    steelseries_headset_battery_register(sd) < 0)
 		hid_err(sd->hdev,
 			"Failed to register battery for headset\n");
 
@@ -635,7 +797,7 @@ static int steelseries_headset_raw_event(struct hid_device *hdev,
 	unsigned long flags;
 
 	/* Not a headset */
-	if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1)
+	if (!(sd->quirks & (STEELSERIES_ARCTIS_1 | STEELSERIES_ARCTIS_9)))
 		return 0;
 
 	if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_1) {
@@ -732,6 +894,16 @@ static const struct hid_device_id steelseries_devices[] = {
 	  HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_9),
 	  .driver_data = STEELSERIES_ARCTIS_9 },
 
+#if STEELSERIES_HAS_LEDS_MULTICOLOR
+	{ /* MSI Raider A18 KLC */
+	  HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_MSI_KLC),
+	  .driver_data = STEELSERIES_MSI_RGB },
+
+	{ /* MSI Raider A18 ALC */
+	  HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_MSI_ALC),
+	  .driver_data = STEELSERIES_MSI_RGB },
+#endif
+
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, steelseries_devices);
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH] HID: steelseries: Add MSI Raider A18 HX A9WJG RGB support
From: sashiko-bot @ 2026-05-31 22:06 UTC (permalink / raw)
  To: David Glushkov; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <20260531215204.172030-1-david.glushkov@sntiq.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Type Confusion / Out-of-Bounds Read due to unsafe cast to `usb_interface`
- [High] `steelseries_remove()` unconditionally calls `cancel_delayed_work_sync()` on an uninitialized `delayed_work` struct.
- [Medium] Missing `hid_hw_stop()` and `hid_hw_close()` on probe error path.
- [Medium] Missing runtime PM management during direct USB control transfer, breaking LED updates when the device is idle.
--

commit 827dd1dcdf0039cad78b73365e7fd12bdc59d84e
Author: David Glushkov <david.glushkov@sntiq.com>

HID: steelseries: Add MSI Raider A18 HX A9WJG RGB support

This patch adds support for MSI Raider A18 HX A9WJG internal RGB devices
(KLC and ALC) to the steelseries HID driver. It exposes them as multicolor
LED class devices and sets uniform RGB values across zones.

> diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
> index f98435631aa18..0492814791753 100644
> --- a/drivers/hid/hid-steelseries.c
> +++ b/drivers/hid/hid-steelseries.c

[ ... ]

> @@ -528,6 +542,140 @@ static bool steelseries_is_vendor_usage_page(struct hid_device *hdev, uint8_t us
>  		hdev->rdesc[2] == 0xff;
>  }
>  
> +static const struct dmi_system_id steelseries_msi_rgb_dmi_table[] = {
> +	{
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Raider A18 HX A9WJG"),
> +			DMI_MATCH(DMI_BOARD_NAME, "MS-182L"),
> +		},
> +	},
> +	{ }
> +};
> +
> +static struct usb_device *steelseries_hid_to_usb_dev(struct hid_device *hdev)
> +{
> +	return interface_to_usbdev(to_usb_interface(hdev->dev.parent));
> +}

[Severity: High]
Could this cause an out-of-bounds read if the device is not a USB device?

If a local user injects a virtual HID device with the MSI RGB vendor and
product IDs via the uhid subsystem, the device's parent will be the uhid
device, not a usb_interface.

Calling to_usb_interface() and interface_to_usbdev() without first verifying
the transport using hid_is_usb(hdev) could interpret the uhid parent memory
as a usb_interface, leading to wild pointer dereferences and a panic.

> +
> +static bool steelseries_msi_rgb_is_interface0(struct hid_device *hdev)
> +{
> +	return to_usb_interface(hdev->dev.parent) ==
> +	       usb_ifnum_to_if(steelseries_hid_to_usb_dev(hdev), 0);
> +}
> +
> +#if STEELSERIES_HAS_LEDS_MULTICOLOR
> +
> +static int steelseries_msi_rgb_set_blocking(struct led_classdev *led_cdev,
> +					    enum led_brightness brightness)
> +{

[ ... ]

> +	if (hdev->product == USB_DEVICE_ID_STEELSERIES_MSI_KLC) {
> +		sd->rgb_buf[2] = 0x66;
> +		for (i = 0; i < ARRAY_SIZE(keys); i++) {
> +			sd->rgb_buf[4 + i * 4] = keys[i];
> +			sd->rgb_buf[5 + i * 4] = r;
> +			sd->rgb_buf[6 + i * 4] = g;
> +			sd->rgb_buf[7 + i * 4] = b;
> +		}
> +	} else {
> +		sd->rgb_buf[2] = 0x06;
> +		for (i = 0; i < ARRAY_SIZE(alc_zones); i++) {
> +			sd->rgb_buf[4 + i * 4] = alc_zones[i];
> +			sd->rgb_buf[5 + i * 4] = r;
> +			sd->rgb_buf[6 + i * 4] = g;
> +			sd->rgb_buf[7 + i * 4] = b;
> +		}
> +	}
> +
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			      HID_REQ_SET_REPORT,
> +			      USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> +			      0x0300, 0,
> +			      sd->rgb_buf, 524, USB_CTRL_SET_TIMEOUT);

[Severity: Medium]
Will this USB control message fail if the device has entered runtime suspend?

Because this directly uses usb_control_msg() and bypasses the HID transport
layer, it doesn't appear to wake the device. Without explicitly waking the
device via hid_hw_power(hdev, PM_HINT_FULLON) or usb_autopm_get_interface(),
the transfer might drop LED updates when the keyboard is idle.

> +
> +	mutex_unlock(&sd->rgb_lock);
> +	return ret < 0 ? ret : 0;
> +}

[ ... ]

> @@ -567,7 +721,15 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id
>  	if (ret)
>  		return ret;
>  
> -	if (steelseries_headset_battery_register(sd) < 0)
> +	if (sd->quirks & STEELSERIES_MSI_RGB) {
> +		ret = steelseries_msi_rgb_register(sd);
> +		if (ret)
> +			hid_err(hdev, "Failed to register MSI RGB LEDs: %d\n", ret);
> +		return ret;
> +	}

[Severity: Medium]
Does this error path leak the hardware state initialized by hid_hw_start()
and hid_hw_open() called earlier in steelseries_probe()?

Returning directly here skips calling hid_hw_stop() and hid_hw_close(),
which could leave active URBs and orphaned hidinput/hidraw device nodes
exposed to userspace.

> +
> +	if (sd->quirks & (STEELSERIES_ARCTIS_1 | STEELSERIES_ARCTIS_9) &&
> +	    steelseries_headset_battery_register(sd) < 0)
>  		hid_err(sd->hdev,
>  			"Failed to register battery for headset\n");

[Severity: High]
Since steelseries_headset_battery_register() and INIT_DELAYED_WORK() are
skipped for MSI RGB devices here, what happens when the device is removed?

If steelseries_remove() unconditionally calls cancel_delayed_work_sync() on
sd->battery_work, passing a zero-initialized work struct will trigger a
debug objects (ODEBUG) warning and splat on device removal.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260531215204.172030-1-david.glushkov@sntiq.com?part=1

^ permalink raw reply


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