* Re: [PATCH 2/9] iio: orientation: hid-sensor-incl-3d: Fix race between callback registration and device exposure
From: Pandruvada, Srinivas @ 2026-06-15 13:36 UTC (permalink / raw)
To: jic23@kernel.org
Cc: dlechner@baylibre.com, archana.patni@linux.intel.com,
hongyan.song@intel.com, linux-iio@vger.kernel.org,
nuno.sa@analog.com, linux-kernel@vger.kernel.org,
jikos@kernel.org, andy@kernel.org, sanjayembeddedse@gmail.com,
linux-input@vger.kernel.org
In-Reply-To: <20260614192442.6eaa1a54@jic23-huawei>
On Sun, 2026-06-14 at 19:24 +0100, Jonathan Cameron wrote:
> On Mon, 8 Jun 2026 15:34:05 +0000
> "Pandruvada, Srinivas" <srinivas.pandruvada@intel.com> wrote:
>
> > On Sat, 2026-06-06 at 17:07 +0530, Sanjay Chitroda wrote:
> > > From: Sanjay Chitroda <sanjayembeddedse@gmail.com>
> > >
> > > The driver registers the IIO device before completing sensor hub
> > > callback registration and unregisters callbacks while the IIO
> > > device
> > > is still exposed during teardown.
> > >
> > > This creates race windows in both probe and remove paths, which
> > > can
> > > lead to NULL pointer dereferences or use-after-free.
> >
> > Reordering is fine, but can you show how this use after free is
> > possible?
> Agreed - I'm not seeing a definite issue so more info needed.
> For now I'm going to mark this changes-requested in patchwork.
>
> It might be a touch slow if someone manages to get buffered capture
> up before the callbacks are available, but I think that just means
> dropping a few samples?
Correct.
Thanks,
Srinivas
>
> Jonathan
>
> >
> > Thanks,
> > Srinivas
>
^ permalink raw reply
* Re: [PATCH] HID: hidpp: fix potential UAF in hidpp_connect_event()
From: sashiko-bot @ 2026-06-15 13:12 UTC (permalink / raw)
To: Jiri Kosina; +Cc: dmitry.torokhov, linux-input
In-Reply-To: <qq420675-14n0-p23s-10oo-1n8113s2nq22@xreary.bet>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Dangling pointer Use-After-Free when `input_register_device()` fails during synchronous probe via `hid_connect()`.
- [High] Time-of-Check to Time-of-Use (TOCTOU) race condition leading to a Use-After-Free.
--
commit 958cf4bb8a3ce7336c278ac4fb346b928f5fe9b9
Author: Jiri Kosina <jikos@kernel.org>
HID: hidpp: fix potential UAF in hidpp_connect_event()
If input_register_device() fails, we call input_free_device(), but keep
stale pointer to the old device in hidpp->input, which could potentially
lead to UAF. Fix that by resetting it to NULL before returning from
hidpp_connect_event().
Reported-by: zdi-disclosures@trendmicro.com
Signed-off-by: Jiri Kosina <jkosina@suse.com>
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index ccbf28869a968..d8e86b6ccf375 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -4295,6 +4295,7 @@ static void hidpp_connect_event(struct work_struct *work)
>
> ret = input_register_device(input);
> if (ret) {
> + hidpp->input = NULL;
[Severity: High]
This is a pre-existing issue, but does this clear the shared state too late to
prevent a race condition?
Since hidpp_connect_event() runs asynchronously in a workqueue, hardware
events can be processed concurrently in interrupt context. The allocated
device pointer is published to the global hidpp->input state via
hidpp_populate_input() before the registration attempt.
A concurrent raw event could read hidpp->input and pass the safety check:
drivers/hid/hid-logitech-hidpp.c:wtp_raw_event() {
if (!wd || !hidpp->input)
return 1;
}
If input_register_device() then fails, the error path clears hidpp->input
and frees the memory locklessly.
Could the concurrent raw event handler, already past the safety check,
access the freed memory and cause a use-after-free?
> input_free_device(input);
> return;
[Severity: Critical]
This is also a pre-existing issue, but does a similar dangling pointer remain
if registration fails during synchronous probe?
While this patch addresses a dangling pointer in hidpp_connect_event(), a
similar situation appears to exist in the hid core connection path. For
non-delayed devices, hidinput_connect() calls hidpp_input_configured(),
which caches hidinput->input into hidpp->input:
drivers/hid/hid-logitech-hidpp.c:hidpp_input_configured() {
hidpp_populate_input(hidpp, input);
}
Immediately after, hidinput_connect() calls input_register_device(). If
registration fails, the error path frees the device:
drivers/hid/hid-input.c:hidinput_connect() {
if (input_register_device(hidinput->input))
goto out_unwind;
}
Because hid_connect() ignores the hidinput_connect() failure when the
driver has a raw_event handler, probe succeeds and the device remains active.
Would incoming hardware events then trigger hidpp_raw_event(), successfully
pass the check against hidpp->input, and dereference the freed pointer?
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/qq420675-14n0-p23s-10oo-1n8113s2nq22@xreary.bet?part=1
^ permalink raw reply
* [PATCH] HID: hidpp: fix potential UAF in hidpp_connect_event()
From: Jiri Kosina @ 2026-06-15 12:58 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: linux-kernel, linux-input
From: Jiri Kosina <jkosina@suse.com>
If input_register_device() fails, we call input_free_device(), but keep
stale pointer to the old device in hidpp->input, which could potentially
lead to UAF. Fix that by resetting it to NULL before returning from
hidpp_connect_event().
Reported-by: zdi-disclosures@trendmicro.com
Signed-off-by: Jiri Kosina <jkosina@suse.com>
---
v1->v2: set hidpp->input to NULL before freeing the device to avoid race
as reported by Sashiko
drivers/hid/hid-logitech-hidpp.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index ccbf28869a96..d8e86b6ccf37 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4295,6 +4295,7 @@ static void hidpp_connect_event(struct work_struct *work)
ret = input_register_device(input);
if (ret) {
+ hidpp->input = NULL;
input_free_device(input);
return;
}
--
Jiri Kosina
SUSE Labs
^ permalink raw reply related
* Re: [PATCH 05/10] [v2] mips: select legacy gpiolib interfaces where used
From: Thomas Bogendoerfer @ 2026-06-15 10:33 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-gpio, linux-kernel, Arnd Bergmann, Christian Lamparter,
Johannes Berg, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, John Paul Adrian Glaubitz,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Linus Walleij, Bartosz Golaszewski,
Dmitry Torokhov, Lee Jones, Pavel Machek, Matti Vaittinen,
Florian Fainelli, Jonas Gorski, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-wireless, linux-omap, linux-arm-kernel, linux-mips,
linux-sh, linux-input, linux-leds, netdev, Bartosz Golaszewski
In-Reply-To: <20260520183815.2510387-6-arnd@kernel.org>
On Wed, May 20, 2026 at 08:38:10PM +0200, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> A few old machines have not been converted away from the old-style
> gpiolib interfaces. Make these select the new CONFIG_GPIOLIB_LEGACY
> symbol so the code still works where it is needed but can be left
> out otherwise.
>
> This is the list of all gpio_request() calls in mips:
>
> arch/mips/alchemy/devboards/db1000.c: gpio_request(19, "sd0_cd");
> arch/mips/alchemy/devboards/db1000.c: gpio_request(20, "sd1_cd");
> arch/mips/alchemy/devboards/db1200.c: gpio_request(215, "otg-vbus");
> arch/mips/bcm47xx/workarounds.c: err = gpio_request_one(usb_power, GPIOF_OUT_INIT_HIGH, "usb_power");
> arch/mips/bcm63xx/boards/board_bcm963xx.c: gpio_request_one(board.ephy_reset_gpio,
> arch/mips/txx9/rbtx4927/setup.c: gpio_request(15, "sio-dtr");
>
> Most of these should be easy enough to change to modern gpio descriptors
> or remove if they are no longer in use.
>
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> v2: no changes. There was no discussion on this, but the patch
> has so far not made it into the linux-mips tree, so I'm including
> it for completeness.
> ---
> arch/mips/Kconfig | 5 +++++
> arch/mips/alchemy/Kconfig | 1 -
> arch/mips/txx9/Kconfig | 1 +
> 3 files changed, 6 insertions(+), 1 deletion(-)
applied to mips-next
Thomas.
--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]
^ permalink raw reply
* Re: [PATCH v3 2/4] Input: snvs_pwrkey - replace hardcoding -EINVAL with original error code
From: sashiko-bot @ 2026-06-15 7:58 UTC (permalink / raw)
To: joy.zou; +Cc: Frank.Li, imx, linux-input, dmitry.torokhov
In-Reply-To: <20260615-b4-pwrkey-v3-2-9510b1173f6e@oss.nxp.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing cleanup for dev_pm_set_wake_irq() causes memory leak and state corruption on driver unbind.
- [High] Systematic failure to check regmap_read() return values leads to consuming uninitialized stack memory, risking spurious system shutdown.
--
commit d2ee00e9f90457779e6f0d87a01d54e5af524f82
Author: Joy Zou <joy.zou@nxp.com>
Input: snvs_pwrkey - replace hardcoding -EINVAL with original error code
This commit replaces a hardcoded -EINVAL with the actual error code returned
by platform_get_irq(). This preserves valuable diagnostic information and
allows probe deferral (-EPROBE_DEFER) to work correctly.
> diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
> index 748196fcce75b..a291812e6d22e 100644
> --- a/drivers/input/keyboard/snvs_pwrkey.c
> +++ b/drivers/input/keyboard/snvs_pwrkey.c
> @@ -148,7 +148,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
>
> pdata->irq = platform_get_irq(pdev, 0);
> if (pdata->irq < 0)
> - return -EINVAL;
> + return pdata->irq;
>
> error = of_property_read_u32(np, "power-off-time-sec", &val);
> if (!error) {
[ ... ]
[Severity: High]
This is a pre-existing issue, but I noticed a potential lifecycle regression
further down in imx_snvs_pwrkey_probe():
drivers/input/keyboard/snvs_pwrkey.c:imx_snvs_pwrkey_probe() {
...
error = dev_pm_set_wake_irq(dev, pdata->irq);
if (error)
dev_err(dev, "irq wake enable failed.\n");
...
}
The driver configures a wake IRQ using dev_pm_set_wake_irq(), which
allocates a wake_irq structure and attaches it to dev->power.wakeirq.
However, there doesn't appear to be a paired remove callback to call
dev_pm_clear_wake_irq() during driver unbind.
Does this permanently leak memory if the driver is unbound via sysfs?
Additionally, since the underlying IRQ is managed by devm_request_irq(), it
will be freed on unbind while dev->power.wakeirq remains configured. If the
system later attempts to suspend, could the PM core evaluate
device_may_wakeup() (which remains true since device_init_wakeup() isn't
reverted) and call enable_irq_wake() on a freed IRQ?
[ ... ]
[Severity: High]
This isn't a bug introduced by this patch, but I also noticed that
regmap_read() return values are not checked in several places before
consuming the variables passed by reference:
drivers/input/keyboard/snvs_pwrkey.c:imx_snvs_pwrkey_interrupt() {
...
u32 lp_status;
pm_wakeup_event(input->dev.parent, 0);
regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
if (lp_status & SNVS_LPSR_SPO) {
...
}
It also happens in the timer handler:
drivers/input/keyboard/snvs_pwrkey.c:imx_imx_snvs_check_for_events() {
...
u32 state;
regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
state = state & SNVS_HPSR_BTN ? 1 : 0;
...
}
If regmap_read() fails (e.g., due to an underlying clock enable failure or
MMIO bus error), it returns an error code and leaves the target stack
variables (lp_status, state) uninitialized.
Since these uninitialized stack variables are then used in logic checks,
could this lead to unpredictable behavior? For example, in the interrupt
and timer handlers, if the uninitialized stack memory randomly has the
SNVS_LPSR_SPO or SNVS_HPSR_BTN bits set, would this trigger a spurious
KEY_POWER event and an unintended system shutdown?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com?part=2
^ permalink raw reply
* Re: [PATCH v3 1/4] Input: snvs_pwrkey - make use of dev_err_probe()
From: sashiko-bot @ 2026-06-15 7:57 UTC (permalink / raw)
To: joy.zou; +Cc: linux-input, Frank.Li, dmitry.torokhov, imx
In-Reply-To: <20260615-b4-pwrkey-v3-1-9510b1173f6e@oss.nxp.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Medium] Missing `.remove` callback causes a leak of `struct wake_irq` and leaves dangling wakeup configuration upon driver unbind.
--
commit 07567ee0ff85afeb83d7fcfa00735130f4ec77e0
Author: Joy Zou <joy.zou@nxp.com>
Input: snvs_pwrkey - make use of dev_err_probe()
This commit updates the imx_snvs_pwrkey_probe function to use dev_err_probe
for its error paths. This helps simplify error logging and properly handles
probe deferral conditions.
> diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
> --- a/drivers/input/keyboard/snvs_pwrkey.c
> +++ b/drivers/input/keyboard/snvs_pwrkey.c
[ ... ]
> @@ -209,16 +203,12 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
> error = devm_request_irq(&pdev->dev, pdata->irq,
> imx_snvs_pwrkey_interrupt,
> 0, pdev->name, pdev);
> - if (error) {
> - dev_err(&pdev->dev, "interrupt not available.\n");
> - return error;
> - }
> + if (error)
> + return dev_err_probe(&pdev->dev, error, "interrupt not available.\n");
>
> error = input_register_device(input);
> - if (error < 0) {
> - dev_err(&pdev->dev, "failed to register input device\n");
> - return error;
> - }
> + if (error < 0)
> + return dev_err_probe(&pdev->dev, error, "failed to register input device\n");
>
> device_init_wakeup(&pdev->dev, pdata->wakeup);
> error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
[Severity: Medium]
This is a pre-existing issue, but I noticed there might be a resource cleanup
issue here in imx_snvs_pwrkey_probe().
Does this code leak the wakeup resources when the driver is unbound?
It appears that device_init_wakeup() and dev_pm_set_wake_irq() allocate
unmanaged resources and attach them to the device. Because there is no remove
callback or managed action to clean them up via dev_pm_clear_wake_irq() and
device_init_wakeup(dev, false), these resources might be leaked on unbind.
If the driver is later re-bound, could this also cause probe to fail since
dev_pm_attach_wake_irq() returns -EEXIST when the wakeirq is already
initialized?
Would it be appropriate to switch these to devm_device_init_wakeup() and
devm_pm_set_wake_irq() to handle the cleanup automatically?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com?part=1
^ permalink raw reply
* Re: [PATCH v3 3/4] Input: snvs_pwrkey - use local device pointer to simple code
From: sashiko-bot @ 2026-06-15 7:57 UTC (permalink / raw)
To: joy.zou; +Cc: linux-input, Frank.Li, imx, dmitry.torokhov
In-Reply-To: <20260615-b4-pwrkey-v3-3-9510b1173f6e@oss.nxp.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The driver calls `dev_pm_set_wake_irq()` but does not use the `devm_` variant or provide a `.remove` function, leading to a resource leak and potentially broken system suspend on driver unbind.
--
commit d7d5ed812213c739d1459c472b4e230aac0a6e8d
Author: Joy Zou <joy.zou@nxp.com>
Input: snvs_pwrkey - use local device pointer to simple code
This commit introduces a local struct device pointer in the probe function
to reduce boilerplate code when referencing the platform device. It is
intended to be a non-functional change.
> diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
> --- a/drivers/input/keyboard/snvs_pwrkey.c
> +++ b/drivers/input/keyboard/snvs_pwrkey.c
[ ... ]
> @@ -193,27 +194,27 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
[ ... ]
> - device_init_wakeup(&pdev->dev, pdata->wakeup);
> - error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
> + device_init_wakeup(dev, pdata->wakeup);
> + error = dev_pm_set_wake_irq(dev, pdata->irq);
[Severity: High]
This is a pre-existing issue, but does this leak the wake IRQ on driver
unbind?
Looking at imx_snvs_pwrkey_probe() in drivers/input/keyboard/snvs_pwrkey.c,
the driver configures the wake IRQ using dev_pm_set_wake_irq() but it does
not use the devm_ variant, nor does it provide a .remove callback to call
dev_pm_clear_wake_irq().
When the driver unbinds, devres automatically frees the IRQ, but the memory
for the wake IRQ structure remains allocated and attached to
dev->power.wakeirq.
Will a subsequent system suspend then attempt to call enable_irq_wake() on a
freed IRQ number? Also, if the driver is later re-bound, would it trigger a
warning in dev_pm_attach_wake_irq() because dev->power.wakeirq is already
initialized?
Should this be updated to use devm_pm_set_wake_irq() instead?
> if (error)
> - dev_err(&pdev->dev, "irq wake enable failed.\n");
> + dev_err(dev, "irq wake enable failed.\n");
>
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com?part=3
^ permalink raw reply
* [PATCH v3 4/4] Input: snvs_pwrkey - report press event in interrupt handler
From: joy.zou @ 2026-06-15 7:52 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
In-Reply-To: <20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com>
From: Joy Zou <joy.zou@nxp.com>
The driver implements debounce protection using a timer-based mechanism:
when a key interrupt occurs, a timer is scheduled to verify the key state
after DEBOUNCE_TIME before reporting the event. This works well during
normal operation.
However, key press events can be lost during system resume on platforms
like i.MX8MQ-EVK because:
1. During the no_irq resume phase, PCIe driver restoration can take up to
200ms with IRQs disabled.
2. The power key interrupt remains pending during the no_irq phase.
3. If the key is released before IRQs are re-enabled, the timer eventually
runs but sees the key as released and skips reporting the event.
Report key press events directly in interrupt handler to prevent event
loss during system suspend. This is safe because:
1. Only one event is reported per suspend cycle.
2. Normal operation retains the existing timer-based debounce mechanism.
Signed-off-by: Joy Zou <joy.zou@nxp.com>
---
Changes for v3:
1. Add spinlock for pdata->keystate and pdata->suspended per AI review
comments.
2. Replace hardcode value 1 with local variable keystate in input_report_key()
under suspended.
Changes for v2:
1. Add a boolean variable suspended and PM callback functions to replace
the use of the is_suspended field per AI review comments.
2. Move event report handle to else branch in suspended state, since the
pdata->minor_rev == 0 branch has no debounce detection per AI review
comments.
3. Modify the commit message.
---
drivers/input/keyboard/snvs_pwrkey.c | 60 ++++++++++++++++++++++++++++++++++--
1 file changed, 57 insertions(+), 3 deletions(-)
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 4a1d04898482..d6ea3c2d87c6 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -39,6 +39,8 @@ struct pwrkey_drv_data {
int keycode;
int keystate; /* 1:pressed */
int wakeup;
+ bool suspended; /* Track suspend state */
+ spinlock_t lock; /* Protects keystate and suspended */
struct timer_list check_timer;
struct input_dev *input;
u8 minor_rev;
@@ -49,14 +51,21 @@ static void imx_imx_snvs_check_for_events(struct timer_list *t)
struct pwrkey_drv_data *pdata = timer_container_of(pdata, t,
check_timer);
struct input_dev *input = pdata->input;
+ bool state_changed = false;
u32 state;
regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
state = state & SNVS_HPSR_BTN ? 1 : 0;
- /* only report new event if status changed */
- if (state ^ pdata->keystate) {
- pdata->keystate = state;
+ scoped_guard(spinlock_irqsave, &pdata->lock) {
+ /* only report new event if status changed */
+ if (state ^ pdata->keystate) {
+ pdata->keystate = state;
+ state_changed = true;
+ }
+ }
+
+ if (state_changed) {
input_event(input, EV_KEY, pdata->keycode, state);
input_sync(input);
pm_relax(pdata->input->dev.parent);
@@ -74,6 +83,8 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
struct platform_device *pdev = dev_id;
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
struct input_dev *input = pdata->input;
+ bool suspended;
+ int keystate;
u32 lp_status;
pm_wakeup_event(input->dev.parent, 0);
@@ -92,6 +103,21 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
input_sync(input);
pm_relax(input->dev.parent);
} else {
+ /*
+ * Report key press events directly in interrupt handler to prevent event
+ * loss during system suspend.
+ */
+ scoped_guard(spinlock_irqsave, &pdata->lock) {
+ suspended = pdata->suspended;
+ if (suspended) {
+ pdata->keystate = 1;
+ keystate = pdata->keystate;
+ }
+ }
+ if (suspended) {
+ input_report_key(input, pdata->keycode, keystate);
+ input_sync(input);
+ }
mod_timer(&pdata->check_timer,
jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
}
@@ -151,6 +177,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
if (pdata->irq < 0)
return pdata->irq;
+ spin_lock_init(&pdata->lock);
error = of_property_read_u32(np, "power-off-time-sec", &val);
if (!error) {
switch (val) {
@@ -219,6 +246,32 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
return 0;
}
+static int __maybe_unused imx_snvs_pwrkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
+
+ scoped_guard(spinlock_irqsave, &pdata->lock)
+ pdata->suspended = true;
+
+ return 0;
+}
+
+static int __maybe_unused imx_snvs_pwrkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
+
+ scoped_guard(spinlock_irqsave, &pdata->lock)
+ pdata->suspended = false;
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops,
+ imx_snvs_pwrkey_suspend,
+ imx_snvs_pwrkey_resume);
+
static const struct of_device_id imx_snvs_pwrkey_ids[] = {
{ .compatible = "fsl,sec-v4.0-pwrkey" },
{ /* sentinel */ }
@@ -229,6 +282,7 @@ static struct platform_driver imx_snvs_pwrkey_driver = {
.driver = {
.name = "snvs_pwrkey",
.of_match_table = imx_snvs_pwrkey_ids,
+ .pm = &imx_snvs_pwrkey_pm_ops,
},
.probe = imx_snvs_pwrkey_probe,
};
--
2.34.1
^ permalink raw reply related
* [PATCH v3 3/4] Input: snvs_pwrkey - use local device pointer to simple code
From: joy.zou @ 2026-06-15 7:52 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
In-Reply-To: <20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com>
From: Joy Zou <joy.zou@nxp.com>
Use local struct device pointer to avoid reference the platform_device
pointer every time.
No functional change.
Signed-off-by: Joy Zou <joy.zou@nxp.com>
---
Changes for v2:
1. Use dev instead of &pdev->dev for devm_input_allocate_device(),
which was missed in patch v1 per AI review comments.
2. Modify commit message.
---
drivers/input/keyboard/snvs_pwrkey.c | 41 ++++++++++++++++++------------------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index a291812e6d22..4a1d04898482 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -112,6 +112,7 @@ static void imx_snvs_pwrkey_act(void *pdata)
static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct pwrkey_drv_data *pdata;
struct input_dev *input;
struct device_node *np;
@@ -122,26 +123,26 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
u32 vid;
/* Get SNVS register Page */
- np = pdev->dev.of_node;
+ np = dev->of_node;
if (!np)
- return dev_err_probe(&pdev->dev, -ENODEV, "Device tree node not found\n");
+ return dev_err_probe(dev, -ENODEV, "Device tree node not found\n");
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
if (IS_ERR(pdata->snvs))
- return dev_err_probe(&pdev->dev, PTR_ERR(pdata->snvs), "Can't get snvs syscon\n");
+ return dev_err_probe(dev, PTR_ERR(pdata->snvs), "Can't get snvs syscon\n");
if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
pdata->keycode = KEY_POWER;
- dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
+ dev_warn(dev, "KEY_POWER without setting in dts\n");
}
- clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
+ clk = devm_clk_get_optional_enabled(dev, NULL);
if (IS_ERR(clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ return dev_err_probe(dev, PTR_ERR(clk),
"Failed to get snvs clock (%pe)\n", clk);
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
@@ -162,7 +163,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
bpt = (val / 5) - 1;
break;
default:
- return dev_err_probe(&pdev->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"power-off-time-sec %d out of range\n", val);
}
@@ -180,9 +181,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0);
- input = devm_input_allocate_device(&pdev->dev);
+ input = devm_input_allocate_device(dev);
if (!input) {
- dev_err(&pdev->dev, "failed to allocate the input device\n");
+ dev_err(dev, "failed to allocate the input device\n");
return -ENOMEM;
}
@@ -193,27 +194,27 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
input_set_capability(input, EV_KEY, pdata->keycode);
/* input customer action to cancel release timer */
- error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
+ error = devm_add_action(dev, imx_snvs_pwrkey_act, pdata);
if (error)
- return dev_err_probe(&pdev->dev, error, "failed to register remove action\n");
+ return dev_err_probe(dev, error, "failed to register remove action\n");
pdata->input = input;
platform_set_drvdata(pdev, pdata);
- error = devm_request_irq(&pdev->dev, pdata->irq,
- imx_snvs_pwrkey_interrupt,
- 0, pdev->name, pdev);
+ error = devm_request_irq(dev, pdata->irq,
+ imx_snvs_pwrkey_interrupt,
+ 0, pdev->name, pdev);
if (error)
- return dev_err_probe(&pdev->dev, error, "interrupt not available.\n");
+ return dev_err_probe(dev, error, "interrupt not available.\n");
error = input_register_device(input);
if (error < 0)
- return dev_err_probe(&pdev->dev, error, "failed to register input device\n");
+ return dev_err_probe(dev, error, "failed to register input device\n");
- device_init_wakeup(&pdev->dev, pdata->wakeup);
- error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
+ device_init_wakeup(dev, pdata->wakeup);
+ error = dev_pm_set_wake_irq(dev, pdata->irq);
if (error)
- dev_err(&pdev->dev, "irq wake enable failed.\n");
+ dev_err(dev, "irq wake enable failed.\n");
return 0;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v3 2/4] Input: snvs_pwrkey - replace hardcoding -EINVAL with original error code
From: joy.zou @ 2026-06-15 7:52 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
In-Reply-To: <20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com>
From: Joy Zou <joy.zou@nxp.com>
Hardcoding -EINVAL discards the actual error code, which breaks probe
deferral (-EPROBE_DEFER) and loses critical diagnostic information
needed for proper kernel error handling.
Signed-off-by: Joy Zou <joy.zou@nxp.com>
---
drivers/input/keyboard/snvs_pwrkey.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 748196fcce75..a291812e6d22 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -148,7 +148,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
pdata->irq = platform_get_irq(pdev, 0);
if (pdata->irq < 0)
- return -EINVAL;
+ return pdata->irq;
error = of_property_read_u32(np, "power-off-time-sec", &val);
if (!error) {
--
2.34.1
^ permalink raw reply related
* [PATCH v3 1/4] Input: snvs_pwrkey - make use of dev_err_probe()
From: joy.zou @ 2026-06-15 7:52 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
In-Reply-To: <20260615-b4-pwrkey-v3-0-9510b1173f6e@oss.nxp.com>
From: Joy Zou <joy.zou@nxp.com>
Add dev_err_probe() at return path of probe() to support users to
identify issues easier.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Joy Zou <joy.zou@nxp.com>
---
Changes in v2:
1. Drop dev_err_probe() change for platform_get_irq() per AI review comments.
2. Add Reviewed-by tag.
---
drivers/input/keyboard/snvs_pwrkey.c | 38 +++++++++++++-----------------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 954055aaf6e2..748196fcce75 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -124,17 +124,15 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
/* Get SNVS register Page */
np = pdev->dev.of_node;
if (!np)
- return -ENODEV;
+ return dev_err_probe(&pdev->dev, -ENODEV, "Device tree node not found\n");
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
- if (IS_ERR(pdata->snvs)) {
- dev_err(&pdev->dev, "Can't get snvs syscon\n");
- return PTR_ERR(pdata->snvs);
- }
+ if (IS_ERR(pdata->snvs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pdata->snvs), "Can't get snvs syscon\n");
if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
pdata->keycode = KEY_POWER;
@@ -142,10 +140,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
}
clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk);
- return PTR_ERR(clk);
- }
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "Failed to get snvs clock (%pe)\n", clk);
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
@@ -165,9 +162,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
bpt = (val / 5) - 1;
break;
default:
- dev_err(&pdev->dev,
- "power-off-time-sec %d out of range\n", val);
- return -EINVAL;
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "power-off-time-sec %d out of range\n", val);
}
regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_BPT_MASK,
@@ -198,10 +194,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
/* input customer action to cancel release timer */
error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
- if (error) {
- dev_err(&pdev->dev, "failed to register remove action\n");
- return error;
- }
+ if (error)
+ return dev_err_probe(&pdev->dev, error, "failed to register remove action\n");
pdata->input = input;
platform_set_drvdata(pdev, pdata);
@@ -209,16 +203,12 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
error = devm_request_irq(&pdev->dev, pdata->irq,
imx_snvs_pwrkey_interrupt,
0, pdev->name, pdev);
- if (error) {
- dev_err(&pdev->dev, "interrupt not available.\n");
- return error;
- }
+ if (error)
+ return dev_err_probe(&pdev->dev, error, "interrupt not available.\n");
error = input_register_device(input);
- if (error < 0) {
- dev_err(&pdev->dev, "failed to register input device\n");
- return error;
- }
+ if (error < 0)
+ return dev_err_probe(&pdev->dev, error, "failed to register input device\n");
device_init_wakeup(&pdev->dev, pdata->wakeup);
error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
--
2.34.1
^ permalink raw reply related
* [PATCH v3 0/4] snvs_pwrkey - code improvements and add report event
From: joy.zou @ 2026-06-15 7:52 UTC (permalink / raw)
To: Dmitry Torokhov, Frank Li, Bough Chen, Peng Fan, Jacky Bai, Ye Li
Cc: Joy Zou, imx, linux-input, linux-kernel, Joy Zou
This patch series improves the snvs_pwrkey driver with better code quality
and add report press event.
The main improvements include:
1. Clean up the code by using local device pointers and dev_err_probe() for
better readability and easier debugging.
2. Fix potential event loss during system suspend by reporting key press events
directly in the interrupt handler.
Signed-off-by: Joy Zou <joy.zou@oss.nxp.com>
---
Changes in v3:
- Add spinlock for pdata->keystate and pdata->suspended per AI review comments.
- Replace hardcode value 1 with local variable keystate in input_report_key()
under suspended.
- Link to v2: https://lore.kernel.org/r/20260604-pwrkey-cleanup-v2-0-59fa0ddf0d7c@nxp.com
Changes in v2:
- Drop dev_err_probe() change for platform_get_irq() per AI review comments.
- Add new patch #2 replace hardcoding -EINVAL with original error code per
AI review comments.
- Use dev instead of &pdev->dev for devm_input_allocate_device(), which was
missed in patch v1 per AI review comments.
- Add a boolean variable suspended and PM callback functions to replace
the use of the is_suspended field per AI review comments.
- Move event report handle to else branch in suspended state, since the
pdata->minor_rev == 0 branch has no debounce detection per AI review
comments.
- Modify patch #3 and #4 commit message.
- Add Reviewed-by tag for patch #1.
- Link to v1: https://lore.kernel.org/r/20260326-pwrkey-cleanup-v1-0-d85d7c0bf275@nxp.com
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Frank Li <Frank.Li@nxp.com>
To: Bough Chen <haibo.chen@nxp.com>
To: Peng Fan <peng.fan@nxp.com>
To: Jacky Bai <ping.bai@nxp.com>
To: Ye Li <ye.li@nxp.com>
Cc: imx@lists.linux.dev
Cc: linux-input@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Joy Zou (4):
Input: snvs_pwrkey - make use of dev_err_probe()
Input: snvs_pwrkey - replace hardcoding -EINVAL with original error code
Input: snvs_pwrkey - use local device pointer to simple code
Input: snvs_pwrkey - report press event in interrupt handler
drivers/input/keyboard/snvs_pwrkey.c | 127 ++++++++++++++++++++++++-----------
1 file changed, 86 insertions(+), 41 deletions(-)
---
base-commit: f7af91adc230aa99e23330ecf85bc9badd9780ad
change-id: 20260615-b4-pwrkey-a60b2043cd29
Best regards,
--
Joy Zou <joy.zou@oss.nxp.com>
^ permalink raw reply
* Re: [PATCH v7 8/9] regulator: Add MediaTek MT6392 regulator
From: sashiko-bot @ 2026-06-15 7:39 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: robh, linux-input, devicetree, dmitry.torokhov, conor+dt
In-Reply-To: <20260615071836.362883-9-l.scorcia@gmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Data race and state corruption due to mutation of the shared global `mt6392_regulators` array.
- [High] Logic error in `mt6392_ldo_get_mode()` reads the wrong register to determine mode.
- [Medium] Missing `.of_map_mode` callback breaks `regulator-initial-mode` parsing.
- [Medium] Poor error handling and unnecessary kernel log spamming in `mt6392_buck_set_mode`.
--
commit cf9cb32e08ea85698033220fad437d4b27bf421d
Author: Fabien Parent <parent.f@gmail.com>
regulator: Add MediaTek MT6392 regulator
The MT6392 is a regulator found on boards based on the MediaTek
MT8167, MT8516, and probably other SoCs. It is a so called PMIC and
connects as a slave to a SoC using SPI, wrapped inside PWRAP.
> diff --git a/drivers/regulator/mt6392-regulator.c b/drivers/regulator/mt6392-regulator.c
> new file mode 100644
> index 0000000000000..1f91aac3917ab
> --- /dev/null
> +++ b/drivers/regulator/mt6392-regulator.c
[ ... ]
> +static int mt6392_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
> +{
[ ... ]
> + ret = regmap_update_bits(rdev->regmap, info->pwm_modeset_reg,
> + info->pwm_modeset_mask, val);
> +
> + if (regmap_read(rdev->regmap, info->pwm_modeset_reg, ®_value) < 0) {
> + dev_err(&rdev->dev, "Failed to read register value\n");
> + return -EIO;
> + }
> +
> + dev_info(&rdev->dev, "%s: info->pwm_modeset_reg 0x%x = 0x%x\n",
> + info->desc.name, info->pwm_modeset_reg, reg_value);
> +
> + return ret;
> +}
[Severity: Medium]
Does this error handling correctly propagate failures?
If regmap_update_bits() fails, 'ret' contains the error code, but the
subsequent regmap_read() might succeed, masking the original error.
Also, since set_mode can be a hot path called frequently by power management,
could this dev_info() spam the kernel ring buffer? Would dev_dbg() be more
appropriate here?
[ ... ]
> +static unsigned int mt6392_ldo_get_mode(struct regulator_dev *rdev)
> +{
[ ... ]
> + ret = regmap_read(rdev->regmap, info->lp_modeset_reg, &val);
> + if (ret < 0)
> + return ret;
> +
> + val &= info->lp_modeset_mask;
> + val >>= ffs(info->lp_modeset_mask) - 1;
[Severity: High]
Should this read from info->lp_modeget_reg instead?
By reading from lp_modeset_reg, it seems this retrieves the requested mode
rather than the actual hardware state, leaving the lp_modeget fields unused.
[ ... ]
> +static const struct regulator_ops mt6392_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,
[Severity: Medium]
Is this missing the .of_map_mode callback?
The driver defines custom device tree mode constants (e.g.,
MT6392_BUCK_MODE_AUTO), but without .of_map_mode, the regulator framework
will ignore the regulator-initial-mode DT property and log a warning.
[ ... ]
> +static int mt6392_set_buck_vsel_reg(struct platform_device *pdev)
> +{
[ ... ]
> + if (regval & mt6392_regulators[i].vselctrl_mask) {
> + // Regulator in Normal mode
> + mt6392_regulators[i].desc.vsel_reg =
> + mt6392_regulators[i].vsel_normal_mode_reg;
> + mt6392_regulators[i].desc.vsel_mask =
> + mt6392_regulators[i].vsel_normal_mode_mask;
[Severity: High]
Can this cause a data race or state corruption?
mt6392_regulators is a shared global static array, and the driver modifies it
during probe based on the current hardware state.
Since the driver requests PROBE_PREFER_ASYNCHRONOUS later on:
> +static struct platform_driver mt6392_regulator_driver = {
> + .driver = {
> + .name = "mt6392-regulator",
> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> + },
Could probing multiple MT6392 instances concurrently overwrite the desc
fields for the other instances? Does the driver need to allocate per-device
copies of the regulator_desc?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615071836.362883-1-l.scorcia@gmail.com?part=8
^ permalink raw reply
* Re: [PATCH v7 5/9] mfd: mt6397: Add support for MT6392 PMIC
From: sashiko-bot @ 2026-06-15 7:38 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: dmitry.torokhov, robh, devicetree, conor+dt, linux-input
In-Reply-To: <20260615071836.362883-6-l.scorcia@gmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-After-Free of PM notifier on device unbind or probe failure
- [High] Use-After-Free of irq_domain in probe error path due to active IRQ thread
- [High] Concurrent hardware state writes in PM notifier
- [High] Lost interrupts due to late Write-1-to-Clear (W1C) in the threaded IRQ handler
--
commit cd7aa2c7d4f30c2e0b9a697283dae8066d30b344
Author: Fabien Parent <parent.f@gmail.com>
mfd: mt6397: Add support for MT6392 PMIC
This commit aligns the MT6397 PMIC driver to other MFD drivers by passing
an identifier through mt6397_of_match and adds support for the MT6392
PMIC variant along with its regulator, RTC, keys, and pinctrl devices.
> diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
> index ccd97d66d7f1c..f683e878543e1 100644
> --- a/drivers/mfd/mt6397-core.c
> +++ b/drivers/mfd/mt6397-core.c
[ ... ]
> @@ -327,30 +388,15 @@ static int mt6397_probe(struct platform_device *pdev)
> }
[Severity: High]
This is a pre-existing issue, but I noticed a potential use-after-free
with the PM notifier during probe failure or device unbind.
In mt6397_irq_init(), the pm_nb notifier is registered globally:
mt6397_irq_init() {
...
register_pm_notifier(&chip->pm_nb);
return 0;
}
However, there doesn't seem to be a corresponding unregister action if
devm_mfd_add_devices() fails in mt6397_probe(), or when the driver is
unbound (since mt6397_driver lacks a .remove callback). Because the chip
struct is devm-allocated, could this leave a dangling pointer in the
global pm_chain_head, resulting in a use-after-free during the next
suspend/resume cycle?
[Severity: High]
This isn't a bug introduced by this patch, but is there a risk of a
use-after-free involving the irq_domain in the probe error path?
In mt6397_probe(), if devm_mfd_add_devices() fails, the domain is
manually removed:
mt6397_probe() {
...
if (ret) {
irq_domain_remove(pmic->irq_domain);
dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
}
}
Since the threaded IRQ handler was requested earlier using
devm_request_threaded_irq(), it remains active until the probe function
returns and devres unwinds. If a pending hardware interrupt fires during
this window, would mt6397_irq_thread() execute and call irq_find_mapping()
on the already freed pmic->irq_domain?
> static const struct of_device_id mt6397_of_match[] = {
[ ... ]
> diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c
> index 5d2e5459f7444..80ea5b92d232f 100644
> --- a/drivers/mfd/mt6397-irq.c
> +++ b/drivers/mfd/mt6397-irq.c
[ ... ]
> @@ -203,6 +205,12 @@ int mt6397_irq_init(struct mt6397_chip *chip)
> chip->int_status[0] = MT6397_INT_STATUS0;
> chip->int_status[1] = MT6397_INT_STATUS1;
> break;
> + case MT6392_CHIP_ID:
> + chip->int_con[0] = MT6392_INT_CON0;
> + chip->int_con[1] = MT6392_INT_CON1;
> + chip->int_status[0] = MT6392_INT_STATUS0;
> + chip->int_status[1] = MT6392_INT_STATUS1;
> + break;
>
> default:
> dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
[Severity: High]
This isn't a bug introduced by this patch, but does the PM notifier
need to acquire the irqlock to prevent hardware state corruption?
In mt6397_irq_pm_notifier(), during PM_SUSPEND_PREPARE:
mt6397_irq_pm_notifier() {
...
case PM_SUSPEND_PREPARE:
regmap_write(chip->regmap,
chip->int_con[0], chip->wake_mask[0]);
}
This directly accesses chip->wake_mask and writes to the regmap without
acquiring chip->irqlock. Since PM notifiers run while userspace tasks
are still active, could a concurrent request_irq() or free_irq()
interleave, causing the PM notifier to read torn state or overwrite
hardware registers with stale values?
[Severity: High]
This is a pre-existing issue, but can this interrupt handling sequence
cause lost edge interrupts?
In mt6397_irq_handle_reg(), the driver reads the status, handles the
nested irqs, and then clears the status at the end:
mt6397_irq_handle_reg() {
...
for (i = 0; i < 16; i++) {
if (status & BIT(i)) {
irq = irq_find_mapping(mt6397->irq_domain, irqbase + i);
if (irq)
handle_nested_irq(irq);
}
}
regmap_write(mt6397->regmap, reg, status);
}
Because these are Write-1-to-Clear registers, does writing the status
back after handling the interrupts unintentionally clear any new edge
interrupts that might have arrived while handle_nested_irq() was executing?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615071836.362883-1-l.scorcia@gmail.com?part=5
^ permalink raw reply
* Re: [PATCH v7 7/9] pinctrl: mediatek: mt6397: Add MediaTek MT6392
From: sashiko-bot @ 2026-06-15 7:35 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: conor+dt, dmitry.torokhov, devicetree, linux-input, robh
In-Reply-To: <20260615071836.362883-8-l.scorcia@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing `.remove` callback in `mtk_pinctrl_driver` causes a Use-After-Free of devres-managed memory upon driver unbind because the GPIO chip is registered with an unmanaged API.
--
commit a353f51e9f14248ddf84f2093bfe6ddad0c83ce8
Author: Luca Leonardo Scorcia <l.scorcia@gmail.com>
pinctrl: mediatek: mt6397: Add MediaTek MT6392
This commit adds support for the MT6392 pinctrl device by introducing
its pin definitions and match data. It also updates the MT6397 driver
to retrieve and use this device data from the match table during probe.
> diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6397.c b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
> index 03d0f65d7bcc1..8ba02e70595ce 100644
> --- a/drivers/pinctrl/mediatek/pinctrl-mt6397.c
> +++ b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
[ ... ]
> @@ -40,13 +62,24 @@ static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
> static int mt6397_pinctrl_probe(struct platform_device *pdev)
> {
> struct mt6397_chip *mt6397;
> + const struct mtk_pinctrl_devdata *data;
> +
> + data = device_get_match_data(&pdev->dev);
> + if (!data)
> + return -ENOENT;
>
> mt6397 = dev_get_drvdata(pdev->dev.parent);
> - return mtk_pctrl_init(pdev, &mt6397_pinctrl_data, mt6397->regmap);
> + return mtk_pctrl_init(pdev, data, mt6397->regmap);
> }
[Severity: High]
This is a pre-existing issue, but by sharing the same initialization path,
the new MT6392 variant inherits a potential use-after-free on driver unbind.
Looking at mtk_pctrl_init() in pinctrl-mtk-common.c, it allocates pctl->chip
using devm_kzalloc() and registers it with the unmanaged gpiochip_add_data()
API:
mtk_pctrl_init() {
...
pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
...
ret = gpiochip_add_data(pctl->chip, pctl);
...
}
However, the mtk_pinctrl_driver struct does not have a .remove callback and
does not set suppress_bind_attrs = true.
If a user manually unbinds the driver via sysfs, devres will automatically
free pctl->chip, but since gpiochip_remove() is never called, the GPIO
framework retains pointers to the freed memory.
Would it make sense to fix this by switching to devm_gpiochip_add_data() in
mtk_pctrl_init(), or by adding suppress_bind_attrs = true to the driver
struct?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615071836.362883-1-l.scorcia@gmail.com?part=7
^ permalink raw reply
* Re: [PATCH v7 6/9] input: keyboard: mtk-pmic-keys: Add MT6392 support
From: sashiko-bot @ 2026-06-15 7:33 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-input, conor+dt, robh, devicetree, dmitry.torokhov
In-Reply-To: <20260615071836.362883-7-l.scorcia@gmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Incorrect reset mask applied for MT6357 home key due to typo (`MTK_PMIC_HOMEKEY_INDEX` instead of `MTK_PMIC_HOMEKEY_RST`).
- [High] Device Tree child nodes are mapped purely by order, ignoring their identity.
- [High] Array bounds overflow due to mismatched DT child node counting and iteration.
- [High] Unchecked return value of `of_match_device()` leads to NULL dereference.
--
commit 576d0be432dffd670f7bb30dc9498d55a10d5703
Author: Val Packett <val@packett.cool>
input: keyboard: mtk-pmic-keys: Add MT6392 support
Add support for the MT6392 PMIC to the keys driver.
> diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
> index c78d9f6d97c4f..8b4a89fce4fb1 100644
> --- a/drivers/input/keyboard/mtk-pmic-keys.c
> +++ b/drivers/input/keyboard/mtk-pmic-keys.c
[ ... ]
> @@ -301,6 +315,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
> {
> .compatible = "mediatek,mt6397-keys",
> .data = &mt6397_regs,
> + }, {
> + .compatible = "mediatek,mt6392-keys",
> + .data = &mt6392_regs,
> }, {
> .compatible = "mediatek,mt6323-keys",
> .data = &mt6323_regs,
[Severity: High]
This isn't a bug introduced by this patch, but the mt6357_regs array
erroneously uses the index constant MTK_PMIC_HOMEKEY_INDEX instead of
the correct bitmask MTK_PMIC_HOMEKEY_RST for the reset enable mask:
drivers/input/keyboard/mtk-pmic-keys.c:
.keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6357_TOPSTATUS,
0x8, MT6357_PSC_TOP_INT_CON0, 0xa,
MTK_PMIC_HOMEKEY_INDEX),
Could this cause incorrect bits to be modified in the MT6357_TOP_RST_MISC
register when configuring long-press reset behaviors, potentially corrupting
other hardware state?
[Severity: High]
This is a pre-existing issue, but Device Tree child nodes are mapped
purely by order in mtk_pmic_keys_probe():
drivers/input/keyboard/mtk-pmic-keys.c:mtk_pmic_keys_probe() {
...
for_each_child_of_node_scoped(node, child) {
keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index];
keys->keys[index].irq =
platform_get_irq_byname(pdev, irqnames[index]);
...
}
Since Device Tree does not guarantee child node ordering, if a device tree
lists the home key before the power key (or omits the power key entirely),
wouldn't the driver blindly map the first child node's properties to the
powerkey hardware resources?
[Severity: High]
This is a pre-existing issue, but is there an array bounds overflow due to
mismatched DT child node counting and iteration in mtk_pmic_keys_probe()?
drivers/input/keyboard/mtk-pmic-keys.c:mtk_pmic_keys_probe() {
...
keycount = of_get_available_child_count(node);
if (keycount > MTK_PMIC_MAX_KEY_COUNT ||
keycount > ARRAY_SIZE(irqnames)) {
...
for_each_child_of_node_scoped(node, child) {
...
}
The probe function uses of_get_available_child_count() for the bounds check
but iterates over all nodes including disabled ones. If a DT defines more
than two child nodes but leaves enough disabled, could the subsequent loop
increment the index beyond the array bounds?
[Severity: High]
This isn't a bug introduced by this patch, but the return value of
of_match_device() is unchecked in mtk_pmic_keys_probe():
drivers/input/keyboard/mtk-pmic-keys.c:mtk_pmic_keys_probe() {
...
const struct of_device_id *of_id =
of_match_device(of_mtk_pmic_keys_match_tbl, &pdev->dev);
...
mtk_pmic_regs = of_id->data;
...
}
If the device is instantiated without a device tree node, won't
of_match_device() return NULL and result in a kernel panic on probe?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615071836.362883-1-l.scorcia@gmail.com?part=6
^ permalink raw reply
* Re: [PATCH v7 3/9] regulator: dt-bindings: Add MediaTek MT6392 PMIC
From: sashiko-bot @ 2026-06-15 7:30 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: dmitry.torokhov, robh, devicetree, conor+dt, linux-input
In-Reply-To: <20260615071836.362883-4-l.scorcia@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Incomplete schema constraints for `regulator-initial-mode` and `regulator-allowed-modes`.
- [Low] The Device Tree example includes an unrelated header and fails to demonstrate new binding properties.
--
commit 7a57eb124bc9a8ab53b73fb4508d2222b254ee23
Author: Luca Leonardo Scorcia <l.scorcia@gmail.com>
regulator: dt-bindings: Add MediaTek MT6392 PMIC
This commit adds device tree bindings for the regulators found in the
MediaTek MT6392 PMIC. It provides schemas for three buck converters and
several LDOs, including constraints for allowed mode settings.
> diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> new file mode 100644
> index 0000000000000..197041df4ba1a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
[ ... ]
> +patternProperties:
> + "^v(core|proc|sys)$":
> + description: Buck regulators
> + type: object
> + $ref: regulator.yaml#
> + properties:
> + regulator-allowed-modes:
> + description: |
> + BUCK regulators can set regulator-initial-mode and regulator-allowed-modes to
> + values specified in dt-bindings/regulator/mediatek,mt6392-regulator.h
> + items:
> + enum: [0, 1]
[Severity: Medium]
The description here mentions both regulator-initial-mode and
regulator-allowed-modes, but only regulator-allowed-modes is constrained.
Since regulator-initial-mode is not explicitly defined in these properties,
does it fall back to the unconstrained uint32 definition from regulator.yaml#?
Should regulator-initial-mode be added here to restrict it to [0, 1] as well?
> + unevaluatedProperties: false
[ ... ]
> + "^v(cama|dig18)$":
> + description: LDOs with fixed output without mode setting
> + type: object
> + $ref: regulator.yaml#
> + unevaluatedProperties: false
[Severity: Medium]
The description states these LDOs are "without mode setting", but the schema
does not explicitly forbid the mode properties. Because of the reference to
regulator.yaml#, doesn't this implicitly allow both regulator-initial-mode and
regulator-allowed-modes to pass validation?
> +
> + "^v(aud22|camaf|camd|cn35|efuse|emc3v3|gp1|gp2|m|mc|mch)$":
> + description: LDOs with adjustable output
> + type: object
> + $ref: regulator.yaml#
> + properties:
> + regulator-allowed-modes: false
[Severity: Medium]
This explicitly forbids regulator-allowed-modes. Should regulator-initial-mode
also be set to false here to fully prevent mode settings on these adjustable
LDOs?
> + unevaluatedProperties: false
> +
> +required:
> + - compatible
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
[Severity: Low]
Is the arm-gic.h header needed here? There do not seem to be any interrupt
definitions in the example block.
Also, would it make sense to include the newly added
dt-bindings/regulator/mediatek,mt6392-regulator.h header instead, and add at
least one example usage of regulator-initial-mode or regulator-allowed-modes?
This would ensure the new properties and custom constraints are actively
exercised by the schema validator.
> +
> + regulators {
> + compatible = "mediatek,mt6392-regulator";
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615071836.362883-1-l.scorcia@gmail.com?part=3
^ permalink raw reply
* [PATCH v7 9/9] arm64: dts: mediatek: Add MediaTek MT6392 PMIC dtsi
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Val Packett, Luca Leonardo Scorcia, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
Macpaul Lin, Lee Jones, Matthias Brugger,
AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
Linus Walleij, Louis-Alexis Eyraud, Julien Massot, Fabien Parent,
Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
From: Val Packett <val@packett.cool>
Add the dts to be included by all boards using the MT6392 PMIC,
providing support for regulator, keys, pinctrl and RTC.
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
arch/arm64/boot/dts/mediatek/mt6392.dtsi | 75 ++++++++++++++++++++++++
1 file changed, 75 insertions(+)
create mode 100644 arch/arm64/boot/dts/mediatek/mt6392.dtsi
diff --git a/arch/arm64/boot/dts/mediatek/mt6392.dtsi b/arch/arm64/boot/dts/mediatek/mt6392.dtsi
new file mode 100644
index 000000000000..81f15d76a05a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt6392.dtsi
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Copyright (c) 2024 Val Packett <val@packett.cool>
+ * Copyright (c) 2026 Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ */
+
+#include <dt-bindings/input/input.h>
+
+&pwrap {
+ pmic: pmic {
+ compatible = "mediatek,mt6392", "mediatek,mt6323";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ mt6392keys: keys {
+ compatible = "mediatek,mt6392-keys";
+
+ key-power {
+ linux,keycodes = <KEY_POWER>;
+ wakeup-source;
+ };
+
+ key-home {
+ linux,keycodes = <KEY_HOME>;
+ wakeup-source;
+ };
+ };
+
+ mt6392pio: pinctrl {
+ compatible = "mediatek,mt6392-pinctrl";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ mt6392rtc: rtc {
+ compatible = "mediatek,mt6392-rtc", "mediatek,mt6323-rtc";
+ };
+
+ mt6392regulators: regulators {
+ compatible = "mediatek,mt6392-regulator";
+
+ /* Fixed supply defined in the data sheet */
+ avddldo-supply = <&mt6392_vsys_reg>;
+
+ mt6392_vcore_reg: vcore { };
+ mt6392_vproc_reg: vproc { };
+ mt6392_vsys_reg: vsys { };
+ mt6392_vaud28_reg: vaud28 { };
+ mt6392_vxo22_reg: vxo22 { };
+ mt6392_vaud22_reg: vaud22 { };
+ mt6392_vadc18_reg: vadc18 { };
+ mt6392_vcama_reg: vcama { };
+ mt6392_vcn35_reg: vcn35 { };
+ mt6392_vio28_reg: vio28 { };
+ mt6392_vusb_reg: vusb { };
+ mt6392_vmc_reg: vmc { };
+ mt6392_vmch_reg: vmch { };
+ mt6392_vemc3v3_reg: vemc3v3 { };
+ mt6392_vcamaf_reg: vcamaf { };
+ mt6392_vgp1_reg: vgp1 { };
+ mt6392_vgp2_reg: vgp2 { };
+ mt6392_vefuse_reg: vefuse { };
+ mt6392_vm25_reg: vm25 { };
+ mt6392_vdig18_reg: vdig18 { };
+ mt6392_vm_reg: vm { };
+ mt6392_vio18_reg: vio18 { };
+ mt6392_vcn18_reg: vcn18 { };
+ mt6392_vcamd_reg: vcamd { };
+ mt6392_vcamio_reg: vcamio { };
+ mt6392_vrtc_reg: vrtc { };
+ };
+ };
+};
--
2.43.0
^ permalink raw reply related
* [PATCH v7 8/9] regulator: Add MediaTek MT6392 regulator
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Fabien Parent, Val Packett, Luca Leonardo Scorcia,
Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
Linus Walleij, Louis-Alexis Eyraud, Julien Massot,
Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
From: Fabien Parent <parent.f@gmail.com>
The MT6392 is a regulator found on boards based on the MediaTek
MT8167, MT8516, and probably other SoCs. It is a so called PMIC and
connects as a slave to a SoC using SPI, wrapped inside PWRAP.
Signed-off-by: Fabien Parent <parent.f@gmail.com>
Co-developed-by: Val Packett <val@packett.cool>
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
drivers/regulator/Kconfig | 9 +
drivers/regulator/Makefile | 1 +
drivers/regulator/mt6392-regulator.c | 756 +++++++++++++++++++++
include/linux/regulator/mt6392-regulator.h | 42 ++
4 files changed, 808 insertions(+)
create mode 100644 drivers/regulator/mt6392-regulator.c
create mode 100644 include/linux/regulator/mt6392-regulator.h
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a54a549196fe..ae375b9e6391 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1001,6 +1001,15 @@ config REGULATOR_MT6380
This driver supports the control of different power rails of device
through regulator interface.
+config REGULATOR_MT6392
+ tristate "MediaTek MT6392 PMIC"
+ depends on MFD_MT6397
+ help
+ Say y here to select this option to enable the power regulator of
+ MediaTek MT6392 PMIC.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_MT6397
tristate "MediaTek MT6397 PMIC"
depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 134eee274dbf..a8e795a1eda1 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o
obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
+obj-$(CONFIG_REGULATOR_MT6392) += mt6392-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
diff --git a/drivers/regulator/mt6392-regulator.c b/drivers/regulator/mt6392-regulator.c
new file mode 100644
index 000000000000..1f91aac3917a
--- /dev/null
+++ b/drivers/regulator/mt6392-regulator.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2020 BayLibre, SAS.
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ * Author: Fabien Parent <fparent@baylibre.com>
+ * Author: Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ *
+ * The data sheet for MT6392 regulators is spotty to say the least,
+ * many important registers/fields are missing and the ones that aren't
+ * lack crucial information. Some useful details have been retrieved from
+ * Android sources.
+ * The driver code is mostly based on the MT6397 one.
+ */
+
+#include <linux/module.h>
+#include <linux/linear_range.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6392/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6392-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+/*
+ * Buck mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+#define MT6392_BUCK_MODE_AUTO 0
+#define MT6392_BUCK_MODE_FORCE_PWM 1
+
+/*
+ * LDO mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+#define MT6392_LDO_MODE_NORMAL 0
+#define MT6392_LDO_MODE_LP 1
+
+/**
+ * MT6392 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi_status_reg: Register to query enable signal status of regulators
+ * @qi_status_mask: Mask to query enable signal status of regulators (RO)
+ * @vselctrl_reg: Vsel control mode selector register
+ * @vselctrl_mask: Vsel control mode selector mask (RO)
+ * @vsel_reg_mode_reg: Vsel register when Vsel control mode selector = 0 (Register mode)
+ * @vsel_reg_mode_mask: Vsel register mask in Register mode (RW)
+ * @vsel_normal_mode_reg: Vsel register when Vsel control mode selector = 1 (Normal mode)
+ * @vsel_normal_mode_mask: Vsel register mask in Register mode (RW)
+ * @pwm_modeset_reg: Register to control buck mode (Auto/Force PWM)
+ * @pwm_modeset_mask: Mask to control buck mode (RW)
+ * @lp_modeget_reg: Register to get LDO low-power mode
+ * @lp_modeget_mask: Mask to get LDO low-power mode (RO)
+ * @lp_modeset_reg: Register to control LDO low-power mode
+ * @lp_modeset_mask: Mask to control LDO low-power mode (WO)
+ */
+struct mt6392_regulator_info {
+ struct regulator_desc desc;
+ u32 qi_status_reg;
+ u32 qi_status_mask;
+ u32 vselctrl_reg;
+ u32 vselctrl_mask;
+ u32 vsel_reg_mode_reg;
+ u32 vsel_reg_mode_mask;
+ u32 vsel_normal_mode_reg;
+ u32 vsel_normal_mode_mask;
+ u32 pwm_modeset_reg;
+ u32 pwm_modeset_mask;
+ u32 lp_modeget_reg;
+ u32 lp_modeget_mask;
+ u32 lp_modeset_reg;
+ u32 lp_modeset_mask;
+};
+
+#define MT6392_BUCK(match, vreg, supply, min, max, step, volt_ranges, \
+ _qi_status_reg, _qi_status_mask, _enable_reg, _enable_mask, \
+ _vselctrl_reg, _vselctrl_mask, \
+ _vsel_reg_mode_reg, _vsel_reg_mode_mask, \
+ _vsel_normal_mode_reg, _vsel_normal_mode_mask, \
+ _pwm_modeset_reg, _pwm_modeset_mask, _ramp_delay) \
+[MT6392_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6392_volt_range_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6392_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .linear_ranges = volt_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
+ .enable_reg = _enable_reg, \
+ .enable_mask = _enable_mask, \
+ .ramp_delay = _ramp_delay, \
+ }, \
+ .qi_status_reg = _qi_status_reg, \
+ .qi_status_mask = _qi_status_mask, \
+ .vselctrl_reg = _vselctrl_reg, \
+ .vselctrl_mask = _vselctrl_mask, \
+ .vsel_reg_mode_reg = _vsel_reg_mode_reg, \
+ .vsel_reg_mode_mask = _vsel_reg_mode_mask, \
+ .vsel_normal_mode_reg = _vsel_normal_mode_reg, \
+ .vsel_normal_mode_mask = _vsel_normal_mode_mask, \
+ .pwm_modeset_reg = _pwm_modeset_reg, \
+ .pwm_modeset_mask = _pwm_modeset_mask, \
+}
+
+#define MT6392_LDO(match, vreg, supply, ldo_volt_table, \
+ _qi_status_reg, _qi_status_mask, \
+ _enable_reg, _enable_mask, \
+ _vsel_reg, _vsel_mask, \
+ _lp_modeget_reg, _lp_modeget_mask, \
+ _lp_modeset_reg, _lp_modeset_mask, \
+ _enable_time) \
+[MT6392_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6392_volt_table_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6392_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(ldo_volt_table), \
+ .volt_table = ldo_volt_table, \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _vsel_mask, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = _enable_mask, \
+ .enable_time = _enable_time, \
+ }, \
+ .qi_status_reg = _qi_status_reg, \
+ .qi_status_mask = _qi_status_mask, \
+ .lp_modeget_reg = _lp_modeget_reg, \
+ .lp_modeget_mask = _lp_modeget_mask, \
+ .lp_modeset_reg = _lp_modeset_reg, \
+ .lp_modeset_mask = _lp_modeset_mask, \
+}
+
+#define MT6392_LDO_LINEAR(match, vreg, supply, min, max, step, \
+ volt_ranges, \
+ _qi_status_reg, _qi_status_mask, \
+ _enable_reg, _enable_mask, \
+ _vsel_reg, _vsel_mask, \
+ _lp_modeget_reg, _lp_modeget_mask, \
+ _lp_modeset_reg, _lp_modeset_mask, \
+ _enable_time) \
+[MT6392_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6392_volt_ldo_range_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6392_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .linear_ranges = volt_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
+ .vsel_reg = _vsel_reg, \
+ .vsel_mask = _vsel_mask, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = _enable_mask, \
+ .enable_time = _enable_time, \
+ }, \
+ .qi_status_reg = _qi_status_reg, \
+ .qi_status_mask = _qi_status_mask, \
+ .lp_modeget_reg = _lp_modeget_reg, \
+ .lp_modeget_mask = _lp_modeget_mask, \
+ .lp_modeset_reg = _lp_modeset_reg, \
+ .lp_modeset_mask = _lp_modeset_mask, \
+}
+
+#define MT6392_REG_FIXED(match, vreg, supply, volt, \
+ _qi_status_reg, _qi_status_mask, \
+ _enable_reg, _enable_mask, \
+ _lp_modeget_reg, _lp_modeget_mask, \
+ _lp_modeset_reg, _lp_modeset_mask, \
+ _enable_time) \
+[MT6392_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6392_volt_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6392_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = 1, \
+ .min_uV = volt, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = _enable_mask, \
+ .enable_time = _enable_time, \
+ }, \
+ .qi_status_reg = _qi_status_reg, \
+ .qi_status_mask = _qi_status_mask, \
+ .lp_modeget_reg = _lp_modeget_reg, \
+ .lp_modeget_mask = _lp_modeget_mask, \
+ .lp_modeset_reg = _lp_modeset_reg, \
+ .lp_modeset_mask = _lp_modeset_mask, \
+}
+
+#define MT6392_REG_FIXED_NO_MODE(match, vreg, supply, volt, \
+ _qi_status_reg, _qi_status_mask, \
+ _enable_reg, _enable_mask, _enable_time) \
+[MT6392_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6392_volt_fixed_no_mode_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6392_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = 1, \
+ .min_uV = volt, \
+ .enable_reg = _enable_reg, \
+ .enable_mask = _enable_mask, \
+ .enable_time = _enable_time, \
+ }, \
+ .qi_status_reg = _qi_status_reg, \
+ .qi_status_mask = _qi_status_mask, \
+}
+
+#define MT6392_REG(match, vreg, supply, volt) \
+[MT6392_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6392_volt_no_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6392_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = 1, \
+ .min_uV = volt, \
+ }, \
+}
+
+static const struct linear_range buck_volt_range1[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct linear_range buck_volt_range2[] = {
+ REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const u32 ldo_volt_table1[] = {
+ 1800000, 1900000, 2000000, 2200000,
+};
+
+static const struct linear_range ldo_volt_range2[] = {
+ REGULATOR_LINEAR_RANGE(3300000, 0, 3, 100000),
+};
+
+static const u32 ldo_volt_table3[] = {
+ 1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+ 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+ 1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+ 1240000, 1390000,
+};
+
+static const u32 ldo_volt_table7[] = {
+ 1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+ 1800000, 2000000,
+};
+
+static int mt6392_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ int ret, val = 0;
+ struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+ u32 reg_value;
+
+ if (!info->pwm_modeset_mask) {
+ dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n", info->desc.name);
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = MT6392_BUCK_MODE_FORCE_PWM;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = MT6392_BUCK_MODE_AUTO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val <<= ffs(info->pwm_modeset_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, info->pwm_modeset_reg,
+ info->pwm_modeset_mask, val);
+
+ if (regmap_read(rdev->regmap, info->pwm_modeset_reg, ®_value) < 0) {
+ dev_err(&rdev->dev, "Failed to read register value\n");
+ return -EIO;
+ }
+
+ dev_info(&rdev->dev, "%s: info->pwm_modeset_reg 0x%x = 0x%x\n",
+ info->desc.name, info->pwm_modeset_reg, reg_value);
+
+ return ret;
+}
+
+static unsigned int mt6392_buck_get_mode(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ unsigned int mode;
+ int ret;
+ struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (!info->pwm_modeset_mask) {
+ dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n", info->desc.name);
+ return -EINVAL;
+ }
+
+ ret = regmap_read(rdev->regmap, info->pwm_modeset_reg, &val);
+ if (ret < 0)
+ return ret;
+
+ val &= info->pwm_modeset_mask;
+ val >>= ffs(info->pwm_modeset_mask) - 1;
+
+ if (val & 0x1)
+ mode = REGULATOR_MODE_FAST;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+
+ return mode;
+}
+
+static int mt6392_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ int ret, val = 0;
+ struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (!info->lp_modeset_mask) {
+ dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+ info->desc.name);
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_STANDBY:
+ val = MT6392_LDO_MODE_LP;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = MT6392_LDO_MODE_NORMAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val <<= ffs(info->lp_modeset_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, info->lp_modeset_reg,
+ info->lp_modeset_mask, val);
+
+ return ret;
+}
+
+static unsigned int mt6392_ldo_get_mode(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ unsigned int mode;
+ int ret;
+ struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (!info->lp_modeset_mask) {
+ dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+ info->desc.name);
+ return -EINVAL;
+ }
+
+ ret = regmap_read(rdev->regmap, info->lp_modeset_reg, &val);
+ if (ret < 0)
+ return ret;
+
+ val &= info->lp_modeset_mask;
+ val >>= ffs(info->lp_modeset_mask) - 1;
+
+ if (val & 0x1)
+ mode = REGULATOR_MODE_STANDBY;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+
+ return mode;
+}
+
+static int mt6392_get_status(struct regulator_dev *rdev)
+{
+ int ret;
+ u32 regval;
+ struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+ ret = regmap_read(rdev->regmap, info->qi_status_reg, ®val);
+ if (ret != 0) {
+ dev_err(&rdev->dev, "Failed to read qi_status_reg: %d\n", ret);
+ return ret;
+ }
+
+ return (regval & info->qi_status_mask) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static const struct regulator_ops mt6392_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 = mt6392_get_status,
+ .set_mode = mt6392_buck_set_mode,
+ .get_mode = mt6392_buck_get_mode,
+};
+
+static const struct regulator_ops mt6392_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 = mt6392_get_status,
+ .set_mode = mt6392_ldo_set_mode,
+ .get_mode = mt6392_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6392_volt_ldo_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 = mt6392_get_status,
+ .set_mode = mt6392_ldo_set_mode,
+ .get_mode = mt6392_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6392_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 = mt6392_get_status,
+ .set_mode = mt6392_ldo_set_mode,
+ .get_mode = mt6392_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6392_volt_fixed_no_mode_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6392_get_status,
+};
+
+static const struct regulator_ops mt6392_volt_no_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+/* The array is indexed by id(MT6392_ID_XXX) */
+static struct mt6392_regulator_info mt6392_regulators[] = {
+ MT6392_BUCK("vproc", VPROC, "vproc", 700000, 1493750, 6250,
+ buck_volt_range1,
+ MT6392_VPROC_CON7, BIT(13), // Regulator status
+ MT6392_VPROC_CON7, BIT(0), // Regulator enable
+ MT6392_VPROC_CON5, BIT(0), // Vsel ctrl mode selector,not present in data sheet
+ MT6392_VPROC_CON9, GENMASK(6, 0), // Vsel when control mode = register (0)
+ MT6392_VPROC_CON10, GENMASK(6, 0), // Vsel when control mode = normal (1)
+ MT6392_VPROC_CON2, BIT(8), // Auto / Force PWM mode
+ 12500),
+ MT6392_BUCK("vsys", VSYS, "vsys", 1400000, 2987500, 12500,
+ buck_volt_range2,
+ MT6392_VSYS_CON7, BIT(13),
+ MT6392_VSYS_CON7, BIT(0),
+ MT6392_VSYS_CON5, BIT(0), // Not present in data sheet
+ MT6392_VSYS_CON9, GENMASK(6, 0),
+ MT6392_VSYS_CON10, GENMASK(6, 0),
+ MT6392_VSYS_CON2, BIT(8),
+ 25000),
+ MT6392_BUCK("vcore", VCORE, "vcore", 700000, 1493750, 6250,
+ buck_volt_range1,
+ MT6392_VCORE_CON7, BIT(13),
+ MT6392_VCORE_CON7, BIT(0),
+ MT6392_VCORE_CON5, BIT(0), // Not present in data sheet
+ MT6392_VCORE_CON9, GENMASK(6, 0),
+ MT6392_VCORE_CON10, GENMASK(6, 0),
+ MT6392_VCORE_CON2, BIT(8),
+ 12500),
+
+ MT6392_REG_FIXED("vxo22", VXO22, "ldo1", 2200000,
+ MT6392_ANALDO_CON1, BIT(15),
+ MT6392_ANALDO_CON1, BIT(10), // Not present in data sheet
+ MT6392_ANALDO_CON1, BIT(7),
+ MT6392_ANALDO_CON1, BIT(1), // Not present in data sheet
+ 110),
+ MT6392_LDO("vaud22", VAUD22, "ldo1", ldo_volt_table1,
+ MT6392_ANALDO_CON2, BIT(15),
+ MT6392_ANALDO_CON2, BIT(14), // Not present in data sheet
+ MT6392_ANALDO_CON8, GENMASK(6, 5), // Not present in data sheet
+ MT6392_ANALDO_CON2, BIT(7),
+ MT6392_ANALDO_CON2, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG_FIXED_NO_MODE("vcama", VCAMA, "ldo1", 2800000,
+ MT6392_ANALDO_CON4, BIT(15),
+ MT6392_ANALDO_CON4, BIT(15),
+ 264),
+ MT6392_REG_FIXED("vaud28", VAUD28, "ldo1", 2800000,
+ MT6392_ANALDO_CON23, BIT(15),
+ MT6392_ANALDO_CON23, BIT(14), // Not present in data sheet
+ MT6392_ANALDO_CON23, BIT(7),
+ MT6392_ANALDO_CON23, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG_FIXED("vadc18", VADC18, "ldo1", 1800000,
+ MT6392_ANALDO_CON25, BIT(15),
+ MT6392_ANALDO_CON25, BIT(14), // Not present in data sheet
+ MT6392_ANALDO_CON25, BIT(7),
+ MT6392_ANALDO_CON25, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO_LINEAR("vcn35", VCN35, "ldo2", 3300000, 3600000, 100000, ldo_volt_range2,
+ MT6392_ANALDO_CON17, BIT(15), // Not present in data sheet
+ MT6392_ANALDO_CON21, BIT(12), // Not present in data sheet
+ MT6392_ANALDO_CON16, GENMASK(4, 3),
+ MT6392_ANALDO_CON21, BIT(7),
+ MT6392_ANALDO_CON21, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG_FIXED("vio28", VIO28, "ldo2", 2800000,
+ MT6392_DIGLDO_CON0, BIT(15),
+ MT6392_DIGLDO_CON0, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON0, BIT(7),
+ MT6392_DIGLDO_CON0, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG_FIXED("vusb", VUSB, "ldo3", 3300000,
+ MT6392_DIGLDO_CON2, BIT(15),
+ MT6392_DIGLDO_CON2, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON2, BIT(7),
+ MT6392_DIGLDO_CON2, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vmc", VMC, "ldo2", ldo_volt_table3,
+ MT6392_DIGLDO_CON3, BIT(15),
+ MT6392_DIGLDO_CON3, BIT(12),
+ MT6392_DIGLDO_CON24, BIT(4),
+ MT6392_DIGLDO_CON3, BIT(7),
+ MT6392_DIGLDO_CON3, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vmch", VMCH, "ldo2", ldo_volt_table4,
+ MT6392_DIGLDO_CON5, BIT(15),
+ MT6392_DIGLDO_CON5, BIT(14),
+ MT6392_DIGLDO_CON26, BIT(7),
+ MT6392_DIGLDO_CON5, BIT(7),
+ MT6392_DIGLDO_CON5, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vemc3v3", VEMC3V3, "ldo3", ldo_volt_table4,
+ MT6392_DIGLDO_CON6, BIT(15),
+ MT6392_DIGLDO_CON6, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON27, BIT(7),
+ MT6392_DIGLDO_CON6, BIT(7),
+ MT6392_DIGLDO_CON6, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vgp1", VGP1, "ldo3", ldo_volt_table5,
+ MT6392_DIGLDO_CON7, BIT(15),
+ MT6392_DIGLDO_CON7, BIT(15),
+ MT6392_DIGLDO_CON28, GENMASK(7, 5),
+ MT6392_DIGLDO_CON7, BIT(7),
+ MT6392_DIGLDO_CON7, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vgp2", VGP2, "ldo3", ldo_volt_table5,
+ MT6392_DIGLDO_CON8, BIT(15),
+ MT6392_DIGLDO_CON8, BIT(15),
+ MT6392_DIGLDO_CON29, GENMASK(7, 5),
+ MT6392_DIGLDO_CON8, BIT(7),
+ MT6392_DIGLDO_CON8, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG_FIXED("vcn18", VCN18, "avddldo", 1800000,
+ MT6392_DIGLDO_CON11, BIT(15),
+ MT6392_DIGLDO_CON11, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON11, BIT(7),
+ MT6392_DIGLDO_CON11, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vcamaf", VCAMAF, "ldo3", ldo_volt_table5,
+ MT6392_DIGLDO_CON31, BIT(15),
+ MT6392_DIGLDO_CON31, BIT(15),
+ MT6392_DIGLDO_CON32, GENMASK(7, 5),
+ MT6392_DIGLDO_CON31, BIT(7),
+ MT6392_DIGLDO_CON31, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vm", VM, "avddldo", ldo_volt_table6,
+ MT6392_DIGLDO_CON47, BIT(15),
+ MT6392_DIGLDO_CON47, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON48, GENMASK(5, 4), // Not present in data sheet
+ MT6392_DIGLDO_CON47, BIT(7), // Not present in data sheet
+ MT6392_DIGLDO_CON47, BIT(1),
+ 264),
+ MT6392_REG_FIXED("vio18", VIO18, "avddldo", 1800000,
+ MT6392_DIGLDO_CON49, BIT(15),
+ MT6392_DIGLDO_CON49, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON49, BIT(7),
+ MT6392_DIGLDO_CON49, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vcamd", VCAMD, "avddldo", ldo_volt_table7,
+ MT6392_DIGLDO_CON51, BIT(15),
+ MT6392_DIGLDO_CON51, BIT(14),
+ MT6392_DIGLDO_CON52, GENMASK(6, 5),
+ MT6392_DIGLDO_CON51, BIT(7),
+ MT6392_DIGLDO_CON51, BIT(1),
+ 264),
+ MT6392_REG_FIXED("vcamio", VCAMIO, "avddldo", 1800000,
+ MT6392_DIGLDO_CON53, BIT(15),
+ MT6392_DIGLDO_CON53, BIT(14),
+ MT6392_DIGLDO_CON53, BIT(7),
+ MT6392_DIGLDO_CON53, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG_FIXED("vm25", VM25, "ldo3", 2500000,
+ MT6392_DIGLDO_CON55, BIT(15),
+ MT6392_DIGLDO_CON55, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON55, BIT(7),
+ MT6392_DIGLDO_CON55, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_LDO("vefuse", VEFUSE, "ldo2", ldo_volt_table8,
+ MT6392_DIGLDO_CON57, BIT(15),
+ MT6392_DIGLDO_CON57, BIT(14), // Not present in data sheet
+ MT6392_DIGLDO_CON58, BIT(5), // Not present in data sheet
+ MT6392_DIGLDO_CON57, BIT(7),
+ MT6392_DIGLDO_CON57, BIT(1), // Not present in data sheet
+ 264),
+ MT6392_REG("vdig18", VDIG18, "ldo2", 1800000), // Internal non changeable regulator
+ MT6392_REG_FIXED_NO_MODE("vrtc", VRTC, "ldo1", 2800000,
+ MT6392_DIGLDO_CON15, BIT(15),
+ MT6392_DIGLDO_CON15, BIT(8), // Not present in data sheet
+ 264)
+};
+
+// Buck regulators can be in Register mode or Normal mode.
+// Each mode uses a different register to set the desired voltage.
+static int mt6392_set_buck_vsel_reg(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6392 = dev_get_drvdata(pdev->dev.parent);
+ int i;
+ u32 regval;
+
+ for (i = 0; i < MT6392_MAX_REGULATOR; i++) {
+ if (mt6392_regulators[i].vselctrl_reg) {
+ // Read the vselctrl_reg register
+ if (regmap_read(mt6392->regmap,
+ mt6392_regulators[i].vselctrl_reg,
+ ®val) < 0) {
+ dev_err(&pdev->dev,
+ "Failed to read buck ctrl\n");
+ return -EIO;
+ }
+
+ // vselctrl_reg[vselctrl_mask] defines the mode
+ if (regval & mt6392_regulators[i].vselctrl_mask) {
+ // Regulator in Normal mode
+ mt6392_regulators[i].desc.vsel_reg =
+ mt6392_regulators[i].vsel_normal_mode_reg;
+ mt6392_regulators[i].desc.vsel_mask =
+ mt6392_regulators[i].vsel_normal_mode_mask;
+ } else {
+ // Regulator in Register mode
+ mt6392_regulators[i].desc.vsel_reg =
+ mt6392_regulators[i].vsel_reg_mode_reg;
+ mt6392_regulators[i].desc.vsel_mask =
+ mt6392_regulators[i].vsel_reg_mode_mask;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int mt6392_regulator_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6392 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = {};
+ struct regulator_dev *rdev;
+ int i;
+
+ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
+ // Initialize the bucks' vsel_reg and vsel_mask according to current HW state
+ if (mt6392_set_buck_vsel_reg(pdev))
+ return -EIO;
+
+ config.dev = mt6392->dev;
+ config.regmap = mt6392->regmap;
+ for (i = 0; i < MT6392_MAX_REGULATOR; i++) {
+ config.driver_data = &mt6392_regulators[i];
+
+ rdev = devm_regulator_register(&pdev->dev,
+ &mt6392_regulators[i].desc,
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s\n",
+ mt6392_regulators[i].desc.name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id mt6392_platform_ids[] = {
+ { .name = "mt6392-regulator" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6392_platform_ids);
+
+static struct platform_driver mt6392_regulator_driver = {
+ .driver = {
+ .name = "mt6392-regulator",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = mt6392_regulator_probe,
+ .id_table = mt6392_platform_ids,
+};
+
+module_platform_driver(mt6392_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6392 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6392-regulator.h b/include/linux/regulator/mt6392-regulator.h
new file mode 100644
index 000000000000..0eccd085b062
--- /dev/null
+++ b/include/linux/regulator/mt6392-regulator.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ */
+
+#ifndef __LINUX_REGULATOR_MT6392_H
+#define __LINUX_REGULATOR_MT6392_H
+
+enum {
+ MT6392_ID_VPROC = 0,
+ MT6392_ID_VSYS,
+ MT6392_ID_VCORE,
+ MT6392_ID_VXO22,
+ MT6392_ID_VAUD22,
+ MT6392_ID_VCAMA,
+ MT6392_ID_VAUD28,
+ MT6392_ID_VADC18,
+ MT6392_ID_VCN35,
+ MT6392_ID_VIO28,
+ MT6392_ID_VUSB = 10,
+ MT6392_ID_VMC,
+ MT6392_ID_VMCH,
+ MT6392_ID_VEMC3V3,
+ MT6392_ID_VGP1,
+ MT6392_ID_VGP2,
+ MT6392_ID_VCN18,
+ MT6392_ID_VCAMAF,
+ MT6392_ID_VM,
+ MT6392_ID_VIO18,
+ MT6392_ID_VCAMD,
+ MT6392_ID_VCAMIO,
+ MT6392_ID_VM25,
+ MT6392_ID_VEFUSE,
+ MT6392_ID_VDIG18,
+ MT6392_ID_VRTC,
+ MT6392_ID_RG_MAX,
+};
+
+#define MT6392_MAX_REGULATOR MT6392_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6392_H */
--
2.43.0
^ permalink raw reply related
* [PATCH v7 7/9] pinctrl: mediatek: mt6397: Add MediaTek MT6392
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Luca Leonardo Scorcia, AngeloGioacchino Del Regno,
Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
Liam Girdwood, Mark Brown, Linus Walleij, Louis-Alexis Eyraud,
Val Packett, Julien Massot, Fabien Parent, Akari Tsuyukusa,
Chen Zhong, linux-input, devicetree, linux-kernel, linux-pm,
linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
Add support for the MT6392 pinctrl device, which is very similar to
MT6397 with a handful of different property values and its own pins
definition.
Update the MT6397 driver to retrieve device data from the match table and
use it for driver init.
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/pinctrl/mediatek/pinctrl-mt6397.c | 37 ++++++++++-
drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h | 64 +++++++++++++++++++
2 files changed, 99 insertions(+), 2 deletions(-)
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6397.c b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
index 03d0f65d7bcc..8ba02e70595c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6397.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
@@ -12,10 +12,32 @@
#include <linux/mfd/mt6397/core.h>
#include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt6392.h"
#include "pinctrl-mtk-mt6397.h"
#define MT6397_PIN_REG_BASE 0xc000
+static const struct mtk_pinctrl_devdata mt6392_pinctrl_data = {
+ .pins = mtk_pins_mt6392,
+ .npins = ARRAY_SIZE(mtk_pins_mt6392),
+ .dir_offset = (MT6397_PIN_REG_BASE + 0x000),
+ .ies_offset = MTK_PINCTRL_NOT_SUPPORT,
+ .smt_offset = MTK_PINCTRL_NOT_SUPPORT,
+ .pullen_offset = (MT6397_PIN_REG_BASE + 0x020),
+ .pullsel_offset = (MT6397_PIN_REG_BASE + 0x040),
+ .dout_offset = (MT6397_PIN_REG_BASE + 0x080),
+ .din_offset = (MT6397_PIN_REG_BASE + 0x0a0),
+ .pinmux_offset = (MT6397_PIN_REG_BASE + 0x0c0),
+ .type1_start = 7,
+ .type1_end = 7,
+ .port_shf = 3,
+ .port_mask = 0x3,
+ .port_align = 2,
+ .mode_mask = 0xf,
+ .mode_per_reg = 5,
+ .mode_shf = 4,
+};
+
static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
.pins = mtk_pins_mt6397,
.npins = ARRAY_SIZE(mtk_pins_mt6397),
@@ -40,13 +62,24 @@ static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
static int mt6397_pinctrl_probe(struct platform_device *pdev)
{
struct mt6397_chip *mt6397;
+ const struct mtk_pinctrl_devdata *data;
+
+ data = device_get_match_data(&pdev->dev);
+ if (!data)
+ return -ENOENT;
mt6397 = dev_get_drvdata(pdev->dev.parent);
- return mtk_pctrl_init(pdev, &mt6397_pinctrl_data, mt6397->regmap);
+ return mtk_pctrl_init(pdev, data, mt6397->regmap);
}
static const struct of_device_id mt6397_pctrl_match[] = {
- { .compatible = "mediatek,mt6397-pinctrl", },
+ {
+ .compatible = "mediatek,mt6392-pinctrl",
+ .data = &mt6392_pinctrl_data
+ }, {
+ .compatible = "mediatek,mt6397-pinctrl",
+ .data = &mt6397_pinctrl_data
+ },
{ }
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h
new file mode 100644
index 000000000000..e7241af28fdb
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PINCTRL_MTK_MT6392_H
+#define __PINCTRL_MTK_MT6392_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt6392[] = {
+ MTK_PIN(PINCTRL_PIN(0, "INT"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "INT"),
+ MTK_FUNCTION(5, "TEST_CK2"),
+ MTK_FUNCTION(6, "TEST_IN1"),
+ MTK_FUNCTION(7, "TEST_OUT1")
+ ),
+ MTK_PIN(PINCTRL_PIN(1, "SRCLKEN"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "SRCLKEN"),
+ MTK_FUNCTION(5, "TEST_CK0"),
+ MTK_FUNCTION(6, "TEST_IN2"),
+ MTK_FUNCTION(7, "TEST_OUT2")
+ ),
+ MTK_PIN(PINCTRL_PIN(2, "RTC_32K1V8"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "RTC_32K1V8"),
+ MTK_FUNCTION(5, "TEST_CK1"),
+ MTK_FUNCTION(6, "TEST_IN3"),
+ MTK_FUNCTION(7, "TEST_OUT3")
+ ),
+ MTK_PIN(PINCTRL_PIN(3, "SPI_CLK"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "SPI_CLK")
+ ),
+ MTK_PIN(PINCTRL_PIN(4, "SPI_CSN"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "SPI_CSN")
+ ),
+ MTK_PIN(PINCTRL_PIN(5, "SPI_MOSI"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "SPI_MOSI")
+ ),
+ MTK_PIN(PINCTRL_PIN(6, "SPI_MISO"),
+ NULL, "mt6392",
+ MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "SPI_MISO"),
+ MTK_FUNCTION(6, "TEST_IN4"),
+ MTK_FUNCTION(7, "TEST_OUT4")
+ ),
+};
+
+#endif /* __PINCTRL_MTK_MT6392_H */
--
2.43.0
^ permalink raw reply related
* [PATCH v7 6/9] input: keyboard: mtk-pmic-keys: Add MT6392 support
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Val Packett, Luca Leonardo Scorcia, AngeloGioacchino Del Regno,
Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
Liam Girdwood, Mark Brown, Linus Walleij, Julien Massot,
Louis-Alexis Eyraud, Fabien Parent, Akari Tsuyukusa, Chen Zhong,
linux-input, devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
From: Val Packett <val@packett.cool>
Add support for the MT6392 PMIC to the keys driver.
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/keyboard/mtk-pmic-keys.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index c78d9f6d97c4..8b4a89fce4fb 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -13,6 +13,7 @@
#include <linux/mfd/mt6357/registers.h>
#include <linux/mfd/mt6358/registers.h>
#include <linux/mfd/mt6359/registers.h>
+#include <linux/mfd/mt6392/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6397/registers.h>
#include <linux/module.h>
@@ -69,6 +70,19 @@ static const struct mtk_pmic_regs mt6397_regs = {
.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
};
+static const struct mtk_pmic_regs mt6392_regs = {
+ .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6392_CHRSTATUS, 0x2,
+ MT6392_INT_MISC_CON, 0x10,
+ MTK_PMIC_PWRKEY_RST),
+ .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6392_CHRSTATUS, 0x4,
+ MT6392_INT_MISC_CON, 0x8,
+ MTK_PMIC_HOMEKEY_RST),
+ .pmic_rst_reg = MT6392_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+};
+
static const struct mtk_pmic_regs mt6323_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS,
@@ -301,6 +315,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
{
.compatible = "mediatek,mt6397-keys",
.data = &mt6397_regs,
+ }, {
+ .compatible = "mediatek,mt6392-keys",
+ .data = &mt6392_regs,
}, {
.compatible = "mediatek,mt6323-keys",
.data = &mt6323_regs,
--
2.43.0
^ permalink raw reply related
* [PATCH v7 5/9] mfd: mt6397: Add support for MT6392 PMIC
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Fabien Parent, Val Packett, Luca Leonardo Scorcia,
AngeloGioacchino Del Regno, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
Macpaul Lin, Lee Jones, Matthias Brugger, Liam Girdwood,
Mark Brown, Linus Walleij, Louis-Alexis Eyraud, Julien Massot,
Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
From: Fabien Parent <parent.f@gmail.com>
Align the MT6397 PMIC driver to other MFD drivers by passing only an
identifier through mt6397_of_match[*].data and add support for the MT6392
PMIC and its regulator, RTC, keys and pinctrl devices.
The keys device manages two buttons named PWRKEY and FCHR_ENB, the latter
is identified as "Force charging disable" in the data sheet but it also
says "Merge with HOMEKEY", so call it "Home" for consistency.
Signed-off-by: Fabien Parent <parent.f@gmail.com>
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/mfd/mt6397-core.c | 98 ++++--
drivers/mfd/mt6397-irq.c | 8 +
include/linux/mfd/mt6392/core.h | 43 +++
include/linux/mfd/mt6392/registers.h | 488 +++++++++++++++++++++++++++
include/linux/mfd/mt6397/core.h | 1 +
5 files changed, 612 insertions(+), 26 deletions(-)
create mode 100644 include/linux/mfd/mt6392/core.h
create mode 100644 include/linux/mfd/mt6392/registers.h
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index ccd97d66d7f1..f683e878543e 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -18,6 +18,7 @@
#include <linux/mfd/mt6357/core.h>
#include <linux/mfd/mt6358/core.h>
#include <linux/mfd/mt6359/core.h>
+#include <linux/mfd/mt6392/core.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6323/registers.h>
#include <linux/mfd/mt6328/registers.h>
@@ -25,6 +26,7 @@
#include <linux/mfd/mt6357/registers.h>
#include <linux/mfd/mt6358/registers.h>
#include <linux/mfd/mt6359/registers.h>
+#include <linux/mfd/mt6392/registers.h>
#include <linux/mfd/mt6397/registers.h>
#define MT6323_RTC_BASE 0x8000
@@ -39,6 +41,9 @@
#define MT6358_RTC_BASE 0x0588
#define MT6358_RTC_SIZE 0x3c
+#define MT6392_RTC_BASE 0x8000
+#define MT6392_RTC_SIZE 0x3e
+
#define MT6397_RTC_BASE 0xe000
#define MT6397_RTC_SIZE 0x3e
@@ -65,6 +70,11 @@ static const struct resource mt6358_rtc_resources[] = {
DEFINE_RES_IRQ(MT6358_IRQ_RTC),
};
+static const struct resource mt6392_rtc_resources[] = {
+ DEFINE_RES_MEM(MT6392_RTC_BASE, MT6392_RTC_SIZE),
+ DEFINE_RES_IRQ(MT6392_IRQ_RTC),
+};
+
static const struct resource mt6397_rtc_resources[] = {
DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
DEFINE_RES_IRQ(MT6397_IRQ_RTC),
@@ -114,6 +124,11 @@ static const struct resource mt6331_keys_resources[] = {
DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_HOMEKEY, "homekey"),
};
+static const struct resource mt6392_keys_resources[] = {
+ DEFINE_RES_IRQ_NAMED(MT6392_IRQ_PWRKEY, "powerkey"),
+ DEFINE_RES_IRQ_NAMED(MT6392_IRQ_FCHRKEY, "homekey"),
+};
+
static const struct resource mt6397_keys_resources[] = {
DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"),
DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"),
@@ -193,6 +208,16 @@ static const struct mfd_cell mt6359_devs[] = {
"mediatek,mt6359-accdet"),
};
+static const struct mfd_cell mt6392_devs[] = {
+ MFD_CELL_OF("mt6392-keys", mt6392_keys_resources, NULL, 0, 0,
+ "mediatek,mt6392-keys"),
+ MFD_CELL_OF("mt6392-pinctrl", NULL, NULL, 0, 0,
+ "mediatek,mt6392-pinctrl"),
+ MFD_CELL_NAME("mt6392-regulator"),
+ MFD_CELL_OF("mt6392-rtc", mt6392_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6392-rtc"),
+};
+
static const struct mfd_cell mt6397_devs[] = {
MFD_CELL_OF("mt6397-rtc", mt6397_rtc_resources, NULL, 0, 0,
"mediatek,mt6397-rtc"),
@@ -264,6 +289,14 @@ static const struct chip_data mt6359_core = {
.irq_init = mt6358_irq_init,
};
+static const struct chip_data mt6392_core = {
+ .cid_addr = MT6392_CID,
+ .cid_shift = 0,
+ .cells = mt6392_devs,
+ .cell_size = ARRAY_SIZE(mt6392_devs),
+ .irq_init = mt6397_irq_init,
+};
+
static const struct chip_data mt6397_core = {
.cid_addr = MT6397_CID,
.cid_shift = 0,
@@ -278,6 +311,7 @@ static int mt6397_probe(struct platform_device *pdev)
unsigned int id = 0;
struct mt6397_chip *pmic;
const struct chip_data *pmic_core;
+ int chip_variant;
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
@@ -293,9 +327,36 @@ static int mt6397_probe(struct platform_device *pdev)
if (!pmic->regmap)
return -ENODEV;
- pmic_core = of_device_get_match_data(&pdev->dev);
- if (!pmic_core)
+ chip_variant = (unsigned int)(uintptr_t)device_get_match_data(&pdev->dev);
+ switch (chip_variant) {
+ case MT6323_CHIP_ID:
+ pmic_core = &mt6323_core;
+ break;
+ case MT6328_CHIP_ID:
+ pmic_core = &mt6328_core;
+ break;
+ case MT6331_CHIP_ID:
+ pmic_core = &mt6331_mt6332_core;
+ break;
+ case MT6357_CHIP_ID:
+ pmic_core = &mt6357_core;
+ break;
+ case MT6358_CHIP_ID:
+ pmic_core = &mt6358_core;
+ break;
+ case MT6359_CHIP_ID:
+ pmic_core = &mt6359_core;
+ break;
+ case MT6392_CHIP_ID:
+ pmic_core = &mt6392_core;
+ break;
+ case MT6397_CHIP_ID:
+ pmic_core = &mt6397_core;
+ break;
+ default:
+ dev_err(&pdev->dev, "Device not supported\n");
return -ENODEV;
+ }
ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id);
if (ret) {
@@ -327,30 +388,15 @@ static int mt6397_probe(struct platform_device *pdev)
}
static const struct of_device_id mt6397_of_match[] = {
- {
- .compatible = "mediatek,mt6323",
- .data = &mt6323_core,
- }, {
- .compatible = "mediatek,mt6328",
- .data = &mt6328_core,
- }, {
- .compatible = "mediatek,mt6331",
- .data = &mt6331_mt6332_core,
- }, {
- .compatible = "mediatek,mt6357",
- .data = &mt6357_core,
- }, {
- .compatible = "mediatek,mt6358",
- .data = &mt6358_core,
- }, {
- .compatible = "mediatek,mt6359",
- .data = &mt6359_core,
- }, {
- .compatible = "mediatek,mt6397",
- .data = &mt6397_core,
- }, {
- /* sentinel */
- }
+ { .compatible = "mediatek,mt6323", .data = (void *)MT6323_CHIP_ID, },
+ { .compatible = "mediatek,mt6328", .data = (void *)MT6328_CHIP_ID, },
+ { .compatible = "mediatek,mt6331", .data = (void *)MT6331_CHIP_ID, },
+ { .compatible = "mediatek,mt6357", .data = (void *)MT6357_CHIP_ID, },
+ { .compatible = "mediatek,mt6358", .data = (void *)MT6358_CHIP_ID, },
+ { .compatible = "mediatek,mt6359", .data = (void *)MT6359_CHIP_ID, },
+ { .compatible = "mediatek,mt6392", .data = (void *)MT6392_CHIP_ID, },
+ { .compatible = "mediatek,mt6397", .data = (void *)MT6397_CHIP_ID, },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mt6397_of_match);
diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c
index 5d2e5459f744..80ea5b92d232 100644
--- a/drivers/mfd/mt6397-irq.c
+++ b/drivers/mfd/mt6397-irq.c
@@ -15,6 +15,8 @@
#include <linux/mfd/mt6328/registers.h>
#include <linux/mfd/mt6331/core.h>
#include <linux/mfd/mt6331/registers.h>
+#include <linux/mfd/mt6392/core.h>
+#include <linux/mfd/mt6392/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6397/registers.h>
@@ -203,6 +205,12 @@ int mt6397_irq_init(struct mt6397_chip *chip)
chip->int_status[0] = MT6397_INT_STATUS0;
chip->int_status[1] = MT6397_INT_STATUS1;
break;
+ case MT6392_CHIP_ID:
+ chip->int_con[0] = MT6392_INT_CON0;
+ chip->int_con[1] = MT6392_INT_CON1;
+ chip->int_status[0] = MT6392_INT_STATUS0;
+ chip->int_status[1] = MT6392_INT_STATUS1;
+ break;
default:
dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
diff --git a/include/linux/mfd/mt6392/core.h b/include/linux/mfd/mt6392/core.h
new file mode 100644
index 000000000000..8777b3abf929
--- /dev/null
+++ b/include/linux/mfd/mt6392/core.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2026 Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ */
+
+#ifndef __MFD_MT6392_CORE_H__
+#define __MFD_MT6392_CORE_H__
+
+enum mt6392_irq_numbers {
+ MT6392_IRQ_SPKL_AB = 0,
+ MT6392_IRQ_SPKL,
+ MT6392_IRQ_BAT_L,
+ MT6392_IRQ_BAT_H,
+ MT6392_IRQ_WATCHDOG,
+ MT6392_IRQ_PWRKEY,
+ MT6392_IRQ_THR_L,
+ MT6392_IRQ_THR_H,
+ MT6392_IRQ_VBATON_UNDET,
+ MT6392_IRQ_BVALID_DET,
+ MT6392_IRQ_CHRDET,
+ MT6392_IRQ_OV,
+ MT6392_IRQ_LDO = 16,
+ MT6392_IRQ_FCHRKEY,
+ MT6392_IRQ_RELEASE_PWRKEY,
+ MT6392_IRQ_RELEASE_FCHRKEY,
+ MT6392_IRQ_RTC,
+ MT6392_IRQ_VPROC,
+ MT6392_IRQ_VSYS,
+ MT6392_IRQ_VCORE,
+ MT6392_IRQ_TYPE_C_CC,
+ MT6392_IRQ_TYPEC_H_MAX,
+ MT6392_IRQ_TYPEC_H_MIN,
+ MT6392_IRQ_TYPEC_L_MAX,
+ MT6392_IRQ_TYPEC_L_MIN,
+ MT6392_IRQ_THR_MAX,
+ MT6392_IRQ_THR_MIN,
+ MT6392_IRQ_NAG_C_DLTV,
+ MT6392_IRQ_NR,
+};
+
+#endif /* __MFD_MT6392_CORE_H__ */
diff --git a/include/linux/mfd/mt6392/registers.h b/include/linux/mfd/mt6392/registers.h
new file mode 100644
index 000000000000..68fe9af448f5
--- /dev/null
+++ b/include/linux/mfd/mt6392/registers.h
@@ -0,0 +1,488 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2026 Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ */
+
+#ifndef __MFD_MT6392_REGISTERS_H__
+#define __MFD_MT6392_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6392_CHR_CON0 0x0000
+#define MT6392_CHR_CON1 0x0002
+#define MT6392_CHR_CON2 0x0004
+#define MT6392_CHR_CON3 0x0006
+#define MT6392_CHR_CON4 0x0008
+#define MT6392_CHR_CON5 0x000A
+#define MT6392_CHR_CON6 0x000C
+#define MT6392_CHR_CON7 0x000E
+#define MT6392_CHR_CON8 0x0010
+#define MT6392_CHR_CON9 0x0012
+#define MT6392_CHR_CON10 0x0014
+#define MT6392_CHR_CON11 0x0016
+#define MT6392_CHR_CON12 0x0018
+#define MT6392_CHR_CON13 0x001A
+#define MT6392_CHR_CON14 0x001C
+#define MT6392_CHR_CON15 0x001E
+#define MT6392_CHR_CON16 0x0020
+#define MT6392_CHR_CON17 0x0022
+#define MT6392_CHR_CON18 0x0024
+#define MT6392_CHR_CON19 0x0026
+#define MT6392_CHR_CON20 0x0028
+#define MT6392_CHR_CON21 0x002A
+#define MT6392_CHR_CON22 0x002C
+#define MT6392_CHR_CON23 0x002E
+#define MT6392_CHR_CON24 0x0030
+#define MT6392_CHR_CON25 0x0032
+#define MT6392_CHR_CON26 0x0034
+#define MT6392_CHR_CON27 0x0036
+#define MT6392_CHR_CON28 0x0038
+#define MT6392_CHR_CON29 0x003A
+#define MT6392_STRUP_CON0 0x003C
+#define MT6392_STRUP_CON2 0x003E
+#define MT6392_STRUP_CON3 0x0040
+#define MT6392_STRUP_CON4 0x0042
+#define MT6392_STRUP_CON5 0x0044
+#define MT6392_STRUP_CON6 0x0046
+#define MT6392_STRUP_CON7 0x0048
+#define MT6392_STRUP_CON8 0x004A
+#define MT6392_STRUP_CON9 0x004C
+#define MT6392_STRUP_CON10 0x004E
+#define MT6392_STRUP_CON11 0x0050
+#define MT6392_SPK_CON0 0x0052
+#define MT6392_SPK_CON1 0x0054
+#define MT6392_SPK_CON2 0x0056
+#define MT6392_SPK_CON6 0x005E
+#define MT6392_SPK_CON7 0x0060
+#define MT6392_SPK_CON8 0x0062
+#define MT6392_SPK_CON9 0x0064
+#define MT6392_SPK_CON10 0x0066
+#define MT6392_SPK_CON11 0x0068
+#define MT6392_SPK_CON12 0x006A
+#define MT6392_STRUP_CON12 0x006E
+#define MT6392_STRUP_CON13 0x0070
+#define MT6392_STRUP_CON14 0x0072
+#define MT6392_STRUP_CON15 0x0074
+#define MT6392_STRUP_CON16 0x0076
+#define MT6392_STRUP_CON17 0x0078
+#define MT6392_STRUP_CON18 0x007A
+#define MT6392_STRUP_CON19 0x007C
+#define MT6392_STRUP_CON20 0x007E
+#define MT6392_CID 0x0100
+#define MT6392_TOP_CKPDN0 0x0102
+#define MT6392_TOP_CKPDN0_SET 0x0104
+#define MT6392_TOP_CKPDN0_CLR 0x0106
+#define MT6392_TOP_CKPDN1 0x0108
+#define MT6392_TOP_CKPDN1_SET 0x010A
+#define MT6392_TOP_CKPDN1_CLR 0x010C
+#define MT6392_TOP_CKPDN2 0x010E
+#define MT6392_TOP_CKPDN2_SET 0x0110
+#define MT6392_TOP_CKPDN2_CLR 0x0112
+#define MT6392_TOP_RST_CON 0x0114
+#define MT6392_TOP_RST_CON_SET 0x0116
+#define MT6392_TOP_RST_CON_CLR 0x0118
+#define MT6392_TOP_RST_MISC 0x011A
+#define MT6392_TOP_RST_MISC_SET 0x011C
+#define MT6392_TOP_RST_MISC_CLR 0x011E
+#define MT6392_TOP_CKCON0 0x0120
+#define MT6392_TOP_CKCON0_SET 0x0122
+#define MT6392_TOP_CKCON0_CLR 0x0124
+#define MT6392_TOP_CKCON1 0x0126
+#define MT6392_TOP_CKCON1_SET 0x0128
+#define MT6392_TOP_CKCON1_CLR 0x012A
+#define MT6392_TOP_CKTST0 0x012C
+#define MT6392_TOP_CKTST1 0x012E
+#define MT6392_TOP_CKTST2 0x0130
+#define MT6392_TEST_OUT 0x0132
+#define MT6392_TEST_CON0 0x0134
+#define MT6392_TEST_CON1 0x0136
+#define MT6392_EN_STATUS0 0x0138
+#define MT6392_EN_STATUS1 0x013A
+#define MT6392_OCSTATUS0 0x013C
+#define MT6392_OCSTATUS1 0x013E
+#define MT6392_PGSTATUS 0x0140
+#define MT6392_CHRSTATUS 0x0142
+#define MT6392_TDSEL_CON 0x0144
+#define MT6392_RDSEL_CON 0x0146
+#define MT6392_SMT_CON0 0x0148
+#define MT6392_SMT_CON1 0x014A
+#define MT6392_DRV_CON0 0x0152
+#define MT6392_DRV_CON1 0x0154
+#define MT6392_INT_CON0 0x0160
+#define MT6392_INT_CON0_SET 0x0162
+#define MT6392_INT_CON0_CLR 0x0164
+#define MT6392_INT_CON1 0x0166
+#define MT6392_INT_CON1_SET 0x0168
+#define MT6392_INT_CON1_CLR 0x016A
+#define MT6392_INT_MISC_CON 0x016C
+#define MT6392_INT_MISC_CON_SET 0x016E
+#define MT6392_INT_MISC_CON_CLR 0x0170
+#define MT6392_INT_STATUS0 0x0172
+#define MT6392_INT_STATUS1 0x0174
+#define MT6392_OC_GEAR_0 0x0176
+#define MT6392_OC_GEAR_1 0x0178
+#define MT6392_OC_GEAR_2 0x017A
+#define MT6392_OC_CTL_VPROC 0x017C
+#define MT6392_OC_CTL_VSYS 0x017E
+#define MT6392_OC_CTL_VCORE 0x0180
+#define MT6392_FQMTR_CON0 0x0182
+#define MT6392_FQMTR_CON1 0x0184
+#define MT6392_FQMTR_CON2 0x0186
+#define MT6392_RG_SPI_CON 0x0188
+#define MT6392_DEW_DIO_EN 0x018A
+#define MT6392_DEW_READ_TEST 0x018C
+#define MT6392_DEW_WRITE_TEST 0x018E
+#define MT6392_DEW_CRC_SWRST 0x0190
+#define MT6392_DEW_CRC_EN 0x0192
+#define MT6392_DEW_CRC_VAL 0x0194
+#define MT6392_DEW_DBG_MON_SEL 0x0196
+#define MT6392_DEW_CIPHER_KEY_SEL 0x0198
+#define MT6392_DEW_CIPHER_IV_SEL 0x019A
+#define MT6392_DEW_CIPHER_EN 0x019C
+#define MT6392_DEW_CIPHER_RDY 0x019E
+#define MT6392_DEW_CIPHER_MODE 0x01A0
+#define MT6392_DEW_CIPHER_SWRST 0x01A2
+#define MT6392_DEW_RDDMY_NO 0x01A4
+#define MT6392_DEW_RDATA_DLY_SEL 0x01A6
+#define MT6392_CLK_TRIM_CON0 0x01A8
+#define MT6392_BUCK_CON0 0x0200
+#define MT6392_BUCK_CON1 0x0202
+#define MT6392_BUCK_CON2 0x0204
+#define MT6392_BUCK_CON3 0x0206
+#define MT6392_BUCK_CON4 0x0208
+#define MT6392_BUCK_CON5 0x020A
+#define MT6392_VPROC_CON0 0x020C
+#define MT6392_VPROC_CON1 0x020E
+#define MT6392_VPROC_CON2 0x0210
+#define MT6392_VPROC_CON3 0x0212
+#define MT6392_VPROC_CON4 0x0214
+#define MT6392_VPROC_CON5 0x0216
+#define MT6392_VPROC_CON7 0x021A
+#define MT6392_VPROC_CON8 0x021C
+#define MT6392_VPROC_CON9 0x021E
+#define MT6392_VPROC_CON10 0x0220
+#define MT6392_VPROC_CON11 0x0222
+#define MT6392_VPROC_CON12 0x0224
+#define MT6392_VPROC_CON13 0x0226
+#define MT6392_VPROC_CON14 0x0228
+#define MT6392_VPROC_CON15 0x022A
+#define MT6392_VPROC_CON18 0x0230
+#define MT6392_VSYS_CON0 0x0232
+#define MT6392_VSYS_CON1 0x0234
+#define MT6392_VSYS_CON2 0x0236
+#define MT6392_VSYS_CON3 0x0238
+#define MT6392_VSYS_CON4 0x023A
+#define MT6392_VSYS_CON5 0x023C
+#define MT6392_VSYS_CON7 0x0240
+#define MT6392_VSYS_CON8 0x0242
+#define MT6392_VSYS_CON9 0x0244
+#define MT6392_VSYS_CON10 0x0246
+#define MT6392_VSYS_CON11 0x0248
+#define MT6392_VSYS_CON12 0x024A
+#define MT6392_VSYS_CON13 0x024C
+#define MT6392_VSYS_CON14 0x024E
+#define MT6392_VSYS_CON15 0x0250
+#define MT6392_VSYS_CON18 0x0256
+#define MT6392_BUCK_OC_CON0 0x0258
+#define MT6392_BUCK_OC_CON1 0x025A
+#define MT6392_BUCK_OC_CON2 0x025C
+#define MT6392_BUCK_OC_CON3 0x025E
+#define MT6392_BUCK_OC_CON4 0x0260
+#define MT6392_BUCK_OC_VPROC_CON0 0x0262
+#define MT6392_BUCK_OC_VCORE_CON0 0x0264
+#define MT6392_BUCK_OC_VSYS_CON0 0x0266
+#define MT6392_BUCK_ANA_MON_CON0 0x0268
+#define MT6392_BUCK_EFUSE_OC_CON0 0x026A
+#define MT6392_VCORE_CON0 0x0300
+#define MT6392_VCORE_CON1 0x0302
+#define MT6392_VCORE_CON2 0x0304
+#define MT6392_VCORE_CON3 0x0306
+#define MT6392_VCORE_CON4 0x0308
+#define MT6392_VCORE_CON5 0x030A
+#define MT6392_VCORE_CON7 0x030E
+#define MT6392_VCORE_CON8 0x0310
+#define MT6392_VCORE_CON9 0x0312
+#define MT6392_VCORE_CON10 0x0314
+#define MT6392_VCORE_CON11 0x0316
+#define MT6392_VCORE_CON12 0x0318
+#define MT6392_VCORE_CON13 0x031A
+#define MT6392_VCORE_CON14 0x031C
+#define MT6392_VCORE_CON15 0x031E
+#define MT6392_VCORE_CON18 0x0324
+#define MT6392_BUCK_K_CON0 0x032A
+#define MT6392_BUCK_K_CON1 0x032C
+#define MT6392_BUCK_K_CON2 0x032E
+#define MT6392_ANALDO_CON0 0x0400
+#define MT6392_ANALDO_CON1 0x0402
+#define MT6392_ANALDO_CON2 0x0404
+#define MT6392_ANALDO_CON3 0x0406
+#define MT6392_ANALDO_CON4 0x0408
+#define MT6392_ANALDO_CON6 0x040C
+#define MT6392_ANALDO_CON7 0x040E
+#define MT6392_ANALDO_CON8 0x0410
+#define MT6392_ANALDO_CON10 0x0412
+#define MT6392_ANALDO_CON15 0x0414
+#define MT6392_ANALDO_CON16 0x0416
+#define MT6392_ANALDO_CON17 0x0418
+#define MT6392_ANALDO_CON21 0x0420
+#define MT6392_ANALDO_CON22 0x0422
+#define MT6392_ANALDO_CON23 0x0424
+#define MT6392_ANALDO_CON24 0x0426
+#define MT6392_ANALDO_CON25 0x0428
+#define MT6392_ANALDO_CON26 0x042A
+#define MT6392_ANALDO_CON27 0x042C
+#define MT6392_ANALDO_CON28 0x042E
+#define MT6392_ANALDO_CON29 0x0430
+#define MT6392_DIGLDO_CON0 0x0500
+#define MT6392_DIGLDO_CON2 0x0502
+#define MT6392_DIGLDO_CON3 0x0504
+#define MT6392_DIGLDO_CON5 0x0506
+#define MT6392_DIGLDO_CON6 0x0508
+#define MT6392_DIGLDO_CON7 0x050A
+#define MT6392_DIGLDO_CON8 0x050C
+#define MT6392_DIGLDO_CON10 0x0510
+#define MT6392_DIGLDO_CON11 0x0512
+#define MT6392_DIGLDO_CON12 0x0514
+#define MT6392_DIGLDO_CON15 0x051A
+#define MT6392_DIGLDO_CON20 0x0524
+#define MT6392_DIGLDO_CON21 0x0526
+#define MT6392_DIGLDO_CON23 0x0528
+#define MT6392_DIGLDO_CON24 0x052A
+#define MT6392_DIGLDO_CON26 0x052C
+#define MT6392_DIGLDO_CON27 0x052E
+#define MT6392_DIGLDO_CON28 0x0530
+#define MT6392_DIGLDO_CON29 0x0532
+#define MT6392_DIGLDO_CON30 0x0534
+#define MT6392_DIGLDO_CON31 0x0536
+#define MT6392_DIGLDO_CON32 0x0538
+#define MT6392_DIGLDO_CON33 0x053A
+#define MT6392_DIGLDO_CON36 0x0540
+#define MT6392_DIGLDO_CON41 0x0546
+#define MT6392_DIGLDO_CON44 0x054C
+#define MT6392_DIGLDO_CON47 0x0552
+#define MT6392_DIGLDO_CON48 0x0554
+#define MT6392_DIGLDO_CON49 0x0556
+#define MT6392_DIGLDO_CON50 0x0558
+#define MT6392_DIGLDO_CON51 0x055A
+#define MT6392_DIGLDO_CON52 0x055C
+#define MT6392_DIGLDO_CON53 0x055E
+#define MT6392_DIGLDO_CON54 0x0560
+#define MT6392_DIGLDO_CON55 0x0562
+#define MT6392_DIGLDO_CON56 0x0564
+#define MT6392_DIGLDO_CON57 0x0566
+#define MT6392_DIGLDO_CON58 0x0568
+#define MT6392_DIGLDO_CON59 0x056A
+#define MT6392_DIGLDO_CON60 0x056C
+#define MT6392_DIGLDO_CON61 0x056E
+#define MT6392_DIGLDO_CON62 0x0570
+#define MT6392_DIGLDO_CON63 0x0572
+#define MT6392_EFUSE_CON0 0x0600
+#define MT6392_EFUSE_CON1 0x0602
+#define MT6392_EFUSE_CON2 0x0604
+#define MT6392_EFUSE_CON3 0x0606
+#define MT6392_EFUSE_CON4 0x0608
+#define MT6392_EFUSE_CON5 0x060A
+#define MT6392_EFUSE_CON6 0x060C
+#define MT6392_EFUSE_VAL_0_15 0x060E
+#define MT6392_EFUSE_VAL_16_31 0x0610
+#define MT6392_EFUSE_VAL_32_47 0x0612
+#define MT6392_EFUSE_VAL_48_63 0x0614
+#define MT6392_EFUSE_VAL_64_79 0x0616
+#define MT6392_EFUSE_VAL_80_95 0x0618
+#define MT6392_EFUSE_VAL_96_111 0x061A
+#define MT6392_EFUSE_VAL_112_127 0x061C
+#define MT6392_EFUSE_VAL_128_143 0x061E
+#define MT6392_EFUSE_VAL_144_159 0x0620
+#define MT6392_EFUSE_VAL_160_175 0x0622
+#define MT6392_EFUSE_VAL_176_191 0x0624
+#define MT6392_EFUSE_VAL_192_207 0x0626
+#define MT6392_EFUSE_VAL_208_223 0x0628
+#define MT6392_EFUSE_VAL_224_239 0x062A
+#define MT6392_EFUSE_VAL_240_255 0x062C
+#define MT6392_EFUSE_VAL_256_271 0x062E
+#define MT6392_EFUSE_VAL_272_287 0x0630
+#define MT6392_EFUSE_VAL_288_303 0x0632
+#define MT6392_EFUSE_VAL_304_319 0x0634
+#define MT6392_EFUSE_VAL_320_335 0x0636
+#define MT6392_EFUSE_VAL_336_351 0x0638
+#define MT6392_EFUSE_VAL_352_367 0x063A
+#define MT6392_EFUSE_VAL_368_383 0x063C
+#define MT6392_EFUSE_VAL_384_399 0x063E
+#define MT6392_EFUSE_VAL_400_415 0x0640
+#define MT6392_EFUSE_VAL_416_431 0x0642
+#define MT6392_RTC_MIX_CON0 0x0644
+#define MT6392_RTC_MIX_CON1 0x0646
+#define MT6392_EFUSE_VAL_432_447 0x0648
+#define MT6392_EFUSE_VAL_448_463 0x064A
+#define MT6392_EFUSE_VAL_464_479 0x064C
+#define MT6392_EFUSE_VAL_480_495 0x064E
+#define MT6392_EFUSE_VAL_496_511 0x0650
+#define MT6392_EFUSE_DOUT_0_15 0x0652
+#define MT6392_EFUSE_DOUT_16_31 0x0654
+#define MT6392_EFUSE_DOUT_32_47 0x0656
+#define MT6392_EFUSE_DOUT_48_63 0x0658
+#define MT6392_EFUSE_DOUT_64_79 0x065A
+#define MT6392_EFUSE_DOUT_80_95 0x065C
+#define MT6392_EFUSE_DOUT_96_111 0x065E
+#define MT6392_EFUSE_DOUT_112_127 0x0660
+#define MT6392_EFUSE_DOUT_128_143 0x0662
+#define MT6392_EFUSE_DOUT_144_159 0x0664
+#define MT6392_EFUSE_DOUT_160_175 0x0666
+#define MT6392_EFUSE_DOUT_176_191 0x0668
+#define MT6392_EFUSE_DOUT_192_207 0x066A
+#define MT6392_EFUSE_DOUT_208_223 0x066C
+#define MT6392_EFUSE_DOUT_224_239 0x066E
+#define MT6392_EFUSE_DOUT_240_255 0x0670
+#define MT6392_EFUSE_DOUT_256_271 0x0672
+#define MT6392_EFUSE_DOUT_272_287 0x0674
+#define MT6392_EFUSE_DOUT_288_303 0x0676
+#define MT6392_EFUSE_DOUT_304_319 0x0678
+#define MT6392_EFUSE_DOUT_320_335 0x067A
+#define MT6392_EFUSE_DOUT_336_351 0x067C
+#define MT6392_EFUSE_DOUT_352_367 0x067E
+#define MT6392_EFUSE_DOUT_368_383 0x0680
+#define MT6392_EFUSE_DOUT_384_399 0x0682
+#define MT6392_EFUSE_DOUT_400_415 0x0684
+#define MT6392_EFUSE_DOUT_416_431 0x0686
+#define MT6392_EFUSE_DOUT_432_447 0x0688
+#define MT6392_EFUSE_DOUT_448_463 0x068A
+#define MT6392_EFUSE_DOUT_464_479 0x068C
+#define MT6392_EFUSE_DOUT_480_495 0x068E
+#define MT6392_EFUSE_DOUT_496_511 0x0690
+#define MT6392_EFUSE_CON7 0x0692
+#define MT6392_EFUSE_CON8 0x0694
+#define MT6392_EFUSE_CON9 0x0696
+#define MT6392_AUXADC_ADC0 0x0700
+#define MT6392_AUXADC_ADC1 0x0702
+#define MT6392_AUXADC_ADC2 0x0704
+#define MT6392_AUXADC_ADC3 0x0706
+#define MT6392_AUXADC_ADC4 0x0708
+#define MT6392_AUXADC_ADC5 0x070A
+#define MT6392_AUXADC_ADC6 0x070C
+#define MT6392_AUXADC_ADC7 0x070E
+#define MT6392_AUXADC_ADC8 0x0710
+#define MT6392_AUXADC_ADC9 0x0712
+#define MT6392_AUXADC_ADC10 0x0714
+#define MT6392_AUXADC_ADC11 0x0716
+#define MT6392_AUXADC_ADC12 0x0718
+#define MT6392_AUXADC_ADC13 0x071A
+#define MT6392_AUXADC_ADC14 0x071C
+#define MT6392_AUXADC_ADC15 0x071E
+#define MT6392_AUXADC_ADC16 0x0720
+#define MT6392_AUXADC_ADC17 0x0722
+#define MT6392_AUXADC_ADC18 0x0724
+#define MT6392_AUXADC_ADC19 0x0726
+#define MT6392_AUXADC_ADC20 0x0728
+#define MT6392_AUXADC_ADC21 0x072A
+#define MT6392_AUXADC_ADC22 0x072C
+#define MT6392_AUXADC_STA0 0x072E
+#define MT6392_AUXADC_STA1 0x0730
+#define MT6392_AUXADC_RQST0 0x0732
+#define MT6392_AUXADC_RQST0_SET 0x0734
+#define MT6392_AUXADC_RQST0_CLR 0x0736
+#define MT6392_AUXADC_CON0 0x0738
+#define MT6392_AUXADC_CON0_SET 0x073A
+#define MT6392_AUXADC_CON0_CLR 0x073C
+#define MT6392_AUXADC_CON1 0x073E
+#define MT6392_AUXADC_CON2 0x0740
+#define MT6392_AUXADC_CON3 0x0742
+#define MT6392_AUXADC_CON4 0x0744
+#define MT6392_AUXADC_CON5 0x0746
+#define MT6392_AUXADC_CON6 0x0748
+#define MT6392_AUXADC_CON7 0x074A
+#define MT6392_AUXADC_CON8 0x074C
+#define MT6392_AUXADC_CON9 0x074E
+#define MT6392_AUXADC_CON10 0x0750
+#define MT6392_AUXADC_CON11 0x0752
+#define MT6392_AUXADC_CON12 0x0754
+#define MT6392_AUXADC_CON13 0x0756
+#define MT6392_AUXADC_CON14 0x0758
+#define MT6392_AUXADC_CON15 0x075A
+#define MT6392_AUXADC_CON16 0x075C
+#define MT6392_AUXADC_AUTORPT0 0x075E
+#define MT6392_AUXADC_LBAT0 0x0760
+#define MT6392_AUXADC_LBAT1 0x0762
+#define MT6392_AUXADC_LBAT2 0x0764
+#define MT6392_AUXADC_LBAT3 0x0766
+#define MT6392_AUXADC_LBAT4 0x0768
+#define MT6392_AUXADC_LBAT5 0x076A
+#define MT6392_AUXADC_LBAT6 0x076C
+#define MT6392_AUXADC_THR0 0x076E
+#define MT6392_AUXADC_THR1 0x0770
+#define MT6392_AUXADC_THR2 0x0772
+#define MT6392_AUXADC_THR3 0x0774
+#define MT6392_AUXADC_THR4 0x0776
+#define MT6392_AUXADC_THR5 0x0778
+#define MT6392_AUXADC_THR6 0x077A
+#define MT6392_AUXADC_EFUSE0 0x077C
+#define MT6392_AUXADC_EFUSE1 0x077E
+#define MT6392_AUXADC_EFUSE2 0x0780
+#define MT6392_AUXADC_EFUSE3 0x0782
+#define MT6392_AUXADC_EFUSE4 0x0784
+#define MT6392_AUXADC_EFUSE5 0x0786
+#define MT6392_AUXADC_NAG_0 0x0788
+#define MT6392_AUXADC_NAG_1 0x078A
+#define MT6392_AUXADC_NAG_2 0x078C
+#define MT6392_AUXADC_NAG_3 0x078E
+#define MT6392_AUXADC_NAG_4 0x0790
+#define MT6392_AUXADC_NAG_5 0x0792
+#define MT6392_AUXADC_NAG_6 0x0794
+#define MT6392_AUXADC_NAG_7 0x0796
+#define MT6392_AUXADC_NAG_8 0x0798
+#define MT6392_AUXADC_TYPEC_H_1 0x079A
+#define MT6392_AUXADC_TYPEC_H_2 0x079C
+#define MT6392_AUXADC_TYPEC_H_3 0x079E
+#define MT6392_AUXADC_TYPEC_H_4 0x07A0
+#define MT6392_AUXADC_TYPEC_H_5 0x07A2
+#define MT6392_AUXADC_TYPEC_H_6 0x07A4
+#define MT6392_AUXADC_TYPEC_H_7 0x07A6
+#define MT6392_AUXADC_TYPEC_L_1 0x07A8
+#define MT6392_AUXADC_TYPEC_L_2 0x07AA
+#define MT6392_AUXADC_TYPEC_L_3 0x07AC
+#define MT6392_AUXADC_TYPEC_L_4 0x07AE
+#define MT6392_AUXADC_TYPEC_L_5 0x07B0
+#define MT6392_AUXADC_TYPEC_L_6 0x07B2
+#define MT6392_AUXADC_TYPEC_L_7 0x07B4
+#define MT6392_AUXADC_NAG_9 0x07B6
+#define MT6392_TYPE_C_PHY_RG_0 0x0800
+#define MT6392_TYPE_C_PHY_RG_CC_RESERVE_CSR 0x0802
+#define MT6392_TYPE_C_VCMP_CTRL 0x0804
+#define MT6392_TYPE_C_CTRL 0x0806
+#define MT6392_TYPE_C_CC_SW_CTRL 0x080a
+#define MT6392_TYPE_C_CC_VOL_PERIODIC_MEAS_VAL 0x080c
+#define MT6392_TYPE_C_CC_VOL_DEBOUNCE_CNT_VAL 0x080e
+#define MT6392_TYPE_C_DRP_SRC_CNT_VAL_0 0x0810
+#define MT6392_TYPE_C_DRP_SNK_CNT_VAL_0 0x0814
+#define MT6392_TYPE_C_DRP_TRY_CNT_VAL_0 0x0818
+#define MT6392_TYPE_C_CC_SRC_DEFAULT_DAC_VAL 0x0820
+#define MT6392_TYPE_C_CC_SRC_15_DAC_VAL 0x0822
+#define MT6392_TYPE_C_CC_SRC_30_DAC_VAL 0x0824
+#define MT6392_TYPE_C_CC_SNK_DAC_VAL_0 0x0828
+#define MT6392_TYPE_C_CC_SNK_DAC_VAL_1 0x082a
+#define MT6392_TYPE_C_INTR_EN_0 0x0830
+#define MT6392_TYPE_C_INTR_EN_2 0x0834
+#define MT6392_TYPE_C_INTR_0 0x0838
+#define MT6392_TYPE_C_INTR_2 0x083C
+#define MT6392_TYPE_C_CC_STATUS 0x0840
+#define MT6392_TYPE_C_PWR_STATUS 0x0842
+#define MT6392_TYPE_C_PHY_RG_CC1_RESISTENCE_0 0x0844
+#define MT6392_TYPE_C_PHY_RG_CC1_RESISTENCE_1 0x0846
+#define MT6392_TYPE_C_PHY_RG_CC2_RESISTENCE_0 0x0848
+#define MT6392_TYPE_C_PHY_RG_CC2_RESISTENCE_1 0x084a
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_ENABLE_0 0x0860
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_0 0x0864
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_1 0x0866
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_ENABLE_1 0x0868
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_2 0x086c
+#define MT6392_TYPE_C_CC_DAC_CALI_CTRL 0x0870
+#define MT6392_TYPE_C_CC_DAC_CALI_RESULT 0x0872
+#define MT6392_TYPE_C_DEBUG_PORT_SELECT_0 0x0880
+#define MT6392_TYPE_C_DEBUG_PORT_SELECT_1 0x0882
+#define MT6392_TYPE_C_DEBUG_MODE_SELECT 0x0884
+#define MT6392_TYPE_C_DEBUG_OUT_READ_0 0x0888
+#define MT6392_TYPE_C_DEBUG_OUT_READ_1 0x088a
+#define MT6392_TYPE_C_SW_DEBUG_PORT_0 0x088c
+#define MT6392_TYPE_C_SW_DEBUG_PORT_1 0x088e
+
+#endif /* __MFD_MT6392_REGISTERS_H__ */
diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h
index 340fc72e22aa..3729a6856c13 100644
--- a/include/linux/mfd/mt6397/core.h
+++ b/include/linux/mfd/mt6397/core.h
@@ -20,6 +20,7 @@ enum chip_id {
MT6359_CHIP_ID = 0x59,
MT6366_CHIP_ID = 0x66,
MT6391_CHIP_ID = 0x91,
+ MT6392_CHIP_ID = 0x92,
MT6397_CHIP_ID = 0x97,
};
--
2.43.0
^ permalink raw reply related
* [PATCH v7 4/9] mfd: mt6397: Use MFD_CELL_* to describe sub-devices
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Luca Leonardo Scorcia, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
Macpaul Lin, Lee Jones, Matthias Brugger,
AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
Linus Walleij, Louis-Alexis Eyraud, Julien Massot, Val Packett,
Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
Use the MFD_CELL_* macros to describe sub-devices. No functional changes.
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
drivers/mfd/mt6397-core.c | 197 ++++++++++++--------------------------
1 file changed, 63 insertions(+), 134 deletions(-)
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 1bdacda9a933..ccd97d66d7f1 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -124,159 +124,88 @@ static const struct resource mt6323_pwrc_resources[] = {
};
static const struct mfd_cell mt6323_devs[] = {
- {
- .name = "mt6323-rtc",
- .num_resources = ARRAY_SIZE(mt6323_rtc_resources),
- .resources = mt6323_rtc_resources,
- .of_compatible = "mediatek,mt6323-rtc",
- }, {
- .name = "mt6323-regulator",
- .of_compatible = "mediatek,mt6323-regulator"
- }, {
- .name = "mt6323-led",
- .of_compatible = "mediatek,mt6323-led"
- }, {
- .name = "mt6323-keys",
- .num_resources = ARRAY_SIZE(mt6323_keys_resources),
- .resources = mt6323_keys_resources,
- .of_compatible = "mediatek,mt6323-keys"
- }, {
- .name = "mt6323-pwrc",
- .num_resources = ARRAY_SIZE(mt6323_pwrc_resources),
- .resources = mt6323_pwrc_resources,
- .of_compatible = "mediatek,mt6323-pwrc"
- },
+ MFD_CELL_OF("mt6323-rtc", mt6323_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6323-rtc"),
+ MFD_CELL_OF("mt6323-regulator", NULL, NULL, 0, 0,
+ "mediatek,mt6323-regulator"),
+ MFD_CELL_OF("mt6323-led", NULL, NULL, 0, 0,
+ "mediatek,mt6323-led"),
+ MFD_CELL_OF("mt6323-keys", mt6323_keys_resources, NULL, 0, 0,
+ "mediatek,mt6323-keys"),
+ MFD_CELL_OF("mt6323-pwrc", mt6323_pwrc_resources, NULL, 0, 0,
+ "mediatek,mt6323-pwrc"),
};
static const struct mfd_cell mt6328_devs[] = {
- {
- .name = "mt6328-regulator",
- .of_compatible = "mediatek,mt6328-regulator"
- }, {
- .name = "mt6328-keys",
- .num_resources = ARRAY_SIZE(mt6328_keys_resources),
- .resources = mt6328_keys_resources,
- .of_compatible = "mediatek,mt6328-keys"
- },
+ MFD_CELL_OF("mt6328-regulator", NULL, NULL, 0, 0,
+ "mediatek,mt6328-regulator"),
+ MFD_CELL_OF("mt6328-keys", mt6328_keys_resources, NULL, 0, 0,
+ "mediatek,mt6328-keys"),
};
static const struct mfd_cell mt6357_devs[] = {
- {
- .name = "mt6359-auxadc",
- .of_compatible = "mediatek,mt6357-auxadc"
- }, {
- .name = "mt6357-regulator",
- }, {
- .name = "mt6357-rtc",
- .num_resources = ARRAY_SIZE(mt6357_rtc_resources),
- .resources = mt6357_rtc_resources,
- .of_compatible = "mediatek,mt6357-rtc",
- }, {
- .name = "mt6357-sound",
- .of_compatible = "mediatek,mt6357-sound"
- }, {
- .name = "mt6357-keys",
- .num_resources = ARRAY_SIZE(mt6357_keys_resources),
- .resources = mt6357_keys_resources,
- .of_compatible = "mediatek,mt6357-keys"
- },
+ MFD_CELL_OF("mt6359-auxadc", NULL, NULL, 0, 0,
+ "mediatek,mt6357-auxadc"),
+ MFD_CELL_NAME("mt6357-regulator"),
+ MFD_CELL_OF("mt6357-rtc", mt6357_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6357-rtc"),
+ MFD_CELL_OF("mt6357-sound", NULL, NULL, 0, 0,
+ "mediatek,mt6357-sound"),
+ MFD_CELL_OF("mt6357-keys", mt6357_keys_resources, NULL, 0, 0,
+ "mediatek,mt6357-keys"),
};
/* MT6331 is always used in combination with MT6332 */
static const struct mfd_cell mt6331_mt6332_devs[] = {
- {
- .name = "mt6331-rtc",
- .num_resources = ARRAY_SIZE(mt6331_rtc_resources),
- .resources = mt6331_rtc_resources,
- .of_compatible = "mediatek,mt6331-rtc",
- }, {
- .name = "mt6331-regulator",
- .of_compatible = "mediatek,mt6331-regulator"
- }, {
- .name = "mt6332-regulator",
- .of_compatible = "mediatek,mt6332-regulator"
- }, {
- .name = "mt6331-keys",
- .num_resources = ARRAY_SIZE(mt6331_keys_resources),
- .resources = mt6331_keys_resources,
- .of_compatible = "mediatek,mt6331-keys"
- },
+ MFD_CELL_OF("mt6331-rtc", mt6331_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6331-rtc"),
+ MFD_CELL_OF("mt6331-regulator", NULL, NULL, 0, 0,
+ "mediatek,mt6331-regulator"),
+ MFD_CELL_OF("mt6332-regulator", NULL, NULL, 0, 0,
+ "mediatek,mt6332-regulator"),
+ MFD_CELL_OF("mt6331-keys", mt6331_keys_resources, NULL, 0, 0,
+ "mediatek,mt6331-keys"),
};
static const struct mfd_cell mt6358_devs[] = {
- {
- .name = "mt6359-auxadc",
- .of_compatible = "mediatek,mt6358-auxadc"
- }, {
- .name = "mt6358-regulator",
- .of_compatible = "mediatek,mt6358-regulator"
- }, {
- .name = "mt6358-rtc",
- .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
- .resources = mt6358_rtc_resources,
- .of_compatible = "mediatek,mt6358-rtc",
- }, {
- .name = "mt6358-sound",
- .of_compatible = "mediatek,mt6358-sound"
- }, {
- .name = "mt6358-keys",
- .num_resources = ARRAY_SIZE(mt6358_keys_resources),
- .resources = mt6358_keys_resources,
- .of_compatible = "mediatek,mt6358-keys"
- },
+ MFD_CELL_OF("mt6359-auxadc", NULL, NULL, 0, 0,
+ "mediatek,mt6358-auxadc"),
+ MFD_CELL_OF("mt6358-regulator", NULL, NULL, 0, 0,
+ "mediatek,mt6358-regulator"),
+ MFD_CELL_OF("mt6358-rtc", mt6358_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6358-rtc"),
+ MFD_CELL_OF("mt6358-sound", NULL, NULL, 0, 0,
+ "mediatek,mt6358-sound"),
+ MFD_CELL_OF("mt6358-keys", mt6358_keys_resources, NULL, 0, 0,
+ "mediatek,mt6358-keys"),
};
static const struct mfd_cell mt6359_devs[] = {
- {
- .name = "mt6359-auxadc",
- .of_compatible = "mediatek,mt6359-auxadc"
- },
- { .name = "mt6359-regulator", },
- {
- .name = "mt6359-rtc",
- .num_resources = ARRAY_SIZE(mt6358_rtc_resources),
- .resources = mt6358_rtc_resources,
- .of_compatible = "mediatek,mt6358-rtc",
- },
- { .name = "mt6359-sound", },
- {
- .name = "mt6359-keys",
- .num_resources = ARRAY_SIZE(mt6359_keys_resources),
- .resources = mt6359_keys_resources,
- .of_compatible = "mediatek,mt6359-keys"
- },
- {
- .name = "mt6359-accdet",
- .of_compatible = "mediatek,mt6359-accdet",
- .num_resources = ARRAY_SIZE(mt6359_accdet_resources),
- .resources = mt6359_accdet_resources,
- },
+ MFD_CELL_OF("mt6359-auxadc", NULL, NULL, 0, 0,
+ "mediatek,mt6359-auxadc"),
+ MFD_CELL_NAME("mt6359-regulator"),
+ MFD_CELL_OF("mt6359-rtc", mt6358_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6358-rtc"),
+ MFD_CELL_NAME("mt6359-sound"),
+ MFD_CELL_OF("mt6359-keys", mt6359_keys_resources, NULL, 0, 0,
+ "mediatek,mt6359-keys"),
+ MFD_CELL_OF("mt6359-accdet", mt6359_accdet_resources, NULL, 0, 0,
+ "mediatek,mt6359-accdet"),
};
static const struct mfd_cell mt6397_devs[] = {
- {
- .name = "mt6397-rtc",
- .num_resources = ARRAY_SIZE(mt6397_rtc_resources),
- .resources = mt6397_rtc_resources,
- .of_compatible = "mediatek,mt6397-rtc",
- }, {
- .name = "mt6397-regulator",
- .of_compatible = "mediatek,mt6397-regulator",
- }, {
- .name = "mt6397-codec",
- .of_compatible = "mediatek,mt6397-codec",
- }, {
- .name = "mt6397-clk",
- .of_compatible = "mediatek,mt6397-clk",
- }, {
- .name = "mt6397-pinctrl",
- .of_compatible = "mediatek,mt6397-pinctrl",
- }, {
- .name = "mt6397-keys",
- .num_resources = ARRAY_SIZE(mt6397_keys_resources),
- .resources = mt6397_keys_resources,
- .of_compatible = "mediatek,mt6397-keys"
- }
+ MFD_CELL_OF("mt6397-rtc", mt6397_rtc_resources, NULL, 0, 0,
+ "mediatek,mt6397-rtc"),
+ MFD_CELL_OF("mt6397-regulator", NULL, NULL, 0, 0,
+ "mediatek,mt6397-regulator"),
+ MFD_CELL_OF("mt6397-codec", NULL, NULL, 0, 0,
+ "mediatek,mt6397-codec"),
+ MFD_CELL_OF("mt6397-clk", NULL, NULL, 0, 0,
+ "mediatek,mt6397-clk"),
+ MFD_CELL_OF("mt6397-pinctrl", NULL, NULL, 0, 0,
+ "mediatek,mt6397-pinctrl"),
+ MFD_CELL_OF("mt6397-keys", mt6397_keys_resources, NULL, 0, 0,
+ "mediatek,mt6397-keys"),
};
struct chip_data {
--
2.43.0
^ permalink raw reply related
* [PATCH v7 3/9] regulator: dt-bindings: Add MediaTek MT6392 PMIC
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Luca Leonardo Scorcia, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
Macpaul Lin, Lee Jones, Matthias Brugger,
AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
Linus Walleij, Val Packett, Julien Massot, Louis-Alexis Eyraud,
Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
Add bindings for the regulators found in the MediaTek MT6392 PMIC,
usually found in board designs using the MediaTek MT8516/MT8167 SoCs.
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
.../regulator/mediatek,mt6392-regulator.yaml | 234 ++++++++++++++++++
.../regulator/mediatek,mt6392-regulator.h | 24 ++
2 files changed, 258 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
create mode 100644 include/dt-bindings/regulator/mediatek,mt6392-regulator.h
diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
new file mode 100644
index 000000000000..197041df4ba1
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
@@ -0,0 +1,234 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6392-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6392 regulator
+
+maintainers:
+ - Luca Leonardo Scorcia <l.scorcia@gmail.com>
+
+description:
+ MT6392 is a power management system chip containing three buck converters and
+ 23 LDOs. All voltage regulators provided by the PMIC are described as
+ sub-nodes of this node.
+
+properties:
+ compatible:
+ items:
+ - const: mediatek,mt6392-regulator
+
+ vproc-supply:
+ description: Supply for buck regulator vproc
+ vcore-supply:
+ description: Supply for buck regulator vcore
+ vsys-supply:
+ description: Supply for buck regulator vsys
+ avddldo-supply:
+ description: |
+ Supply for AVDD LDOs (vm, vio18, vcn18, vcamd, vcamio). According to the data sheet
+ this is an internal supply derived from vsys.
+ ldo1-supply:
+ description: Supply for LDOs group 1 (vaud28, vxo22, vaud22, vadc18, vcama, vrtc)
+ ldo2-supply:
+ description: Supply for LDOs group 2 (vcn35, vio28, vmc, vmch, vefuse, vdig18)
+ ldo3-supply:
+ description: Supply for LDOs group 3 (vusb, vemc3v3, vcamaf, vgp1, vgp2, vm25)
+
+patternProperties:
+ "^v(core|proc|sys)$":
+ description: Buck regulators
+ type: object
+ $ref: regulator.yaml#
+ properties:
+ regulator-allowed-modes:
+ description: |
+ BUCK regulators can set regulator-initial-mode and regulator-allowed-modes to
+ values specified in dt-bindings/regulator/mediatek,mt6392-regulator.h
+ items:
+ enum: [0, 1]
+ unevaluatedProperties: false
+
+ "^v(adc18|camio|cn18|io18|xo22|m25|aud28|io28|rtc|usb)$":
+ description: LDOs with fixed output and mode setting
+ type: object
+ $ref: regulator.yaml#
+ properties:
+ regulator-allowed-modes:
+ description: |
+ LDO regulators can set regulator-initial-mode and regulator-allowed-modes to
+ values specified in dt-bindings/regulator/mediatek,mt6392-regulator.h
+ items:
+ enum: [0, 1]
+ unevaluatedProperties: false
+
+ "^v(cama|dig18)$":
+ description: LDOs with fixed output without mode setting
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+ "^v(aud22|camaf|camd|cn35|efuse|emc3v3|gp1|gp2|m|mc|mch)$":
+ description: LDOs with adjustable output
+ type: object
+ $ref: regulator.yaml#
+ properties:
+ regulator-allowed-modes: false
+ unevaluatedProperties: false
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ regulators {
+ compatible = "mediatek,mt6392-regulator";
+
+ mt6392_vproc_reg: vproc {
+ regulator-min-microvolt = < 700000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vsys_reg: vsys {
+ regulator-min-microvolt = <1400000>;
+ regulator-max-microvolt = <2987500>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vcore_reg: vcore {
+ regulator-min-microvolt = < 700000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vxo22_reg: vxo22 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vaud22_reg: vaud22 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vcama_reg: vcama {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ mt6392_vaud28_reg: vaud28 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vadc18_reg: vadc18 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vcn35_reg: vcn35 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3600000>;
+ };
+
+ mt6392_vio28_reg: vio28 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vusb_reg: vusb {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vmc_reg: vmc {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ mt6392_vmch_reg: vmch {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ };
+
+ mt6392_vemc3v3_reg: vemc3v3 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ mt6392_vgp1_reg: vgp1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ mt6392_vgp2_reg: vgp2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ mt6392_vcn18_reg: vcn18 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ mt6392_vcamaf_reg: vcamaf {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ mt6392_vm_reg: vm {
+ regulator-min-microvolt = <1240000>;
+ regulator-max-microvolt = <1390000>;
+ };
+
+ mt6392_vio18_reg: vio18 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ mt6392_vcamd_reg: vcamd {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ mt6392_vcamio_reg: vcamio {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ mt6392_vm25_reg: vm25 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ };
+
+ mt6392_vefuse_reg: vefuse {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2000000>;
+ };
+ };
diff --git a/include/dt-bindings/regulator/mediatek,mt6392-regulator.h b/include/dt-bindings/regulator/mediatek,mt6392-regulator.h
new file mode 100644
index 000000000000..8bd1a13faad8
--- /dev/null
+++ b/include/dt-bindings/regulator/mediatek,mt6392-regulator.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_REGULATOR_MEDIATEK_MT6392_H_
+#define _DT_BINDINGS_REGULATOR_MEDIATEK_MT6392_H_
+
+/*
+ * Buck mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+
+#define MT6392_BUCK_MODE_AUTO 0
+#define MT6392_BUCK_MODE_FORCE_PWM 1
+
+/*
+ * LDO mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+
+#define MT6392_LDO_MODE_NORMAL 0
+#define MT6392_LDO_MODE_LP 1
+
+#endif
--
2.43.0
^ permalink raw reply related
* [PATCH v7 2/9] dt-bindings: input: mtk-pmic-keys: Add MT6392 PMIC keys
From: Luca Leonardo Scorcia @ 2026-06-15 7:16 UTC (permalink / raw)
To: linux-mediatek
Cc: Fabien Parent, Val Packett, Luca Leonardo Scorcia,
AngeloGioacchino Del Regno, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
Macpaul Lin, Lee Jones, Matthias Brugger, Liam Girdwood,
Mark Brown, Linus Walleij, Julien Massot, Louis-Alexis Eyraud,
Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260615071836.362883-1-l.scorcia@gmail.com>
From: Fabien Parent <parent.f@gmail.com>
Add the binding documentation of mtk-pmic-keys for the MT6392 PMIC.
Signed-off-by: Fabien Parent <parent.f@gmail.com>
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
---
Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
index 140a862ecfbe..ff720588128b 100644
--- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
+++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml
@@ -31,6 +31,7 @@ properties:
- mediatek,mt6357-keys
- mediatek,mt6358-keys
- mediatek,mt6359-keys
+ - mediatek,mt6392-keys
- mediatek,mt6397-keys
- items:
- enum:
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox