Re: [PATCH v2 1/4] soc: qcom: rpmh: Allow non-child devices to issue write commands
From: Dmitry Baryshkov
Date: Mon Jun 01 2026 - 09:37:59 EST
On Thu, May 28, 2026 at 06:05:35PM -0700, Fenglin Wu wrote:
> Currently, the RPMH driver only allows child devices of the RPMH
> controller to issue commands, as it assumes dev->parent points to the
> RSC device.
>
> There is a possibility that certain devices which are not children of
> the RPMH controller want to send commands for special control at the
> RPMH side. For example, in PMH0101 PMICs, there are bidirectional
> level shifter (LS) peripherals, and each LS works with a pair of PMIC
> GPIOs. The control of the LS, which is combined with the GPIO
> configuration, is handled by RPMH firmware for sharing the resource
> between different subsystems. From a hardware point of view, the LS
> functionality is tied to a pair of PMIC GPIOs, so its control is more
> suitable to be added in the pinctrl-spmi-gpio driver by adding the
> level-shifter function. However, the pinctrl-spmi-gpio device is a
> child device of the SPMI controller, not the RPMH controller.
This replicates the story of the PMIC regulators. There are two drivers,
one SPMI and one RPMh. Why don't we add a separate, RPMh-based GPIO
driver targeting only those paired GPIOs (and we don't even need to
represent them as a pair, it might be just one pin).
> This patch extends the RPMH driver to support write commands from any
> device that has a pointer to the RPMH controller device:
>
> 1. Add rpmh_get_ctrlr_dev() to lookup controller via device tree
> phandle "qcom,rpmh"
> 2. Add new APIs: rpmh_write_async_ctrlr() and rpmh_write_ctrlr()
> that accept controller device pointer directly
>
> With this change, the pinctrl-spmi-gpio driver is able to issue write
> commands to the RPMH controller by using the controller device pointer,
> and vote for enabling the level-shifter function.
>
> Signed-off-by: Fenglin Wu <fenglin.wu@xxxxxxxxxxxxxxxx>
> ---
> drivers/soc/qcom/rpmh.c | 173 +++++++++++++++++++++++++++++++++++++++++++-----
> include/soc/qcom/rpmh.h | 21 ++++++
> 2 files changed, 179 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
> index ca37da3dc2b1..9dbc42b775d9 100644
> --- a/drivers/soc/qcom/rpmh.c
> +++ b/drivers/soc/qcom/rpmh.c
> @@ -12,6 +12,7 @@
> #include <linux/lockdep.h>
> #include <linux/module.h>
> #include <linux/of.h>
> +#include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> @@ -76,6 +77,21 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
> return &drv->client;
> }
>
> +static struct rpmh_ctrlr *get_rpmh_ctrlr_from_dev(const struct device *ctrl_dev)
> +{
> + struct rsc_drv *drv;
> +
> + if (!ctrl_dev)
> + return ERR_PTR(-EINVAL);
> +
> + drv = dev_get_drvdata(ctrl_dev);
This is racy, because the drvdata can disappear at any point. Having the
handle of the device doesn't help because the driver can be unbound even
if we have the reference on the device.
It's not the case for RPMh (which if unbound will break a lot of
devices), but it's still a antipattern.
> +
> + if (!drv)
> + return ERR_PTR(-ENODEV);
> +
> + return &drv->client;
> +}
> +
> void rpmh_tx_done(const struct tcs_request *msg)
> {
> struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
> @@ -271,6 +294,126 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
> }
> EXPORT_SYMBOL_GPL(rpmh_write);
>
> +static void rpmh_put_device(void *data)
> +{
> + put_device(data);
> +}
> +
> +/**
> + * rpmh_get_ctrlr_dev: Get RPMH controller device from device tree
> + *
> + * @dev: Device with "qcom,rpmh" phandle property
> + *
> + * Returns: Pointer to RPMH controller device, with a devm action registered
> + * on @dev to release the reference when @dev is unbound.
> + */
> +struct device *rpmh_get_ctrlr_dev(struct device *dev)
> +{
> + struct device_node *rpmh_np;
> + struct platform_device *pdev;
> + struct device_link *link;
> + int ret;
> +
> + rpmh_np = of_parse_phandle(dev->of_node, "qcom,rpmh", 0);
Ugh. I think this kind of phandle properties are not recommended.
> + if (!rpmh_np)
> + return ERR_PTR(-ENODEV);
> +
> + pdev = of_find_device_by_node(rpmh_np);
> + of_node_put(rpmh_np);
> +
--
With best wishes
Dmitry