* [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers
@ 2026-07-07 8:37 AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference AngeloGioacchino Del Regno
` (10 more replies)
0 siblings, 11 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel
Changes in v10:
- Add use-after-free fix rebased to before this series, as the v1 of
that did not apply cleanly on a tree without this series applied
- Replace unsafe to_spmi_device() with spmi_find_device_by_of_node() (Sashiko)
- Fix -Wformat warning in dev_set_name call (Sashiko)
Changes in v9:
- Added check for dev->parent where missing (Sashiko)
- Changed %d to %u in dev_set_name() call as arg is unsigned (Sashiko)
- Propagating error code from devm_regmap_init_spmi_ext() instead of
returning -ENODEV in phy-qcom-eusb2-repeater.c (Sashiko)
- Rebased over next-20260605 (no conflicts anyway)
Changes in v8:
- Renamed *res to *sub_sdev in devm_spmi_subdevice_remove() (Andy)
- Changed kerneldoc wording to "error pointer" for function
spmi_subdevice_alloc_and_add() (Andy)
- Shuffled around some assignments in spmi_subdevice_alloc_and_add() (Andy)
- Used device_property_read_u32() instead of of_property_read_u32()
in all of the migrated drivers (Andy)
- Changed .max_register field in all of the migrated drivers from
0x100 to 0xff (Andy)
- Kept `sta1` declaration in reversed xmas tree order in function
iadc_poll_wait_eoc() of qcom-spmi-iadc.c (Andy)
Changes in v7:
- Added commit to cleanup redundant dev_name() in the pre-existing
spmi_device_add() function
- Added commit removing unneeded goto and improving spmi_device_add()
readability by returning error in error path, and explicitly zero
for success at the end.
Changes in v6:
- Added commit to convert spmi.c to %pe error format and used
%pe error format in spmi_subdevice code as wanted by Uwe Kleine-Konig
Changes in v5:
- Changed dev_err to dev_err_probe in qcom-spmi-sdam (and done
that even though I disagree - because I wanted this series to
*exclusively* introduce the minimum required changes to
migrate to the new API, but okay, whatever....!);
- Added missing REGMAP dependency in Kconfig for qcom-spmi-sdam,
phy-qcom-eusb2-repeater and qcom-coincell to resolve build
issues when the already allowed COMPILE_TEST is enabled
as pointed out by the test robot's randconfig builds.
Changes in v4:
- Added selection of REGMAP_SPMI in Kconfig for qcom-coincell and
for phy-qcom-eusb2-repeater to resolve undefined references when
compiled with some randconfig
Changes in v3:
- Fixed importing "SPMI" namespace in spmi-devres.c
- Removed all instances of defensive programming, as pointed out by
jic23 and Sebastian
- Removed explicit casting as pointed out by jic23
- Moved ida_free call to spmi_subdev_release() and simplified error
handling in spmi_subdevice_alloc_and_add() as pointed out by jic23
Changes in v2:
- Fixed missing `sparent` initialization in phy-qcom-eusb2-repeater
- Changed val_bits to 8 in all Qualcomm drivers to ensure
compatibility as suggested by Casey
- Added struct device pointer in all conversion commits as suggested
by Andy
- Exported newly introduced functions with a new "SPMI" namespace
and imported the same in all converted drivers as suggested by Andy
- Added missing error checking for dev_set_name() call in spmi.c
as suggested by Andy
- Added comma to last entry of regmap_config as suggested by Andy
While adding support for newer MediaTek platforms, featuring complex
SPMI PMICs, I've seen that those SPMI-connected chips are internally
divided in various IP blocks, reachable in specific contiguous address
ranges... more or less like a MMIO, but over a slow SPMI bus instead.
I recalled that Qualcomm had something similar... and upon checking a
couple of devicetrees, yeah - indeed it's the same over there.
What I've seen then is a common pattern of reading the "reg" property
from devicetree in a struct member and then either
A. Wrapping regmap_{read/write/etc}() calls in a function that adds
the register base with "base + ..register", like it's done with
writel()/readl() calls; or
B. Doing the same as A. but without wrapper functions.
Even though that works just fine, in my opinion it's wrong.
The regmap API is way more complex than MMIO-only readl()/writel()
functions for multiple reasons (including supporting multiple busses
like SPMI, of course) - but everyone seemed to forget that regmap
can manage register base offsets transparently and automatically in
its API functions by simply adding a `reg_base` to the regmap_config
structure, which is used for initializing a `struct regmap`.
So, here we go: this series implements the software concept of an SPMI
Sub-Device (which, well, also reflects how Qualcomm and MediaTek's
actual hardware is laid out anyway).
SPMI Controller
| ______
| / Sub-Device 1
V /
SPMI Device (PMIC) ----------- Sub-Device 2
\
\______ Sub-Device 3
As per this implementation, an SPMI Sub-Device can be allocated/created
and added in any driver that implements a... well.. subdevice (!) with
an SPMI "main" device as its parent: this allows to create and finally
to correctly configure a regmap that is specific to the sub-device,
operating on its specific address range and reading, and writing, to
its registers with the regmap API taking care of adding the base address
of a sub-device's registers as per regmap API design.
All of the SPMI Sub-Devices are therefore added as children of the SPMI
Device (usually a PMIC), as communication depends on the PMIC's SPMI bus
to be available (and the PMIC to be up and running, of course).
Summarizing the dependency chain (which is obvious to whoever knows what
is going on with Qualcomm and/or MediaTek SPMI PMICs):
"SPMI Sub-Device x...N" are children "SPMI Device"
"SPMI Device" is a child of "SPMI Controller"
(that was just another way to say the same thing as the graph above anyway).
Along with the new SPMI Sub-Device registration functions, I have also
performed a conversion of some Qualcomm SPMI drivers and only where the
actual conversion was trivial.
I haven't included any conversion of more complex Qualcomm SPMI drivers
because I don't have the required bandwidth to do so (and besides, I think,
but haven't exactly verified, that some of those require SoCs that I don't
have for testing anyway).
AngeloGioacchino Del Regno (10):
spmi: Remove redundant dev_name() print in spmi_device_add()
spmi: Print error status with %pe format
spmi: Remove unneeded goto in spmi_device_add() error path
spmi: Implement spmi_subdevice_alloc_and_add() and devm variant
nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add()
power: reset: qcom-pon: Migrate to devm_spmi_subdevice_alloc_and_add()
phy: qualcomm: eusb2-repeater: Migrate to
devm_spmi_subdevice_alloc_and_add()
misc: qcom-coincell: Migrate to devm_spmi_subdevice_alloc_and_add()
iio: adc: qcom-spmi-iadc: Migrate to
devm_spmi_subdevice_alloc_and_add()
iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions
drivers/iio/adc/qcom-spmi-iadc.c | 118 ++++++++----------
drivers/misc/Kconfig | 2 +
drivers/misc/qcom-coincell.c | 45 +++++--
drivers/nvmem/Kconfig | 1 +
drivers/nvmem/qcom-spmi-sdam.c | 38 ++++--
drivers/phy/qualcomm/Kconfig | 2 +
.../phy/qualcomm/phy-qcom-eusb2-repeater.c | 54 ++++----
drivers/power/reset/qcom-pon.c | 33 +++--
drivers/spmi/spmi-devres.c | 24 ++++
drivers/spmi/spmi.c | 95 ++++++++++++--
include/linux/spmi.h | 16 +++
11 files changed, 299 insertions(+), 129 deletions(-)
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:53 ` sashiko-bot
2026-07-07 9:07 ` Andy Shevchenko
2026-07-07 8:37 ` [PATCH v10 02/11] spmi: Remove redundant dev_name() print in spmi_device_add() AngeloGioacchino Del Regno
` (9 subsequent siblings)
10 siblings, 2 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, stable, Sashiko Bot
As noticed by Sashiko during a review run of an unrelated patch,
in of_spmi_register_devices(), for_each_available_child_of_node()
is used to loop through children, and to also assign a node to a
newly created SPMI child device.
Problem is that the refcount is dropped at every iteration so, in
the specific case of DT overlays, a use-after-free may occur when
an overlay is dynamically unloaded!
To resolve this, increase the of_node refcount when assigning (in
function of_spmi_register_devices) and release the reference in
spmi_device_remove().
Fixes: bc32bbd04011 ("spmi: Set fwnode for spmi devices")
Cc: stable@vger.kernel.org
Reported-by: Sashiko Bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260608100949.36309-1-angelogioacchino.delregno@collabora.com?part=2
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/spmi/spmi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 57b7c0cb4240..6e701aff6045 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -86,6 +86,9 @@ EXPORT_SYMBOL_GPL(spmi_device_add);
*/
void spmi_device_remove(struct spmi_device *sdev)
{
+ if (IS_ENABLED(CONFIG_OF))
+ of_node_put(sdev->dev.of_node);
+
device_unregister(&sdev->dev);
}
EXPORT_SYMBOL_GPL(spmi_device_remove);
@@ -517,13 +520,14 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl)
if (!sdev)
continue;
- device_set_node(&sdev->dev, of_fwnode_handle(node));
+ device_set_node(&sdev->dev, of_fwnode_handle(of_node_get(node)));
sdev->usid = (u8)reg[0];
err = spmi_device_add(sdev);
if (err) {
dev_err(&sdev->dev,
"failure adding device. status %d\n", err);
+ of_node_put(node);
spmi_device_put(sdev);
}
}
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 02/11] spmi: Remove redundant dev_name() print in spmi_device_add()
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 03/11] spmi: Print error status with %pe format AngeloGioacchino Del Regno
` (8 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Andy Shevchenko
Function spmi_device_add() uses dev_{dbg,err}() for respectively
debug and error prints, and passes the same device pointer as both
the dev_{dbg,err}() parameters and to a dev_name() that is part of
the actual message.
This means that the device name gets printed twice!
Remove the redundant dev_name() from the messages.
Acked-by: Stephen Boyd <sboyd@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/spmi/spmi.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 6e701aff6045..cf33262eaeb2 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -68,12 +68,11 @@ int spmi_device_add(struct spmi_device *sdev)
err = device_add(&sdev->dev);
if (err < 0) {
- dev_err(&sdev->dev, "Can't add %s, status %d\n",
- dev_name(&sdev->dev), err);
+ dev_err(&sdev->dev, "Can't add device, status %d\n", err);
goto err_device_add;
}
- dev_dbg(&sdev->dev, "device %s registered\n", dev_name(&sdev->dev));
+ dev_dbg(&sdev->dev, "device registered\n");
err_device_add:
return err;
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 03/11] spmi: Print error status with %pe format
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 02/11] spmi: Remove redundant dev_name() print in spmi_device_add() AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path AngeloGioacchino Del Regno
` (7 subsequent siblings)
10 siblings, 0 replies; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Andy Shevchenko
Instead of printing just a number, use the %pe format for error
status, increasing readability of error prints.
Acked-by: Stephen Boyd <sboyd@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/spmi/spmi.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index cf33262eaeb2..fa3323521f1a 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -68,7 +68,7 @@ int spmi_device_add(struct spmi_device *sdev)
err = device_add(&sdev->dev);
if (err < 0) {
- dev_err(&sdev->dev, "Can't add device, status %d\n", err);
+ dev_err(&sdev->dev, "Can't add device, status %pe\n", ERR_PTR(err));
goto err_device_add;
}
@@ -496,8 +496,8 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl)
err = of_property_read_u32_array(node, "reg", reg, 2);
if (err) {
dev_err(&ctrl->dev,
- "node %pOF err (%d) does not have 'reg' property\n",
- node, err);
+ "node %pOF err (%pe) does not have 'reg' property\n",
+ node, ERR_PTR(err));
continue;
}
@@ -525,7 +525,7 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl)
err = spmi_device_add(sdev);
if (err) {
dev_err(&sdev->dev,
- "failure adding device. status %d\n", err);
+ "failure adding device. status %pe\n", ERR_PTR(err));
of_node_put(node);
spmi_device_put(sdev);
}
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (2 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 03/11] spmi: Print error status with %pe format AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:48 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant AngeloGioacchino Del Regno
` (6 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Andy Shevchenko
If any error happens during device_add() just return inside of the
conditional, as the goto path doesn't do anything else if not just
returning.
While at it, to improve readability, also change this function to
explicitly return 0 (for success) at the end.
Acked-by: Stephen Boyd <sboyd@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/spmi/spmi.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index fa3323521f1a..cae89dd915d4 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -69,13 +69,11 @@ int spmi_device_add(struct spmi_device *sdev)
err = device_add(&sdev->dev);
if (err < 0) {
dev_err(&sdev->dev, "Can't add device, status %pe\n", ERR_PTR(err));
- goto err_device_add;
+ return err;
}
dev_dbg(&sdev->dev, "device registered\n");
-
-err_device_add:
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(spmi_device_add);
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (3 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:48 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() AngeloGioacchino Del Regno
` (5 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Jonathan Cameron,
Andy Shevchenko
Some devices connected over the SPMI bus may be big, in the sense
that those may be a complex of devices managed by a single chip
over the SPMI bus, reachable through a single SID.
Add new functions aimed at managing sub-devices of a SPMI device
spmi_subdevice_alloc_and_add() and a spmi_subdevice_remove() for
adding a new subdevice and removing it respectively, and also
add their devm_* variants.
The need for such functions comes from the existence of those
complex Power Management ICs (PMICs), which feature one or many
sub-devices, in some cases with these being even addressable on
the chip in form of SPMI register ranges.
Examples of those devices can be found in both Qualcomm platforms
with their PMICs having PON, RTC, SDAM, GPIO controller, and other
sub-devices, and in newer MediaTek platforms showing similar HW
features and a similar layout with those also having many subdevs.
Also, instead of generally exporting symbols, export them with a
new "SPMI" namespace: all users will have to import this namespace
to make use of the newly introduced exports.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Acked-by: Stephen Boyd <sboyd@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/spmi/spmi-devres.c | 24 ++++++++++++
drivers/spmi/spmi.c | 78 ++++++++++++++++++++++++++++++++++++++
include/linux/spmi.h | 16 ++++++++
3 files changed, 118 insertions(+)
diff --git a/drivers/spmi/spmi-devres.c b/drivers/spmi/spmi-devres.c
index 62c4b3f24d06..c3e889fe1b6e 100644
--- a/drivers/spmi/spmi-devres.c
+++ b/drivers/spmi/spmi-devres.c
@@ -60,5 +60,29 @@ int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl
}
EXPORT_SYMBOL_GPL(devm_spmi_controller_add);
+static void devm_spmi_subdevice_remove(void *sub_sdev)
+{
+ spmi_subdevice_remove(sub_sdev);
+}
+
+struct spmi_subdevice *devm_spmi_subdevice_alloc_and_add(struct device *dev,
+ struct spmi_device *sparent)
+{
+ struct spmi_subdevice *sub_sdev;
+ int ret;
+
+ sub_sdev = spmi_subdevice_alloc_and_add(sparent);
+ if (IS_ERR(sub_sdev))
+ return sub_sdev;
+
+ ret = devm_add_action_or_reset(dev, devm_spmi_subdevice_remove, sub_sdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return sub_sdev;
+}
+EXPORT_SYMBOL_NS_GPL(devm_spmi_subdevice_alloc_and_add, "SPMI");
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SPMI devres helpers");
+MODULE_IMPORT_NS("SPMI");
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index cae89dd915d4..cd047aba38ab 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -19,6 +19,7 @@
static bool is_registered;
static DEFINE_IDA(ctrl_ida);
+static DEFINE_IDA(spmi_subdevice_ida);
static void spmi_dev_release(struct device *dev)
{
@@ -31,6 +32,19 @@ static const struct device_type spmi_dev_type = {
.release = spmi_dev_release,
};
+static void spmi_subdev_release(struct device *dev)
+{
+ struct spmi_device *sdev = to_spmi_device(dev);
+ struct spmi_subdevice *sub_sdev = container_of(sdev, struct spmi_subdevice, sdev);
+
+ ida_free(&spmi_subdevice_ida, sub_sdev->devid);
+ kfree(sub_sdev);
+}
+
+static const struct device_type spmi_subdev_type = {
+ .release = spmi_subdev_release,
+};
+
static void spmi_ctrl_release(struct device *dev)
{
struct spmi_controller *ctrl = to_spmi_controller(dev);
@@ -90,6 +104,18 @@ void spmi_device_remove(struct spmi_device *sdev)
}
EXPORT_SYMBOL_GPL(spmi_device_remove);
+/**
+ * spmi_subdevice_remove() - Remove an SPMI subdevice
+ * @sub_sdev: spmi_device to be removed
+ */
+void spmi_subdevice_remove(struct spmi_subdevice *sub_sdev)
+{
+ struct spmi_device *sdev = &sub_sdev->sdev;
+
+ device_unregister(&sdev->dev);
+}
+EXPORT_SYMBOL_NS_GPL(spmi_subdevice_remove, "SPMI");
+
static inline int
spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid)
{
@@ -431,6 +457,58 @@ struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl)
}
EXPORT_SYMBOL_GPL(spmi_device_alloc);
+/**
+ * spmi_subdevice_alloc_and_add(): Allocate and add a new SPMI sub-device
+ * @sparent: SPMI parent device with previously registered SPMI controller
+ *
+ * Returns:
+ * Pointer to newly allocated SPMI sub-device for success or error pointer.
+ */
+struct spmi_subdevice *spmi_subdevice_alloc_and_add(struct spmi_device *sparent)
+{
+ struct spmi_subdevice *sub_sdev;
+ struct spmi_device *sdev;
+ int ret;
+
+ sub_sdev = kzalloc_obj(*sub_sdev);
+ if (!sub_sdev)
+ return ERR_PTR(-ENOMEM);
+
+ sdev = &sub_sdev->sdev;
+ sdev->ctrl = sparent->ctrl;
+ sdev->usid = sparent->usid;
+
+ ret = ida_alloc(&spmi_subdevice_ida, GFP_KERNEL);
+ if (ret < 0) {
+ kfree(sub_sdev);
+ return ERR_PTR(ret);
+ }
+ sub_sdev->devid = ret;
+
+ device_initialize(&sdev->dev);
+ sdev->dev.parent = &sparent->dev;
+ sdev->dev.bus = &spmi_bus_type;
+ sdev->dev.type = &spmi_subdev_type;
+
+ ret = dev_set_name(&sdev->dev, "%u-%02x.%u.auto",
+ sdev->ctrl->nr, sdev->usid, sub_sdev->devid);
+ if (ret)
+ goto err_put_dev;
+
+ ret = device_add(&sdev->dev);
+ if (ret) {
+ dev_err(&sdev->dev, "Can't add device, status %pe\n", ERR_PTR(ret));
+ goto err_put_dev;
+ }
+
+ return sub_sdev;
+
+err_put_dev:
+ put_device(&sdev->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS_GPL(spmi_subdevice_alloc_and_add, "SPMI");
+
/**
* spmi_controller_alloc() - Allocate a new SPMI controller
* @parent: parent device
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index 4eb9564a7fb3..a78a8924b2ac 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -69,6 +69,22 @@ int spmi_device_add(struct spmi_device *sdev);
void spmi_device_remove(struct spmi_device *sdev);
+/**
+ * struct spmi_subdevice - Basic representation of an SPMI sub-device
+ * @sdev: Sub-device representation of an SPMI device
+ * @devid: Platform Device ID of an SPMI sub-device
+ */
+struct spmi_subdevice {
+ struct spmi_device sdev;
+ unsigned int devid;
+};
+
+struct spmi_subdevice *spmi_subdevice_alloc_and_add(struct spmi_device *sparent);
+void spmi_subdevice_remove(struct spmi_subdevice *sdev);
+
+struct spmi_subdevice *devm_spmi_subdevice_alloc_and_add(struct device *dev,
+ struct spmi_device *sparent);
+
/**
* struct spmi_controller - interface to the SPMI master controller
* @dev: Driver model representation of the device.
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (4 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:50 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 07/11] power: reset: qcom-pon: " AngeloGioacchino Del Regno
` (4 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Andy Shevchenko
Some Qualcomm PMICs integrate a SDAM device, internally located in
a specific address range reachable through SPMI communication.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device for SDAM
and initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
This allows to stop manually adding the register base address to
every R/W call in this driver, as this can be, and is now, handled
by the regmap API instead.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Acked-by: Srinivas Kandagatla <srini@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/nvmem/Kconfig | 1 +
drivers/nvmem/qcom-spmi-sdam.c | 44 ++++++++++++++++++++++++----------
2 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index e10f7ff725ff..cc032d60b8c1 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -380,6 +380,7 @@ config NVMEM_SNVS_LPGPR
config NVMEM_SPMI_SDAM
tristate "SPMI SDAM Support"
depends on SPMI
+ select REGMAP_SPMI
help
This driver supports the Shared Direct Access Memory Module on
Qualcomm Technologies, Inc. PMICs. It provides the clients
diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
index 4f1cca6eab71..3ad842676dde 100644
--- a/drivers/nvmem/qcom-spmi-sdam.c
+++ b/drivers/nvmem/qcom-spmi-sdam.c
@@ -9,6 +9,7 @@
#include <linux/nvmem-provider.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/spmi.h>
#define SDAM_MEM_START 0x40
#define REGISTER_MAP_ID 0x40
@@ -20,7 +21,6 @@
struct sdam_chip {
struct regmap *regmap;
struct nvmem_config sdam_config;
- unsigned int base;
unsigned int size;
};
@@ -73,7 +73,7 @@ static int sdam_read(void *priv, unsigned int offset, void *val,
return -EINVAL;
}
- rc = regmap_bulk_read(sdam->regmap, sdam->base + offset, val, bytes);
+ rc = regmap_bulk_read(sdam->regmap, offset, val, bytes);
if (rc < 0)
dev_err(dev, "Failed to read SDAM offset %#x len=%zd, rc=%d\n",
offset, bytes, rc);
@@ -100,7 +100,7 @@ static int sdam_write(void *priv, unsigned int offset, void *val,
return -EINVAL;
}
- rc = regmap_bulk_write(sdam->regmap, sdam->base + offset, val, bytes);
+ rc = regmap_bulk_write(sdam->regmap, offset, val, bytes);
if (rc < 0)
dev_err(dev, "Failed to write SDAM offset %#x len=%zd, rc=%d\n",
offset, bytes, rc);
@@ -110,28 +110,47 @@ static int sdam_write(void *priv, unsigned int offset, void *val,
static int sdam_probe(struct platform_device *pdev)
{
+ struct regmap_config sdam_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .fast_io = true,
+ };
struct sdam_chip *sdam;
struct nvmem_device *nvmem;
+ struct spmi_device *sparent;
+ struct spmi_subdevice *sub_sdev;
+ struct device *dev = &pdev->dev;
unsigned int val;
int rc;
+ if (!dev->parent)
+ return -ENODEV;
+
sdam = devm_kzalloc(&pdev->dev, sizeof(*sdam), GFP_KERNEL);
if (!sdam)
return -ENOMEM;
- sdam->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!sdam->regmap) {
- dev_err(&pdev->dev, "Failed to get regmap handle\n");
- return -ENXIO;
- }
+ sparent = spmi_find_device_by_of_node(dev->parent->of_node);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
- rc = of_property_read_u32(pdev->dev.of_node, "reg", &sdam->base);
+ sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
+ if (IS_ERR(sub_sdev))
+ return PTR_ERR(sub_sdev);
+
+ rc = device_property_read_u32(dev, "reg", &sdam_regmap_config.reg_base);
if (rc < 0) {
- dev_err(&pdev->dev, "Failed to get SDAM base, rc=%d\n", rc);
+ dev_err(dev, "Failed to get SDAM base, rc=%d\n", rc);
return -EINVAL;
}
- rc = regmap_read(sdam->regmap, sdam->base + SDAM_SIZE, &val);
+ sdam->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &sdam_regmap_config);
+ if (IS_ERR(sdam->regmap))
+ return dev_err_probe(dev, PTR_ERR(sdam->regmap),
+ "Failed to get regmap handle\n");
+
+ rc = regmap_read(sdam->regmap, SDAM_SIZE, &val);
if (rc < 0) {
dev_err(&pdev->dev, "Failed to read SDAM_SIZE rc=%d\n", rc);
return -EINVAL;
@@ -159,7 +178,7 @@ static int sdam_probe(struct platform_device *pdev)
}
dev_dbg(&pdev->dev,
"SDAM base=%#x size=%u registered successfully\n",
- sdam->base, sdam->size);
+ sdam_regmap_config.reg_base, sdam->size);
return 0;
}
@@ -181,3 +200,4 @@ module_platform_driver(sdam_driver);
MODULE_DESCRIPTION("QCOM SPMI SDAM driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("SPMI");
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 07/11] power: reset: qcom-pon: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (5 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:49 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: " AngeloGioacchino Del Regno
` (3 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Sebastian Reichel,
Andy Shevchenko
Some Qualcomm PMICs integrates a Power On device supporting pwrkey
and resin along with the Android reboot reason action identifier.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device for PON
and initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
This allows to stop manually adding the register base address to
every R/W call in this driver, as this can be, and is now, handled
by the regmap API instead.
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/power/reset/qcom-pon.c | 36 +++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index 7e108982a582..f94aaecd6ed6 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -11,6 +11,7 @@
#include <linux/reboot.h>
#include <linux/reboot-mode.h>
#include <linux/regmap.h>
+#include <linux/spmi.h>
#define PON_SOFT_RB_SPARE 0x8f
@@ -22,7 +23,6 @@
struct qcom_pon {
struct device *dev;
struct regmap *regmap;
- u32 baseaddr;
struct reboot_mode_driver reboot_mode;
long reason_shift;
};
@@ -35,7 +35,7 @@ static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot,
int ret;
ret = regmap_update_bits(pon->regmap,
- pon->baseaddr + PON_SOFT_RB_SPARE,
+ PON_SOFT_RB_SPARE,
GENMASK(7, pon->reason_shift),
magic << pon->reason_shift);
if (ret < 0)
@@ -46,27 +46,44 @@ static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot,
static int qcom_pon_probe(struct platform_device *pdev)
{
+ struct regmap_config qcom_pon_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .fast_io = true,
+ };
+ struct device *dev = &pdev->dev;
+ struct spmi_subdevice *sub_sdev;
+ struct spmi_device *sparent;
struct qcom_pon *pon;
long reason_shift;
int error;
+ if (!dev->parent)
+ return -ENODEV;
+
pon = devm_kzalloc(&pdev->dev, sizeof(*pon), GFP_KERNEL);
if (!pon)
return -ENOMEM;
pon->dev = &pdev->dev;
- pon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!pon->regmap) {
- dev_err(&pdev->dev, "failed to locate regmap\n");
- return -ENODEV;
- }
+ sparent = spmi_find_device_by_of_node(dev->parent->of_node);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
+
+ sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
+ if (IS_ERR(sub_sdev))
+ return PTR_ERR(sub_sdev);
- error = of_property_read_u32(pdev->dev.of_node, "reg",
- &pon->baseaddr);
+ error = device_property_read_u32(dev, "reg", &qcom_pon_regmap_config.reg_base);
if (error)
return error;
+ pon->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &qcom_pon_regmap_config);
+ if (IS_ERR(pon->regmap))
+ return PTR_ERR(pon->regmap);
+
reason_shift = (long)of_device_get_match_data(&pdev->dev);
if (reason_shift != NO_REASON_SHIFT) {
@@ -106,3 +123,4 @@ module_platform_driver(qcom_pon_driver);
MODULE_DESCRIPTION("Qualcomm Power On driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("SPMI");
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (6 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 07/11] power: reset: qcom-pon: " AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:51 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 09/11] misc: qcom-coincell: " AngeloGioacchino Del Regno
` (2 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Abel Vesa,
Andy Shevchenko
Some Qualcomm PMICs integrate an USB Repeater device, used to
convert between eUSB2 and USB 2.0 signaling levels, reachable
in a specific address range over SPMI.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device for EUSB2
and initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
This allows to stop manually adding the register base address to
every R/W call in this driver, as this can be, and is now, handled
by the regmap API instead.
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Reviewed-by: Abel Vesa <abel.vesa@linaro.org>
Acked-by: Vinod Koul <vkoul@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/phy/qualcomm/Kconfig | 2 +
.../phy/qualcomm/phy-qcom-eusb2-repeater.c | 57 ++++++++++++-------
2 files changed, 38 insertions(+), 21 deletions(-)
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index 60a0ead127fa..902a788f35f1 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -128,7 +128,9 @@ config PHY_QCOM_QUSB2
config PHY_QCOM_EUSB2_REPEATER
tristate "Qualcomm PMIC eUSB2 Repeater Driver"
depends on OF && (ARCH_QCOM || COMPILE_TEST)
+ depends on SPMI
select GENERIC_PHY
+ select REGMAP_SPMI
help
Enable support for the USB high-speed eUSB2 repeater on Qualcomm
PMICs. The repeater is paired with a Synopsys or M31 eUSB2 Phy
diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
index efeec4709a15..f99152cf5984 100644
--- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
@@ -9,6 +9,7 @@
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
+#include <linux/spmi.h>
/* eUSB2 status registers */
#define EUSB2_RPTR_STATUS 0x08
@@ -66,7 +67,6 @@ struct eusb2_repeater {
struct phy *phy;
struct regulator_bulk_data *vregs;
const struct eusb2_repeater_cfg *cfg;
- u32 base;
enum phy_mode mode;
};
@@ -143,7 +143,6 @@ static int eusb2_repeater_init(struct phy *phy)
struct eusb2_repeater *rptr = phy_get_drvdata(phy);
struct device_node *np = rptr->dev->of_node;
struct regmap *regmap = rptr->regmap;
- u32 base = rptr->base;
u32 poll_val;
s32 dt_val;
int ret;
@@ -154,37 +153,37 @@ static int eusb2_repeater_init(struct phy *phy)
if (ret)
return ret;
- regmap_write(regmap, base + EUSB2_EN_CTL1, EUSB2_RPTR_EN);
+ regmap_write(regmap, EUSB2_EN_CTL1, EUSB2_RPTR_EN);
/* Write registers from init table */
for (int i = 0; i < rptr->cfg->init_tbl_num; i++)
- regmap_write(regmap, base + rptr->cfg->init_tbl[i].reg,
+ regmap_write(regmap, rptr->cfg->init_tbl[i].reg,
rptr->cfg->init_tbl[i].value);
/* Override registers from devicetree values */
if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val))
- regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, val);
+ regmap_write(regmap, EUSB2_TUNE_USB2_PREEM, val);
if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &val))
- regmap_write(regmap, base + EUSB2_TUNE_HSDISC, val);
+ regmap_write(regmap, EUSB2_TUNE_HSDISC, val);
if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &val))
- regmap_write(regmap, base + EUSB2_TUNE_IUSB2, val);
+ regmap_write(regmap, EUSB2_TUNE_IUSB2, val);
if (!of_property_read_u8(np, "qcom,tune-res-fsdif", &val))
- regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, val);
+ regmap_write(regmap, EUSB2_TUNE_RES_FSDIF, val);
if (!of_property_read_s32(np, "qcom,squelch-detector-bp", &dt_val)) {
for (i = 0; i < ARRAY_SIZE(squelch_detector); i++) {
if (squelch_detector[i] == dt_val) {
- regmap_write(regmap, base + EUSB2_TUNE_SQUELCH_U, i);
+ regmap_write(regmap, EUSB2_TUNE_SQUELCH_U, i);
break;
}
}
}
/* Wait for status OK */
- ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, poll_val,
+ ret = regmap_read_poll_timeout(regmap, EUSB2_RPTR_STATUS, poll_val,
poll_val & RPTR_OK, 10, 5);
if (ret)
dev_err(rptr->dev, "initialization timed-out\n");
@@ -197,7 +196,6 @@ static int eusb2_repeater_set_mode(struct phy *phy,
{
struct eusb2_repeater *rptr = phy_get_drvdata(phy);
struct regmap *regmap = rptr->regmap;
- u32 base = rptr->base;
switch (mode) {
case PHY_MODE_USB_HOST:
@@ -206,8 +204,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
* per eUSB 1.2 Spec. Below implement software workaround until
* PHY and controller is fixing seen observation.
*/
- regmap_write(regmap, base + EUSB2_FORCE_EN_5, F_CLK_19P2M_EN);
- regmap_write(regmap, base + EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN);
+ regmap_write(regmap, EUSB2_FORCE_EN_5, F_CLK_19P2M_EN);
+ regmap_write(regmap, EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN);
break;
case PHY_MODE_USB_DEVICE:
/*
@@ -216,8 +214,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
* repeater doesn't clear previous value due to shared
* regulators (say host <-> device mode switch).
*/
- regmap_write(regmap, base + EUSB2_FORCE_EN_5, 0);
- regmap_write(regmap, base + EUSB2_FORCE_VAL_5, 0);
+ regmap_write(regmap, EUSB2_FORCE_EN_5, 0);
+ regmap_write(regmap, EUSB2_FORCE_VAL_5, 0);
break;
default:
return -EINVAL;
@@ -242,13 +240,23 @@ static const struct phy_ops eusb2_repeater_ops = {
static int eusb2_repeater_probe(struct platform_device *pdev)
{
+ struct regmap_config eusb2_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .fast_io = true,
+ };
+ struct spmi_device *sparent;
struct eusb2_repeater *rptr;
+ struct spmi_subdevice *sub_sdev;
struct device *dev = &pdev->dev;
struct phy_provider *phy_provider;
struct device_node *np = dev->of_node;
- u32 res;
int ret;
+ if (!dev->parent)
+ return -ENODEV;
+
rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL);
if (!rptr)
return -ENOMEM;
@@ -260,15 +268,21 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
if (!rptr->cfg)
return -EINVAL;
- rptr->regmap = dev_get_regmap(dev->parent, NULL);
- if (!rptr->regmap)
- return -ENODEV;
+ sparent = spmi_find_device_by_of_node(dev->parent->of_node);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
+
+ sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
+ if (IS_ERR(sub_sdev))
+ return PTR_ERR(sub_sdev);
- ret = of_property_read_u32(np, "reg", &res);
+ ret = device_property_read_u32(dev, "reg", &eusb2_regmap_config.reg_base);
if (ret < 0)
return ret;
- rptr->base = res;
+ rptr->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &eusb2_regmap_config);
+ if (IS_ERR(rptr->regmap))
+ return PTR_ERR(rptr->regmap);
ret = eusb2_repeater_init_vregs(rptr);
if (ret < 0) {
@@ -335,3 +349,4 @@ module_platform_driver(eusb2_repeater_driver);
MODULE_DESCRIPTION("Qualcomm PMIC eUSB2 Repeater driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SPMI");
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 09/11] misc: qcom-coincell: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (7 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: " AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:56 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: " AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions AngeloGioacchino Del Regno
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Andy Shevchenko
Some Qualcomm PMICs integrate a charger for coincells, usually
powering an RTC when external (or main battery) power is missing.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device and
initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
This allows to stop manually adding the register base address to
every R/W call in this driver, as this can be, and is now, handled
by the regmap API instead.
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/misc/Kconfig | 2 ++
drivers/misc/qcom-coincell.c | 48 ++++++++++++++++++++++++++----------
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 390256ed91f4..90947c015179 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -291,6 +291,8 @@ config HP_ILO
config QCOM_COINCELL
tristate "Qualcomm coincell charger support"
depends on MFD_SPMI_PMIC || COMPILE_TEST
+ depends on SPMI
+ select REGMAP_SPMI
help
This driver supports the coincell block found inside of
Qualcomm PMICs. The coincell charger provides a means to
diff --git a/drivers/misc/qcom-coincell.c b/drivers/misc/qcom-coincell.c
index 3c57f7429147..46340f0199cd 100644
--- a/drivers/misc/qcom-coincell.c
+++ b/drivers/misc/qcom-coincell.c
@@ -9,11 +9,11 @@
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <linux/spmi.h>
struct qcom_coincell {
struct device *dev;
struct regmap *regmap;
- u32 base_addr;
};
#define QCOM_COINCELL_REG_RSET 0x44
@@ -35,7 +35,7 @@ static int qcom_coincell_chgr_config(struct qcom_coincell *chgr, int rset,
/* if disabling, just do that and skip other operations */
if (!enable)
return regmap_write(chgr->regmap,
- chgr->base_addr + QCOM_COINCELL_REG_ENABLE, 0);
+ QCOM_COINCELL_REG_ENABLE, 0);
/* find index for current-limiting resistor */
for (i = 0; i < ARRAY_SIZE(qcom_rset_map); i++)
@@ -58,7 +58,7 @@ static int qcom_coincell_chgr_config(struct qcom_coincell *chgr, int rset,
}
rc = regmap_write(chgr->regmap,
- chgr->base_addr + QCOM_COINCELL_REG_RSET, i);
+ QCOM_COINCELL_REG_RSET, i);
if (rc) {
/*
* This is mainly to flag a bad base_addr (reg) from dts.
@@ -71,37 +71,58 @@ static int qcom_coincell_chgr_config(struct qcom_coincell *chgr, int rset,
}
rc = regmap_write(chgr->regmap,
- chgr->base_addr + QCOM_COINCELL_REG_VSET, j);
+ QCOM_COINCELL_REG_VSET, j);
if (rc)
return rc;
/* set 'enable' register */
return regmap_write(chgr->regmap,
- chgr->base_addr + QCOM_COINCELL_REG_ENABLE,
+ QCOM_COINCELL_REG_ENABLE,
QCOM_COINCELL_ENABLE);
}
static int qcom_coincell_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
+ struct regmap_config qcom_coincell_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .fast_io = true,
+ };
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct spmi_subdevice *sub_sdev;
+ struct spmi_device *sparent;
struct qcom_coincell chgr;
u32 rset = 0;
u32 vset = 0;
bool enable;
int rc;
- chgr.dev = &pdev->dev;
+ if (!dev->parent)
+ return -ENODEV;
- chgr.regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!chgr.regmap) {
- dev_err(chgr.dev, "Unable to get regmap\n");
- return -EINVAL;
- }
+ chgr.dev = &pdev->dev;
- rc = of_property_read_u32(node, "reg", &chgr.base_addr);
+ rc = device_property_read_u32(dev, "reg", &qcom_coincell_regmap_config.reg_base);
if (rc)
return rc;
+ sparent = spmi_find_device_by_of_node(dev->parent->of_node);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
+
+ sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
+ if (IS_ERR(sub_sdev))
+ return PTR_ERR(sub_sdev);
+
+ chgr.regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev,
+ &qcom_coincell_regmap_config);
+ if (IS_ERR(chgr.regmap)) {
+ dev_err(chgr.dev, "Unable to get regmap\n");
+ return PTR_ERR(chgr.regmap);
+ }
+
enable = !of_property_read_bool(node, "qcom,charger-disable");
if (enable) {
@@ -142,3 +163,4 @@ module_platform_driver(qcom_coincell_driver);
MODULE_DESCRIPTION("Qualcomm PMIC coincell charger driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("SPMI");
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (8 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 09/11] misc: qcom-coincell: " AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 9:03 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions AngeloGioacchino Del Regno
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Jonathan Cameron,
Andy Shevchenko
Some Qualcomm PMICs integrate an Current ADC device, reachable
in a specific address range over SPMI.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device and
initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
This allows to stop manually adding the register base address to
every R/W call in this driver, as this can be, and is now, handled
by the regmap API instead.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/iio/adc/qcom-spmi-iadc.c | 35 ++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 11 deletions(-)
diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
index 0ec3a0c4b1de..ad66bb92fe19 100644
--- a/drivers/iio/adc/qcom-spmi-iadc.c
+++ b/drivers/iio/adc/qcom-spmi-iadc.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/spmi.h>
/* IADC register and bit definition */
#define IADC_REVISION2 0x1
@@ -94,7 +95,6 @@
* struct iadc_chip - IADC Current ADC device structure.
* @regmap: regmap for register read/write.
* @dev: This device pointer.
- * @base: base offset for the ADC peripheral.
* @rsense: Values of the internal and external sense resister in micro Ohms.
* @poll_eoc: Poll for end of conversion instead of waiting for IRQ.
* @offset: Raw offset values for the internal and external channels.
@@ -105,7 +105,6 @@
struct iadc_chip {
struct regmap *regmap;
struct device *dev;
- u16 base;
bool poll_eoc;
u32 rsense[2];
u16 offset[2];
@@ -119,7 +118,7 @@ static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data)
unsigned int val;
int ret;
- ret = regmap_read(iadc->regmap, iadc->base + offset, &val);
+ ret = regmap_read(iadc->regmap, offset, &val);
if (ret < 0)
return ret;
@@ -129,7 +128,7 @@ static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data)
static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data)
{
- return regmap_write(iadc->regmap, iadc->base + offset, data);
+ return regmap_write(iadc->regmap, offset, data);
}
static int iadc_reset(struct iadc_chip *iadc)
@@ -270,7 +269,7 @@ static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us)
static int iadc_read_result(struct iadc_chip *iadc, u16 *data)
{
- return regmap_bulk_read(iadc->regmap, iadc->base + IADC_DATA, data, 2);
+ return regmap_bulk_read(iadc->regmap, IADC_DATA, data, 2);
}
static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
@@ -488,12 +487,22 @@ static void iadc_disable_irq_wake(void *data)
static int iadc_probe(struct platform_device *pdev)
{
+ struct regmap_config iadc_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .fast_io = true,
+ };
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
+ struct spmi_subdevice *sub_sdev;
+ struct spmi_device *sparent;
struct iio_dev *indio_dev;
struct iadc_chip *iadc;
int ret, irq_eoc;
- u32 res;
+
+ if (!dev->parent)
+ return -ENODEV;
indio_dev = devm_iio_device_alloc(dev, sizeof(*iadc));
if (!indio_dev)
@@ -502,18 +511,21 @@ static int iadc_probe(struct platform_device *pdev)
iadc = iio_priv(indio_dev);
iadc->dev = dev;
- iadc->regmap = dev_get_regmap(dev->parent, NULL);
- if (!iadc->regmap)
- return -ENODEV;
+ sparent = to_spmi_device(dev->parent);
+ sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
+ if (IS_ERR(sub_sdev))
+ return PTR_ERR(sub_sdev);
init_completion(&iadc->complete);
mutex_init(&iadc->lock);
- ret = of_property_read_u32(node, "reg", &res);
+ ret = device_property_read_u32(dev, "reg", &iadc_regmap_config.reg_base);
if (ret < 0)
return -ENODEV;
- iadc->base = res;
+ iadc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &iadc_regmap_config);
+ if (IS_ERR(iadc->regmap))
+ return PTR_ERR(iadc->regmap);
ret = iadc_version_check(iadc);
if (ret < 0)
@@ -596,3 +608,4 @@ MODULE_ALIAS("platform:qcom-spmi-iadc");
MODULE_DESCRIPTION("Qualcomm SPMI PMIC current ADC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
+MODULE_IMPORT_NS("SPMI");
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
` (9 preceding siblings ...)
2026-07-07 8:37 ` [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: " AngeloGioacchino Del Regno
@ 2026-07-07 8:37 ` AngeloGioacchino Del Regno
2026-07-07 8:55 ` sashiko-bot
10 siblings, 1 reply; 22+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-07 8:37 UTC (permalink / raw)
To: jic23, sboyd
Cc: dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, angelogioacchino.delregno, krzk,
dmitry.baryshkov, quic_wcheng, melody.olvera, quic_nsekar,
ivo.ivanov.ivanov1, abelvesa, luca.weiss, konrad.dybcio,
mitltlatltl, krishna.kurapati, linux-arm-msm, linux-iio,
linux-kernel, linux-phy, linux-pm, kernel, Jonathan Cameron,
Andy Shevchenko
This driver doesn't need to add any register base address to any
regmap call anymore since it was migrated to register as a SPMI
subdevice with its own regmap reg_base, which makes the regmap
API to automatically add such base address internally.
Since the iadc_{read,write,read_result}() functions now only do
call regmap_{read,write,bulk_read}() and nothing else, simplify
the driver by removing them and by calling regmap APIs directly.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/iio/adc/qcom-spmi-iadc.c | 94 +++++++++++++-------------------
1 file changed, 37 insertions(+), 57 deletions(-)
diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
index ad66bb92fe19..84c2bd27367f 100644
--- a/drivers/iio/adc/qcom-spmi-iadc.c
+++ b/drivers/iio/adc/qcom-spmi-iadc.c
@@ -113,77 +113,59 @@ struct iadc_chip {
struct completion complete;
};
-static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data)
-{
- unsigned int val;
- int ret;
-
- ret = regmap_read(iadc->regmap, offset, &val);
- if (ret < 0)
- return ret;
-
- *data = val;
- return 0;
-}
-
-static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data)
-{
- return regmap_write(iadc->regmap, offset, data);
-}
-
static int iadc_reset(struct iadc_chip *iadc)
{
- u8 data;
+ u32 data;
int ret;
- ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
+ ret = regmap_write(iadc->regmap, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
if (ret < 0)
return ret;
- ret = iadc_read(iadc, IADC_PERH_RESET_CTL3, &data);
+ ret = regmap_read(iadc->regmap, IADC_PERH_RESET_CTL3, &data);
if (ret < 0)
return ret;
- ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
+ ret = regmap_write(iadc->regmap, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
if (ret < 0)
return ret;
data |= IADC_FOLLOW_WARM_RB;
- return iadc_write(iadc, IADC_PERH_RESET_CTL3, data);
+ return regmap_write(iadc->regmap, IADC_PERH_RESET_CTL3, data);
}
static int iadc_set_state(struct iadc_chip *iadc, bool state)
{
- return iadc_write(iadc, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0);
+ return regmap_write(iadc->regmap, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0);
}
static void iadc_status_show(struct iadc_chip *iadc)
{
- u8 mode, sta1, chan, dig, en, req;
+ u32 mode, sta1, chan, dig, en, req;
int ret;
- ret = iadc_read(iadc, IADC_MODE_CTL, &mode);
+ ret = regmap_read(iadc->regmap, IADC_MODE_CTL, &mode);
if (ret < 0)
return;
- ret = iadc_read(iadc, IADC_DIG_PARAM, &dig);
+ ret = regmap_read(iadc->regmap, IADC_DIG_PARAM, &dig);
if (ret < 0)
return;
- ret = iadc_read(iadc, IADC_CH_SEL_CTL, &chan);
+ ret = regmap_read(iadc->regmap, IADC_CH_SEL_CTL, &chan);
if (ret < 0)
return;
- ret = iadc_read(iadc, IADC_CONV_REQ, &req);
+ ret = regmap_read(iadc->regmap, IADC_CONV_REQ, &req);
if (ret < 0)
return;
- ret = iadc_read(iadc, IADC_STATUS1, &sta1);
+ ret = regmap_read(iadc->regmap, IADC_STATUS1, &sta1);
if (ret < 0)
return;
- ret = iadc_read(iadc, IADC_EN_CTL1, &en);
+ ret = regmap_read(iadc->regmap, IADC_EN_CTL1, &en);
if (ret < 0)
return;
@@ -199,34 +181,34 @@ static int iadc_configure(struct iadc_chip *iadc, int channel)
/* Mode selection */
mode = (IADC_OP_MODE_NORMAL << IADC_OP_MODE_SHIFT) | IADC_TRIM_EN;
- ret = iadc_write(iadc, IADC_MODE_CTL, mode);
+ ret = regmap_write(iadc->regmap, IADC_MODE_CTL, mode);
if (ret < 0)
return ret;
/* Channel selection */
- ret = iadc_write(iadc, IADC_CH_SEL_CTL, channel);
+ ret = regmap_write(iadc->regmap, IADC_CH_SEL_CTL, channel);
if (ret < 0)
return ret;
/* Digital parameter setup */
decim = IADC_DEF_DECIMATION << IADC_DIG_DEC_RATIO_SEL_SHIFT;
- ret = iadc_write(iadc, IADC_DIG_PARAM, decim);
+ ret = regmap_write(iadc->regmap, IADC_DIG_PARAM, decim);
if (ret < 0)
return ret;
/* HW settle time delay */
- ret = iadc_write(iadc, IADC_HW_SETTLE_DELAY, IADC_DEF_HW_SETTLE_TIME);
+ ret = regmap_write(iadc->regmap, IADC_HW_SETTLE_DELAY, IADC_DEF_HW_SETTLE_TIME);
if (ret < 0)
return ret;
- ret = iadc_write(iadc, IADC_FAST_AVG_CTL, IADC_DEF_AVG_SAMPLES);
+ ret = regmap_write(iadc->regmap, IADC_FAST_AVG_CTL, IADC_DEF_AVG_SAMPLES);
if (ret < 0)
return ret;
if (IADC_DEF_AVG_SAMPLES)
- ret = iadc_write(iadc, IADC_FAST_AVG_EN, IADC_FAST_AVG_EN_SET);
+ ret = regmap_write(iadc->regmap, IADC_FAST_AVG_EN, IADC_FAST_AVG_EN_SET);
else
- ret = iadc_write(iadc, IADC_FAST_AVG_EN, 0);
+ ret = regmap_write(iadc->regmap, IADC_FAST_AVG_EN, 0);
if (ret < 0)
return ret;
@@ -239,19 +221,19 @@ static int iadc_configure(struct iadc_chip *iadc, int channel)
return ret;
/* Request conversion */
- return iadc_write(iadc, IADC_CONV_REQ, IADC_CONV_REQ_SET);
+ return regmap_write(iadc->regmap, IADC_CONV_REQ, IADC_CONV_REQ_SET);
}
static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us)
{
unsigned int count, retry;
+ u32 sta1;
int ret;
- u8 sta1;
retry = interval_us / IADC_CONV_TIME_MIN_US;
for (count = 0; count < retry; count++) {
- ret = iadc_read(iadc, IADC_STATUS1, &sta1);
+ ret = regmap_read(iadc->regmap, IADC_STATUS1, &sta1);
if (ret < 0)
return ret;
@@ -267,11 +249,6 @@ static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us)
return -ETIMEDOUT;
}
-static int iadc_read_result(struct iadc_chip *iadc, u16 *data)
-{
- return regmap_bulk_read(iadc->regmap, IADC_DATA, data, 2);
-}
-
static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
{
unsigned int wait;
@@ -296,7 +273,7 @@ static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
}
if (!ret)
- ret = iadc_read_result(iadc, data);
+ ret = regmap_bulk_read(iadc->regmap, IADC_DATA, data, sizeof(*data));
exit:
iadc_set_state(iadc, false);
if (ret < 0)
@@ -392,33 +369,33 @@ static int iadc_update_offset(struct iadc_chip *iadc)
static int iadc_version_check(struct iadc_chip *iadc)
{
- u8 val;
+ u32 val;
int ret;
- ret = iadc_read(iadc, IADC_PERPH_TYPE, &val);
+ ret = regmap_read(iadc->regmap, IADC_PERPH_TYPE, &val);
if (ret < 0)
return ret;
if (val < IADC_PERPH_TYPE_ADC) {
- dev_err(iadc->dev, "%d is not ADC\n", val);
+ dev_err(iadc->dev, "%u is not ADC\n", val);
return -EINVAL;
}
- ret = iadc_read(iadc, IADC_PERPH_SUBTYPE, &val);
+ ret = regmap_read(iadc->regmap, IADC_PERPH_SUBTYPE, &val);
if (ret < 0)
return ret;
if (val < IADC_PERPH_SUBTYPE_IADC) {
- dev_err(iadc->dev, "%d is not IADC\n", val);
+ dev_err(iadc->dev, "%u is not IADC\n", val);
return -EINVAL;
}
- ret = iadc_read(iadc, IADC_REVISION2, &val);
+ ret = regmap_read(iadc->regmap, IADC_REVISION2, &val);
if (ret < 0)
return ret;
if (val < IADC_REVISION2_SUPPORTED_IADC) {
- dev_err(iadc->dev, "revision %d not supported\n", val);
+ dev_err(iadc->dev, "revision %u not supported\n", val);
return -EINVAL;
}
@@ -428,7 +405,7 @@ static int iadc_version_check(struct iadc_chip *iadc)
static int iadc_rsense_read(struct iadc_chip *iadc, struct device_node *node)
{
int ret, sign, int_sense;
- u8 deviation;
+ u32 deviation;
ret = of_property_read_u32(node, "qcom,external-resistor-micro-ohms",
&iadc->rsense[IADC_EXT_RSENSE]);
@@ -440,7 +417,7 @@ static int iadc_rsense_read(struct iadc_chip *iadc, struct device_node *node)
return -EINVAL;
}
- ret = iadc_read(iadc, IADC_NOMINAL_RSENSE, &deviation);
+ ret = regmap_read(iadc->regmap, IADC_NOMINAL_RSENSE, &deviation);
if (ret < 0)
return ret;
@@ -511,7 +488,10 @@ static int iadc_probe(struct platform_device *pdev)
iadc = iio_priv(indio_dev);
iadc->dev = dev;
- sparent = to_spmi_device(dev->parent);
+ sparent = spmi_find_device_by_of_node(dev->parent->of_node);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
+
sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
if (IS_ERR(sub_sdev))
return PTR_ERR(sub_sdev);
--
2.54.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path
2026-07-07 8:37 ` [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path AngeloGioacchino Del Regno
@ 2026-07-07 8:48 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:48 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: olteanv, vkoul, neil.armstrong, linux-phy
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] If `ida_alloc()` fails in `spmi_controller_alloc()`, the error path incorrectly frees ID 0.
--
--- Patch [4]: [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path ---
commit 46c20d4429e15ea3e907f6068ddedd7ed9c940f8
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
spmi: Remove unneeded goto in spmi_device_add() error path
This commit simplifies the error handling in spmi_device_add() by removing an
unnecessary goto statement and returning directly on failure. It also explicitly
returns 0 on success to improve code readability.
> diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> index fa3323521f1a2..cae89dd915d4a 100644
> --- a/drivers/spmi/spmi.c
> +++ b/drivers/spmi/spmi.c
[ ... ]
[Severity: High]
This is a pre-existing issue, but does the spmi_controller_alloc() error path
incorrectly free ID 0 if ida_alloc() fails?
Looking at spmi_controller_alloc():
ctrl = kzalloc_flex(*ctrl, priv, size);
/* ctrl->nr is implicitly 0 */
/* ... */
id = ida_alloc(&ctrl_ida, GFP_KERNEL);
if (id < 0) {
dev_err(parent,
"unable to allocate SPMI controller identifier.\n");
spmi_controller_put(ctrl);
return ERR_PTR(id);
}
If ida_alloc() returns an error code, spmi_controller_put(ctrl) is called
while ctrl->nr is still 0. This drops the reference and triggers the release
function:
drivers/spmi/spmi.c:spmi_ctrl_release() {
struct spmi_controller *ctrl = to_spmi_controller(dev);
ida_free(&ctrl_ida, ctrl->nr);
kfree(ctrl);
}
Could this cause ida_free() to unconditionally free ID 0, potentially
corrupting the global IDA state if another SPMI controller is actively using
that identifier?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=4
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant
2026-07-07 8:37 ` [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant AngeloGioacchino Del Regno
@ 2026-07-07 8:48 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:48 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: olteanv, neil.armstrong, vkoul, linux-phy
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] spmi_subdevice_alloc_and_add() fuses allocation and registration, preventing initialization of device properties (e.g., of_node, fwnode) before device discovery.
--
--- Patch [5]: [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant ---
commit c893fdf928479eb51fde233e27eea04fa096cc24
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
spmi: Implement spmi_subdevice_alloc_and_add() and devm variant
This commit introduces new functions to allocate and register sub-devices
for SPMI devices, along with their devm_* equivalents. The exports are
placed under the "SPMI" namespace.
> diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> index cae89dd915d4a..cd047aba38ab1 100644
> --- a/drivers/spmi/spmi.c
> +++ b/drivers/spmi/spmi.c
[ ... ]
> @@ -431,6 +457,58 @@ struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl)
> }
> EXPORT_SYMBOL_GPL(spmi_device_alloc);
>
> +/**
> + * spmi_subdevice_alloc_and_add(): Allocate and add a new SPMI sub-device
> + * @sparent: SPMI parent device with previously registered SPMI controller
> + *
> + * Returns:
> + * Pointer to newly allocated SPMI sub-device for success or error pointer.
> + */
> +struct spmi_subdevice *spmi_subdevice_alloc_and_add(struct spmi_device *sparent)
> +{
> + struct spmi_subdevice *sub_sdev;
> + struct spmi_device *sdev;
> + int ret;
[ ... ]
> + ret = dev_set_name(&sdev->dev, "%u-%02x.%u.auto",
> + sdev->ctrl->nr, sdev->usid, sub_sdev->devid);
> + if (ret)
> + goto err_put_dev;
> +
> + ret = device_add(&sdev->dev);
[Severity: High]
By combining allocation and registration into a single function, doesn't this
prevent the caller from initializing device properties like of_node or fwnode
before the device is discovered?
If device_add() is called immediately, the initial KOBJ_ADD uevent will be
emitted without a MODALIAS, which can break module autoloading. Furthermore,
fw_devlink might fail to correctly establish device links, and
spmi_device_match() is likely to unconditionally fail to find a matching driver
during the initial bus_probe_device() since of_node is NULL.
Would it be better to split this into separate alloc and add operations so the
caller can safely configure the device properties before adding it to the system?
> + if (ret) {
> + dev_err(&sdev->dev, "Can't add device, status %pe\n", ERR_PTR(ret));
> + goto err_put_dev;
> + }
> +
> + return sub_sdev;
> +
> +err_put_dev:
> + put_device(&sdev->dev);
> + return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_NS_GPL(spmi_subdevice_alloc_and_add, "SPMI");
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 07/11] power: reset: qcom-pon: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 ` [PATCH v10 07/11] power: reset: qcom-pon: " AngeloGioacchino Del Regno
@ 2026-07-07 8:49 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:49 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: neil.armstrong, vkoul, linux-phy, olteanv
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The SPMI parent device reference acquired by `spmi_find_device_by_of_node()` is permanently leaked on both success and error paths.
- [Low] Returning a pointer (`ERR_PTR(-ENODEV)`) from a function with an `int` return type.
--
--- Patch [7]: [PATCH v10 07/11] power: reset: qcom-pon: Migrate to devm_spmi_subdevice_alloc_and_add() ---
commit 7acdc04479f1ecdcac3a3f4d2ef16b8d339d843d
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
power: reset: qcom-pon: Migrate to devm_spmi_subdevice_alloc_and_add()
This commit migrates the Qualcomm PON driver to register an SPMI sub-device
and initialize a specific regmap. This allows the driver to avoid manually
adding the base address to every read/write call.
> diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
> index 7e108982a582e..f94aaecd6ed67 100644
> --- a/drivers/power/reset/qcom-pon.c
> +++ b/drivers/power/reset/qcom-pon.c
[ ... ]
> @@ -46,27 +46,44 @@ static int qcom_pon_reboot_mode_write(struct reboot_mode_driver *reboot,
>
> static int qcom_pon_probe(struct platform_device *pdev)
> {
[ ... ]
> + if (!dev->parent)
> + return -ENODEV;
>
> pon = devm_kzalloc(&pdev->dev, sizeof(*pon), GFP_KERNEL);
> if (!pon)
> return -ENOMEM;
>
> pon->dev = &pdev->dev;
>
> - pon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> - if (!pon->regmap) {
> - dev_err(&pdev->dev, "failed to locate regmap\n");
> - return -ENODEV;
> - }
> + sparent = spmi_find_device_by_of_node(dev->parent->of_node);
> + if (!sparent)
> + return ERR_PTR(-ENODEV);
[Severity: Low]
Does this code return a pointer from a function that returns an integer?
qcom_pon_probe() has an int return type, so returning ERR_PTR(-ENODEV)
causes an implicit pointer-to-integer conversion and a build warning.
Should this just return -ENODEV?
(Note: A similar type conversion appears to exist in sdam_probe() in
drivers/nvmem/qcom-spmi-sdam.c)
[Severity: Medium]
Does this leak the device reference acquired by spmi_find_device_by_of_node()?
spmi_find_device_by_of_node() increments the reference count of the SPMI
parent device, but it appears put_device(&sparent->dev) is never called
on either the success or error paths to release it.
(Note: This same reference leak pattern also appears to be duplicated in
sdam_probe() in drivers/nvmem/qcom-spmi-sdam.c)
>
> - error = of_property_read_u32(pdev->dev.of_node, "reg",
> - &pon->baseaddr);
> + sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=7
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 ` [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() AngeloGioacchino Del Regno
@ 2026-07-07 8:50 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:50 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: linux-phy, vkoul, neil.armstrong, olteanv
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] The reference to the parent SPMI device acquired via `spmi_find_device_by_of_node()` is leaked on both success and error paths.
- [Low] Returning a pointer (`ERR_PTR`) from an integer-returning function causes a type mismatch and build warning.
Pre-existing issues:
- [High] The upper half of the SDAM memory cannot be accessed via the nvmem API due to a bound restriction mismatch.
--
--- Patch [6]: [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() ---
commit 8fe2831bc2e512389dd631ef16ab000bbe8f6706
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add()
Some Qualcomm PMICs integrate a SDAM device, internally located in
a specific address range reachable through SPMI communication.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device for SDAM
and initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
> diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
> index 4f1cca6eab71e..3ad842676dde5 100644
> --- a/drivers/nvmem/qcom-spmi-sdam.c
> +++ b/drivers/nvmem/qcom-spmi-sdam.c
[ ... ]
> @@ -110,28 +110,47 @@ static int sdam_write(void *priv, unsigned int offset, void *val,
>
> static int sdam_probe(struct platform_device *pdev)
> {
> + struct regmap_config sdam_regmap_config = {
> + .reg_bits = 16,
> + .val_bits = 8,
> + .max_register = 0xff,
> + .fast_io = true,
> + };
> struct sdam_chip *sdam;
> struct nvmem_device *nvmem;
> + struct spmi_device *sparent;
> + struct spmi_subdevice *sub_sdev;
> + struct device *dev = &pdev->dev;
> unsigned int val;
> int rc;
>
> + if (!dev->parent)
> + return -ENODEV;
> +
> sdam = devm_kzalloc(&pdev->dev, sizeof(*sdam), GFP_KERNEL);
> if (!sdam)
> return -ENOMEM;
>
> - sdam->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> - if (!sdam->regmap) {
> - dev_err(&pdev->dev, "Failed to get regmap handle\n");
> - return -ENXIO;
> - }
> + sparent = spmi_find_device_by_of_node(dev->parent->of_node);
> + if (!sparent)
> + return ERR_PTR(-ENODEV);
[Severity: Low]
Does returning ERR_PTR(-ENODEV) here cause a compiler warning?
Since sdam_probe() returns an int, this implicitly casts a pointer to an
integer. This triggers a -Wint-conversion warning, which results in a build
failure on modern compiler configurations using -Werror=int-conversion.
[Severity: High]
Does this code leak the sparent device reference?
spmi_find_device_by_of_node() internally invokes bus_find_device_by_of_node(),
which returns a device with an incremented reference count via get_device().
I don't see a corresponding put_device(&sparent->dev) on the success or
error paths before returning from sdam_probe(). Because
devm_spmi_subdevice_alloc_and_add() registers the device but does not assume
ownership of this specific reference, the parent PMIC device object appears
to be permanently leaked on every probe.
> +
> + sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
> + if (IS_ERR(sub_sdev))
> + return PTR_ERR(sub_sdev);
[ ... ]
> @@ -159,7 +178,7 @@ static int sdam_probe(struct platform_device *pdev)
> }
> dev_dbg(&pdev->dev,
> "SDAM base=%#x size=%u registered successfully\n",
> - sdam->base, sdam->size);
> + sdam_regmap_config.reg_base, sdam->size);
[Severity: High]
This is a pre-existing issue, but does setting the nvmem framework size limit
to sdam->size earlier in this function restrict the maximum readable offsets
incorrectly?
The driver maps physical memory starting at SDAM_MEM_START (0x40), and
sdam_is_valid() mandates that the input offset must be >= 0x40.
However, configuring sdam->sdam_config.size = sdam->size forces nvmem
consumers to pass an offset strictly less than sdam->size. This permits
access to only a fraction of the intended size, completely blocking access
to the upper portion of the SDAM memory block which are valid physical
SDAM registers approved by sdam_is_valid().
>
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=6
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 ` [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: " AngeloGioacchino Del Regno
@ 2026-07-07 8:51 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:51 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: vkoul, neil.armstrong, linux-phy, olteanv
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Leak of the SPMI parent device reference obtained from spmi_find_device_by_of_node().
- [Low] Type mismatch causing a build warning/error: returning a pointer from a function with an integer return type.
--
--- Patch [8]: [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: Migrate to devm_spmi_subdevice_alloc_and_add() ---
commit e125fa6d40c28f38023d56b9eb34e9de7e9957fc
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
phy: qualcomm: eusb2-repeater: Migrate to devm_spmi_subdevice_alloc_and_add()
This patch modifies the Qualcomm eUSB2 repeater driver to register a new SPMI
sub-device instead of using the parent SPMI device. It initializes a regmap
with this sub-device's specific base address retrieved from the devicetree,
allowing the regmap API to handle the register base address implicitly.
> diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
> index efeec4709a15d..f99152cf59849 100644
> --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
> +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
[ ... ]
> @@ -260,15 +268,21 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
> if (!rptr->cfg)
> return -EINVAL;
>
> - rptr->regmap = dev_get_regmap(dev->parent, NULL);
> - if (!rptr->regmap)
> - return -ENODEV;
> + sparent = spmi_find_device_by_of_node(dev->parent->of_node);
> + if (!sparent)
> + return ERR_PTR(-ENODEV);
[Severity: Medium]
Does this code leak the device reference returned by
spmi_find_device_by_of_node()?
The function spmi_find_device_by_of_node() increments the reference count of
the returned device, but it appears this reference is never released via
put_device() on either the success or error paths before returning from
eusb2_repeater_probe().
[Severity: Low]
Does this code return a pointer from a function declared to return an int?
The eusb2_repeater_probe() function returns int, but this error path returns
ERR_PTR(-ENODEV), which might cause a type mismatch warning or build failure.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=8
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference
2026-07-07 8:37 ` [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference AngeloGioacchino Del Regno
@ 2026-07-07 8:53 ` sashiko-bot
2026-07-07 9:07 ` Andy Shevchenko
1 sibling, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:53 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: linux-phy, olteanv, neil.armstrong, vkoul
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Premature release of the OF node reference in `spmi_device_remove()` causes a use-after-free during device unregistration.
Pre-existing issues:
- [High] If `ida_alloc()` fails in `spmi_controller_alloc()`, the error path erroneously frees ID 0.
--
--- Patch [1]: [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference ---
commit 32b4e0545e66d81a2191ec48ea0cb9fc1e026b1c
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
spmi: Fix potential use-after-free by grabbing of_node reference
This patch increases the of_node refcount when assigning in
of_spmi_register_devices() and releases it in spmi_device_remove() to fix a
potential use-after-free during dynamic overlay unloading.
Link: https://sashiko.dev/#/patchset/20260608100949.36309-1-angelogioacchino.delregno@collabora.com?part=2
> diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> index 57b7c0cb42407..6e701aff60454 100644
> --- a/drivers/spmi/spmi.c
> +++ b/drivers/spmi/spmi.c
> @@ -86,6 +86,9 @@ EXPORT_SYMBOL_GPL(spmi_device_add);
> */
> void spmi_device_remove(struct spmi_device *sdev)
> {
> + if (IS_ENABLED(CONFIG_OF))
> + of_node_put(sdev->dev.of_node);
> +
> device_unregister(&sdev->dev);
> }
[Severity: High]
Could this prematurely release the OF node reference?
By dropping the reference before device_unregister() completes, this seems to
risk a use-after-free. During device_unregister(), device_del() is called and
the driver core emits a KOBJ_REMOVE uevent. This triggers the bus callback
spmi_drv_uevent(), which calls of_device_uevent_modalias() where it directly
dereferences the freed dev->of_node to read the compatible string.
Would it be better to drop the OF node reference in spmi_dev_release() so it
is bound to the device's lifetime? (If moved there, the manual of_node_put()
in the spmi_device_add() error path might need to be removed to prevent a
double-free).
[ ... ]
[Severity: High]
This isn't a bug introduced by this patch, but I noticed a potential problem
in the error handling for spmi_controller_alloc().
drivers/spmi/spmi.c:spmi_controller_alloc() {
...
ctrl = kzalloc_flex(*ctrl, priv, size);
...
id = ida_alloc(&ctrl_ida, GFP_KERNEL);
if (id < 0) {
dev_err(parent,
"unable to allocate SPMI controller identifier.\n");
spmi_controller_put(ctrl);
return ERR_PTR(id);
}
...
}
If ida_alloc() fails, wouldn't this error path inadvertently free ID 0?
Since kzalloc_flex() zero-initializes ctrl->nr, an ida_alloc() failure will
call spmi_controller_put(ctrl) while ctrl->nr is still 0. This triggers the
spmi_ctrl_release() callback:
drivers/spmi/spmi.c:spmi_ctrl_release() {
...
ida_free(&ctrl_ida, ctrl->nr);
kfree(ctrl);
}
Because it unconditionally frees ctrl->nr, ID 0 is released. If ID 0 was
already assigned to another SPMI controller, this could cause its ID to be
erroneously marked as available, potentially leading to a sysfs naming
collision ('spmi-0') during the next controller allocation.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions
2026-07-07 8:37 ` [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions AngeloGioacchino Del Regno
@ 2026-07-07 8:55 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:55 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: vkoul, linux-phy, olteanv, neil.armstrong
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The reference count of the parent SPMI device obtained via `spmi_find_device_by_of_node()` is never dropped, causing a memory and device reference leak.
- [Low] Type mismatch in `iadc_probe`: returning `ERR_PTR(-ENODEV)` instead of `-ENODEV`.
--
--- Patch [11]: [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions ---
commit 2cc2678cec6d923731a39311dff1c18e6f022adf
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions
This commit simplifies the driver by removing custom regmap read/write
wrappers and directly calling the regmap APIs. It also migrates the driver
to register as a SPMI subdevice to handle the base address internally.
> diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
> index ad66bb92fe19c..84c2bd27367fd 100644
> --- a/drivers/iio/adc/qcom-spmi-iadc.c
> +++ b/drivers/iio/adc/qcom-spmi-iadc.c
[ ... ]
> @@ -511,7 +488,10 @@ static int iadc_probe(struct platform_device *pdev)
> iadc = iio_priv(indio_dev);
> iadc->dev = dev;
>
> - sparent = to_spmi_device(dev->parent);
> + sparent = spmi_find_device_by_of_node(dev->parent->of_node);
[Severity: High]
Does this leak the device reference?
spmi_find_device_by_of_node() returns a device with its reference count
incremented, but it doesn't appear that put_device() is ever called to
release it within iadc_probe() on either the success or error paths.
> + if (!sparent)
> + return ERR_PTR(-ENODEV);
[Severity: Low]
Does this need to return -ENODEV directly instead of using ERR_PTR()?
Since iadc_probe() returns an int, returning ERR_PTR(-ENODEV) causes a type
mismatch and a compiler warning.
> +
> sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
> if (IS_ERR(sub_sdev))
> return PTR_ERR(sub_sdev);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=11
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 09/11] misc: qcom-coincell: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 ` [PATCH v10 09/11] misc: qcom-coincell: " AngeloGioacchino Del Regno
@ 2026-07-07 8:56 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 8:56 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: olteanv, vkoul, linux-phy, neil.armstrong
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Leaked device reference count for the parent SPMI device acquired via spmi_find_device_by_of_node().
- [Low] Returning a pointer (`ERR_PTR(-ENODEV)`) from a function with an `int` return type.
--
--- Patch [9]: [PATCH v10 09/11] misc: qcom-coincell: Migrate to devm_spmi_subdevice_alloc_and_add() ---
commit d4a4d2ba5d9e18044bfae04039df8731e13ea2f2
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
misc: qcom-coincell: Migrate to devm_spmi_subdevice_alloc_and_add()
This commit migrates the coincell charger driver to use the new
devm_spmi_subdevice_alloc_and_add() API. It registers a new SPMI
sub-device and initializes its own regmap.
> diff --git a/drivers/misc/qcom-coincell.c b/drivers/misc/qcom-coincell.c
> index 3c57f74291476..46340f0199cdc 100644
> --- a/drivers/misc/qcom-coincell.c
> +++ b/drivers/misc/qcom-coincell.c
[ ... ]
> @@ -71,37 +71,58 @@ static int qcom_coincell_probe(struct platform_device *pdev)
> {
[ ... ]
> - rc = of_property_read_u32(node, "reg", &chgr.base_addr);
> + rc = device_property_read_u32(dev, "reg", &qcom_coincell_regmap_config.reg_base);
> if (rc)
> return rc;
>
> + sparent = spmi_find_device_by_of_node(dev->parent->of_node);
> + if (!sparent)
> + return ERR_PTR(-ENODEV);
[Severity: Low]
The qcom_coincell_probe() function returns an int, but ERR_PTR(-ENODEV)
constructs a pointer. Will this cause a compiler error for implicit
pointer-to-integer conversion?
[Severity: Medium]
The spmi_find_device_by_of_node() function acquires a reference to the parent
SPMI device. Since devm_spmi_subdevice_alloc_and_add() does not consume this
reference, does this code leak the device reference by never calling
put_device() to release it?
These same return type mismatches and reference leaks also appear to be
present in the probe functions for qcom-spmi-sdam.c, qcom-pon.c, and
phy-qcom-eusb2-repeater.c introduced by this patchset.
> +
> + sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
> + if (IS_ERR(sub_sdev))
> + return PTR_ERR(sub_sdev);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=9
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: Migrate to devm_spmi_subdevice_alloc_and_add()
2026-07-07 8:37 ` [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: " AngeloGioacchino Del Regno
@ 2026-07-07 9:03 ` sashiko-bot
0 siblings, 0 replies; 22+ messages in thread
From: sashiko-bot @ 2026-07-07 9:03 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: olteanv, neil.armstrong, linux-phy, vkoul
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Blind cast of `dev->parent` to `struct spmi_device` bypassing bus type validation can lead to a type confusion vulnerability and kernel panic.
--
--- Patch [10]: [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: Migrate to devm_spmi_subdevice_alloc_and_add() ---
commit e1eedb072014331c1e52822eb31e7a9aaeb3e848
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
iio: adc: qcom-spmi-iadc: Migrate to devm_spmi_subdevice_alloc_and_add()
This commit changes the driver to register a new SPMI sub-device and
initialize its own regmap rather than using the parent SPMI device's
regmap. This allows the regmap API to handle the base address directly.
> diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c
> --- a/drivers/iio/adc/qcom-spmi-iadc.c
> +++ b/drivers/iio/adc/qcom-spmi-iadc.c
[ ... ]
> @@ -502,18 +511,21 @@ static int iadc_probe(struct platform_device *pdev)
> iadc = iio_priv(indio_dev);
> iadc->dev = dev;
>
> - iadc->regmap = dev_get_regmap(dev->parent, NULL);
> - if (!iadc->regmap)
> - return -ENODEV;
> + sparent = to_spmi_device(dev->parent);
> + sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
[Severity: High]
Could this blind cast to struct spmi_device cause a kernel panic if the
parent device isn't actually on the SPMI bus?
If a customized device tree or overlay instantiates this driver under a
non-SPMI parent node (for example, directly under simple-bus), dev->parent
will not be a valid spmi_device. When subdevice allocation accesses
sparent->ctrl, it will read memory overlapping with the parent's actual
structure, which can lead to an invalid pointer dereference.
The previous implementation safely handled this via dev_get_regmap(), but
this new cast bypasses bus type validation. Would it be better to use
spmi_find_device_by_of_node() here, similar to how it is used in other
drivers in this patch series, to ensure the device is safely retrieved?
> + if (IS_ERR(sub_sdev))
> + return PTR_ERR(sub_sdev);
>
> init_completion(&iadc->complete);
> mutex_init(&iadc->lock);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707083730.33977-1-angelogioacchino.delregno@collabora.com?part=10
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference
2026-07-07 8:37 ` [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference AngeloGioacchino Del Regno
2026-07-07 8:53 ` sashiko-bot
@ 2026-07-07 9:07 ` Andy Shevchenko
1 sibling, 0 replies; 22+ messages in thread
From: Andy Shevchenko @ 2026-07-07 9:07 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: jic23, sboyd, dlechner, nuno.sa, andy, arnd, gregkh, srini, vkoul,
neil.armstrong, sre, krzk, dmitry.baryshkov, quic_wcheng,
melody.olvera, quic_nsekar, ivo.ivanov.ivanov1, abelvesa,
luca.weiss, konrad.dybcio, mitltlatltl, krishna.kurapati,
linux-arm-msm, linux-iio, linux-kernel, linux-phy, linux-pm,
kernel, stable, Sashiko Bot
On Tue, Jul 07, 2026 at 10:37:20AM +0200, AngeloGioacchino Del Regno wrote:
> As noticed by Sashiko during a review run of an unrelated patch,
> in of_spmi_register_devices(), for_each_available_child_of_node()
> is used to loop through children, and to also assign a node to a
> newly created SPMI child device.
>
> Problem is that the refcount is dropped at every iteration so, in
> the specific case of DT overlays, a use-after-free may occur when
> an overlay is dynamically unloaded!
>
> To resolve this, increase the of_node refcount when assigning (in
> function of_spmi_register_devices) and release the reference in
> spmi_device_remove().
...
> void spmi_device_remove(struct spmi_device *sdev)
> {
> + if (IS_ENABLED(CONFIG_OF))
Unneeded check.
> + of_node_put(sdev->dev.of_node);
> +
> device_unregister(&sdev->dev);
> }
--
With Best Regards,
Andy Shevchenko
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-07-07 9:07 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 8:37 [PATCH v10 00/11] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 01/11] spmi: Fix potential use-after-free by grabbing of_node reference AngeloGioacchino Del Regno
2026-07-07 8:53 ` sashiko-bot
2026-07-07 9:07 ` Andy Shevchenko
2026-07-07 8:37 ` [PATCH v10 02/11] spmi: Remove redundant dev_name() print in spmi_device_add() AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 03/11] spmi: Print error status with %pe format AngeloGioacchino Del Regno
2026-07-07 8:37 ` [PATCH v10 04/11] spmi: Remove unneeded goto in spmi_device_add() error path AngeloGioacchino Del Regno
2026-07-07 8:48 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 05/11] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant AngeloGioacchino Del Regno
2026-07-07 8:48 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 06/11] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() AngeloGioacchino Del Regno
2026-07-07 8:50 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 07/11] power: reset: qcom-pon: " AngeloGioacchino Del Regno
2026-07-07 8:49 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 08/11] phy: qualcomm: eusb2-repeater: " AngeloGioacchino Del Regno
2026-07-07 8:51 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 09/11] misc: qcom-coincell: " AngeloGioacchino Del Regno
2026-07-07 8:56 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 10/11] iio: adc: qcom-spmi-iadc: " AngeloGioacchino Del Regno
2026-07-07 9:03 ` sashiko-bot
2026-07-07 8:37 ` [PATCH v10 11/11] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions AngeloGioacchino Del Regno
2026-07-07 8:55 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox