From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Cc: <sboyd@kernel.org>, <jic23@kernel.org>, <dlechner@baylibre.com>,
<nuno.sa@analog.com>, <andy@kernel.org>, <arnd@arndb.de>,
<gregkh@linuxfoundation.org>, <srini@kernel.org>,
<vkoul@kernel.org>, <kishon@kernel.org>, <sre@kernel.org>,
<krzysztof.kozlowski@linaro.org>, <u.kleine-koenig@baylibre.com>,
<linux-arm-msm@vger.kernel.org>, <linux-iio@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <linux-phy@lists.infradead.org>,
<linux-pm@vger.kernel.org>, <kernel@collabora.com>,
<wenst@chromium.org>, <casey.connolly@linaro.org>
Subject: Re: [PATCH v2 1/7] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant
Date: Tue, 22 Jul 2025 15:09:30 +0100 [thread overview]
Message-ID: <20250722150930.00000a2f@huawei.com> (raw)
In-Reply-To: <20250722101317.76729-2-angelogioacchino.delregno@collabora.com>
On Tue, 22 Jul 2025 12:13:11 +0200
AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> wrote:
> 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_put_and_remove()
> for adding a new subdevice and removing it respectively, and also
> add their devm_* variants.
>
> The need for such functions comes from the existance 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.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/spmi/spmi-devres.c | 23 +++++++++++
> drivers/spmi/spmi.c | 83 ++++++++++++++++++++++++++++++++++++++
> include/linux/spmi.h | 16 ++++++++
> 3 files changed, 122 insertions(+)
>
> diff --git a/drivers/spmi/spmi-devres.c b/drivers/spmi/spmi-devres.c
> index 62c4b3f24d06..7e00e38be2ff 100644
> --- a/drivers/spmi/spmi-devres.c
> +++ b/drivers/spmi/spmi-devres.c
> @@ -60,5 +60,28 @@ 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 *res)
> +{
> + spmi_subdevice_remove((struct spmi_subdevice *)res);
Why the cast? Implicit casts are fine for void * to any other pointer type
so
spmi_subdevice_remove(res);
should be fine.
> +}
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("SPMI devres helpers");
> diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> index 3cf8d9bd4566..62bb782b2bbc 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,18 @@ 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);
> +
> + 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 +103,19 @@ 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);
> + ida_free(&spmi_subdevice_ida, sub_sdev->devid);
Why not make the ida free part of the release? If not
the device_unregister could (I think) result in a reference
count drop and freeing of sub_sdev before you dereference it here.
> +}
> +EXPORT_SYMBOL_NS_GPL(spmi_subdevice_remove, "SPMI");
> +
> static inline int
> spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid)
> {
> @@ -431,6 +457,63 @@ 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 negative ERR_PTR.
> + */
> +struct spmi_subdevice *spmi_subdevice_alloc_and_add(struct spmi_device *sparent)
> +{
> + struct spmi_subdevice *sub_sdev;
> + struct spmi_device *sdev;
> + int ret;
> +
> + if (!sparent)
> + return ERR_PTR(-EINVAL);
Is this protecting against a real possibility? Feels like something went
very wrong if you are allocating a subdevice of 'nothing'.
If it's just defensive programming I'd drop it.
> +
> + sub_sdev = kzalloc(sizeof(*sub_sdev), GFP_KERNEL);
> + if (!sub_sdev)
> + return ERR_PTR(-ENOMEM);
> +
> + ret = ida_alloc(&spmi_subdevice_ida, GFP_KERNEL);
> + if (ret < 0)
> + goto err_ida_alloc;
> +
> + sdev = &sub_sdev->sdev;
> + sdev->ctrl = sparent->ctrl;
> + device_initialize(&sdev->dev);
Read the device_initialize() documentation for what you need to do
if an error occurs after this point. Specifically the last 'NOTE'.
> + sdev->dev.parent = &sparent->dev;
> + sdev->dev.bus = &spmi_bus_type;
> + sdev->dev.type = &spmi_subdev_type;
> +
> + sub_sdev->devid = ret;
> + sdev->usid = sparent->usid;
> +
> + ret = dev_set_name(&sdev->dev, "%d-%02x.%d.auto",
> + sdev->ctrl->nr, sdev->usid, sub_sdev->devid);
> + if (ret)
> + goto err_set_name;
> +
> + ret = device_add(&sdev->dev);
> + if (ret) {
> + dev_err(&sdev->dev, "Can't add %s, status %d\n",
> + dev_name(&sdev->dev), ret);
> + put_device(&sdev->dev);
> + return ERR_PTR(ret);
> + }
> +
> + return sub_sdev;
> +
> +err_set_name:
> + ida_free(&ctrl_ida, sub_sdev->devid);
> +err_ida_alloc:
> + kfree(sub_sdev);
> + 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 28e8c8bd3944..7cea0a5b034b 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;
Having something called a subdevice containing an instance of a device
does seem a little odd. Maybe the spmi_device naming is inappropriate after
this patch?
> + 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);
WARNING: multiple messages have this Message-ID (diff)
From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Cc: <sboyd@kernel.org>, <jic23@kernel.org>, <dlechner@baylibre.com>,
<nuno.sa@analog.com>, <andy@kernel.org>, <arnd@arndb.de>,
<gregkh@linuxfoundation.org>, <srini@kernel.org>,
<vkoul@kernel.org>, <kishon@kernel.org>, <sre@kernel.org>,
<krzysztof.kozlowski@linaro.org>, <u.kleine-koenig@baylibre.com>,
<linux-arm-msm@vger.kernel.org>, <linux-iio@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <linux-phy@lists.infradead.org>,
<linux-pm@vger.kernel.org>, <kernel@collabora.com>,
<wenst@chromium.org>, <casey.connolly@linaro.org>
Subject: Re: [PATCH v2 1/7] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant
Date: Tue, 22 Jul 2025 15:09:30 +0100 [thread overview]
Message-ID: <20250722150930.00000a2f@huawei.com> (raw)
In-Reply-To: <20250722101317.76729-2-angelogioacchino.delregno@collabora.com>
On Tue, 22 Jul 2025 12:13:11 +0200
AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> wrote:
> 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_put_and_remove()
> for adding a new subdevice and removing it respectively, and also
> add their devm_* variants.
>
> The need for such functions comes from the existance 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.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/spmi/spmi-devres.c | 23 +++++++++++
> drivers/spmi/spmi.c | 83 ++++++++++++++++++++++++++++++++++++++
> include/linux/spmi.h | 16 ++++++++
> 3 files changed, 122 insertions(+)
>
> diff --git a/drivers/spmi/spmi-devres.c b/drivers/spmi/spmi-devres.c
> index 62c4b3f24d06..7e00e38be2ff 100644
> --- a/drivers/spmi/spmi-devres.c
> +++ b/drivers/spmi/spmi-devres.c
> @@ -60,5 +60,28 @@ 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 *res)
> +{
> + spmi_subdevice_remove((struct spmi_subdevice *)res);
Why the cast? Implicit casts are fine for void * to any other pointer type
so
spmi_subdevice_remove(res);
should be fine.
> +}
> MODULE_LICENSE("GPL");
> MODULE_DESCRIPTION("SPMI devres helpers");
> diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> index 3cf8d9bd4566..62bb782b2bbc 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,18 @@ 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);
> +
> + 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 +103,19 @@ 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);
> + ida_free(&spmi_subdevice_ida, sub_sdev->devid);
Why not make the ida free part of the release? If not
the device_unregister could (I think) result in a reference
count drop and freeing of sub_sdev before you dereference it here.
> +}
> +EXPORT_SYMBOL_NS_GPL(spmi_subdevice_remove, "SPMI");
> +
> static inline int
> spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid)
> {
> @@ -431,6 +457,63 @@ 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 negative ERR_PTR.
> + */
> +struct spmi_subdevice *spmi_subdevice_alloc_and_add(struct spmi_device *sparent)
> +{
> + struct spmi_subdevice *sub_sdev;
> + struct spmi_device *sdev;
> + int ret;
> +
> + if (!sparent)
> + return ERR_PTR(-EINVAL);
Is this protecting against a real possibility? Feels like something went
very wrong if you are allocating a subdevice of 'nothing'.
If it's just defensive programming I'd drop it.
> +
> + sub_sdev = kzalloc(sizeof(*sub_sdev), GFP_KERNEL);
> + if (!sub_sdev)
> + return ERR_PTR(-ENOMEM);
> +
> + ret = ida_alloc(&spmi_subdevice_ida, GFP_KERNEL);
> + if (ret < 0)
> + goto err_ida_alloc;
> +
> + sdev = &sub_sdev->sdev;
> + sdev->ctrl = sparent->ctrl;
> + device_initialize(&sdev->dev);
Read the device_initialize() documentation for what you need to do
if an error occurs after this point. Specifically the last 'NOTE'.
> + sdev->dev.parent = &sparent->dev;
> + sdev->dev.bus = &spmi_bus_type;
> + sdev->dev.type = &spmi_subdev_type;
> +
> + sub_sdev->devid = ret;
> + sdev->usid = sparent->usid;
> +
> + ret = dev_set_name(&sdev->dev, "%d-%02x.%d.auto",
> + sdev->ctrl->nr, sdev->usid, sub_sdev->devid);
> + if (ret)
> + goto err_set_name;
> +
> + ret = device_add(&sdev->dev);
> + if (ret) {
> + dev_err(&sdev->dev, "Can't add %s, status %d\n",
> + dev_name(&sdev->dev), ret);
> + put_device(&sdev->dev);
> + return ERR_PTR(ret);
> + }
> +
> + return sub_sdev;
> +
> +err_set_name:
> + ida_free(&ctrl_ida, sub_sdev->devid);
> +err_ida_alloc:
> + kfree(sub_sdev);
> + 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 28e8c8bd3944..7cea0a5b034b 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;
Having something called a subdevice containing an instance of a device
does seem a little odd. Maybe the spmi_device naming is inappropriate after
this patch?
> + 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);
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
next prev parent reply other threads:[~2025-07-22 14:09 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-22 10:13 [PATCH v2 0/7] SPMI: Implement sub-devices and migrate drivers AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 10:13 ` [PATCH v2 1/7] spmi: Implement spmi_subdevice_alloc_and_add() and devm variant AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 14:09 ` Jonathan Cameron [this message]
2025-07-22 14:09 ` Jonathan Cameron
2025-07-29 10:44 ` AngeloGioacchino Del Regno
2025-07-29 10:44 ` AngeloGioacchino Del Regno
2025-07-29 18:41 ` Jonathan Cameron
2025-07-29 18:41 ` Jonathan Cameron
2025-07-23 8:37 ` kernel test robot
2025-07-23 8:37 ` kernel test robot
2025-07-23 9:52 ` kernel test robot
2025-07-23 9:52 ` kernel test robot
2025-07-22 10:13 ` [PATCH v2 2/7] nvmem: qcom-spmi-sdam: Migrate to devm_spmi_subdevice_alloc_and_add() AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 11:11 ` Konrad Dybcio
2025-07-22 11:11 ` Konrad Dybcio
2025-07-22 10:13 ` [PATCH v2 3/7] power: reset: qcom-pon: " AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 16:05 ` Sebastian Reichel
2025-07-22 16:05 ` Sebastian Reichel
2025-07-22 10:13 ` [PATCH v2 4/7] phy: qualcomm: eusb2-repeater: " AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-23 10:02 ` kernel test robot
2025-07-23 10:02 ` kernel test robot
2025-07-22 10:13 ` [PATCH v2 5/7] misc: qcom-coincell: " AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 10:13 ` [PATCH v2 6/7] iio: adc: qcom-spmi-iadc: " AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 14:17 ` Jonathan Cameron
2025-07-22 14:17 ` Jonathan Cameron
2025-07-22 10:13 ` [PATCH v2 7/7] iio: adc: qcom-spmi-iadc: Remove regmap R/W wrapper functions AngeloGioacchino Del Regno
2025-07-22 10:13 ` AngeloGioacchino Del Regno
2025-07-22 14:19 ` Jonathan Cameron
2025-07-22 14:19 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250722150930.00000a2f@huawei.com \
--to=jonathan.cameron@huawei.com \
--cc=andy@kernel.org \
--cc=angelogioacchino.delregno@collabora.com \
--cc=arnd@arndb.de \
--cc=casey.connolly@linaro.org \
--cc=dlechner@baylibre.com \
--cc=gregkh@linuxfoundation.org \
--cc=jic23@kernel.org \
--cc=kernel@collabora.com \
--cc=kishon@kernel.org \
--cc=krzysztof.kozlowski@linaro.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-pm@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=sboyd@kernel.org \
--cc=sre@kernel.org \
--cc=srini@kernel.org \
--cc=u.kleine-koenig@baylibre.com \
--cc=vkoul@kernel.org \
--cc=wenst@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.