Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Lee Jones <lee@kernel.org>
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Krzysztof Kozlowski <krzk@kernel.org>,
	Peter Griffin <peter.griffin@linaro.org>,
	Alim Akhtar <alim.akhtar@samsung.com>,
	Russell King <linux@armlinux.org.uk>,
	Mark Brown <broonie@kernel.org>,
	Charles Keepax <ckeepax@opensource.cirrus.com>,
	Linus Walleij <linusw@kernel.org>,
	Bartosz Golaszewski <brgl@bgdev.pl>,
	Arnd Bergmann <arnd@arndb.de>,
	mfd@lists.linux.dev, linux-samsung-soc@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	patches@opensource.cirrus.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4 1/4] mfd: wm831x: Support software nodes for DCDC regulators
Date: Thu, 5 Nov 2026 08:53:21 +0000	[thread overview]
Message-ID: <20261105085321.GG1650678@google.com> (raw)
In-Reply-To: <ad02069b0cdede7ae191e4a3df57f33a@gmail.com>

On Wed, 04 Nov 2026, Dmitry Torokhov wrote:

> Hi Lee,
> 
> On Wed, Nov 04, 2026 at 06:14:29PM +0000, Lee Jones wrote:
> > On Sat, 24 Oct 2026, Dmitry Torokhov wrote:
> > > +static int wm831x_add_devices(struct wm831x *wm831x, int wm831x_num,
> > > +			      const struct mfd_cell *cells, int num_cells)
> > > +{
> > > +	struct wm831x_pdata *pdata = &wm831x->pdata;
> > > +	int i;
> > > +
> > > +	struct mfd_cell *local_cells __free(kfree) =
> > > +		kmemdup_array(cells, num_cells, sizeof(*cells), GFP_KERNEL);
> > > +	if (!local_cells)
> > > +		return -ENOMEM;
> > > +
> > > +	for (i = 0; i < num_cells; i++) {
> > > +		struct mfd_cell *cell = &local_cells[i];
> > > +
> > > +		if (strcmp(cell->name, "wm831x-buckv") == 0) {
> > > +			int id = cell->id - 1;
> > > +
> > > +			if (id >= 0 && id < WM831X_MAX_DCDC)
> > > +				cell->swnode = pdata->dcdc_swnodes[id];
> > > +		}
> > > +	}
> >
> > I can't begin to tell you how much I hate this.
> >
> > Why are we duplicating massive static const structs just to add a S/W
> > node?  Is there no other way we can do this statically?
> 
> The software node itself is defined statically in the board file
> (crag_dcdc1_swnode in arch/arm/mach-s3c/mach-crag6410.c in patch 2/4),
> as it describes board-specific and PMIC-instance-specific wiring -
> specifically the host SoC GPIO wired to the PMIC's DVS pin (GPK(0) on
> Cragganmore 6410).
> 
> Because wm831x-core.c is a generic PMIC driver that can be instantiated
> on different boards or even multiple times on the same board (for
> example, Cragganmore 6410 has two WM831x PMIC instances, only one of
> which has a DVS GPIO wired to DCDC1), the shared static mfd_cell arrays
> in wm831x-core.c cannot point to a board's software node at compile
> time.
> 
> Note that local_cells is annotated with __free(kfree), so the duplicate
> array only lives for the duration of the mfd_add_devices() call (which
> makes its own per-device copy of each mfd_cell anyway) and is freed
> immediately before wm831x_add_devices() returns.
> 
> > Since pdata is being populated already, why not just pass that on to the
> > consuming child device (the regulator)?
> 
> The regulator driver (wm831x_buckv_dvs_init() in
> drivers/regulator/wm831x-dcdc.c) acquires the DVS GPIO using
> devm_gpiod_get(&pdev->dev, "dvs", ...). When converting the board file
> away from legacy gpiod_lookup_table to software nodes (to drop the
> fragile MFD device name matching and fix the GPIO chip label lookup),
> gpiolib resolves the "dvs-gpios" property against the consumer device's
> fwnode (&pdev->dev), so the software node needs to be attached to the
> wm831x-buckv platform device.
> 
> In v2 of this series I actually tried passing the software_node pointer
> through wm831x_buckv_pdata and attaching it to &pdev->dev inside the
> regulator driver's probe() [1]. However, attaching a software node to
> an already-registered platform device inside probe() is awkward and
> requires manual teardown in the child driver, whereas mfd-core already
> has built-in support for cell->swnode in mfd_add_device() (attaching
> the node via device_add_software_node() before platform_device_add(),
> and cleaning it up via device_remove_software_node() on error or
> removal). Populating cell->swnode lets mfd-core manage the software
> node lifecycle cleanly and keeps the regulator driver untouched.

Why do you need to attach the software_node to &pdev->dev at all?

All of the other DVS configuration (dvs_control_src, dvs_init_state) is
already passed to wm831x_buckv_dvs_init() via pdata.  If you put the
software node pointer in 'wm831x_buckv_pdata' (with the rest of the DVS
parameters, where it belongs), wm831x_buckv_dvs_init() can simply use
devm_fwnode_gpiod_get() to fetch it.

This then requires no device_add_software_node(), no manual tear-down in
the regulator driver and no "middle-man" changes to MFD at all.

> If you prefer not to kmemdup the full cell table, another option would
> be to split the buckv cells out of the main wm831x cell arrays and
> register them via a separate mfd_add_devices() call, though that seemed
> more intrusive across wm8310/wm8311/wm8312/wm8320. Please let me know
> what you would prefer here.

If there is a good reason why the above cannot be done in the regulator
driver (which I doubt), then yes, factoring the two identical
wm831x-buckv cells out of wm8310_devs/wm8311_devs/wm8312_devs/wm8320_devs
(just like touch_devs, rtc_devs and backlight_devs already are) is still
far better than kmemdup'ing the static const tables and matching cell
names with strcmp() in a loop.

> [1] https://lore.kernel.org/all/20260708-samsung-kp-v2-7-3c6ed4c9b3b6@gmail.com/

[2] Code talks, BS walks  =:-)

diff --git a/arch/arm/mach-s3c/mach-crag6410.c b/arch/arm/mach-s3c/mach-crag6410.c
index 2264beef6dda..9657d74ca0c5 100644
--- a/arch/arm/mach-s3c/mach-crag6410.c
+++ b/arch/arm/mach-s3c/mach-crag6410.c
@@ -456,9 +456,21 @@ static struct pca953x_platform_data crag6410_pca_data = {
 	.irq_base	= -1,
 };
 
+static const struct property_entry crag_dcdc1_properties[] = {
+	PROPERTY_ENTRY_GPIO("dvs-gpios", SAMSUNG_GPIO_NODE('K'), 0, GPIO_ACTIVE_HIGH),
+	{ }
+};
+
+static const struct software_node crag_dcdc1_swnode = {
+	.name = "wm831x-buckv-dcdc1",
+	.properties = crag_dcdc1_properties,
+};
+
 /* VDDARM is controlled by DVS1 connected to GPK(0) */
 static struct wm831x_buckv_pdata vddarm_pdata = {
 	.dvs_control_src = 1,
+	.swnode = &crag_dcdc1_swnode,
 };
 
 static struct regulator_consumer_supply vddarm_consumers[] = {
@@ -656,24 +668,6 @@ static struct wm831x_pdata crag_pmic_pdata = {
 	.touch = &touch_pdata,
 };
 
-/*
- * VDDARM is eventually ending up as a regulator hanging on the MFD cell device
- * "wm831x-buckv.1" spawn from drivers/mfd/wm831x-core.c.
- *
- * From the note on the platform data we can see that this is clearly DVS1
- * and assigned as dcdc1 resource to the MFD core which sets .id of the cell
- * spawning the DVS1 platform device to 1, then the cell platform device
- * name is calculated from 10*instance + id resulting in the device name
- * "wm831x-buckv.11"
- */
-static struct gpiod_lookup_table crag_pmic_gpiod_table = {
-	.dev_id = "wm831x-buckv.11",
-	.table = {
-		GPIO_LOOKUP("GPIOK", 0, "dvs", GPIO_ACTIVE_HIGH),
-		{ },
-	},
-};
-
 static struct i2c_board_info i2c_devs0[] = {
 	{ I2C_BOARD_INFO("24c08", 0x50), },
 	{ I2C_BOARD_INFO("tca6408", 0x20),
@@ -931,7 +925,7 @@ static void __init crag6410_machine_init(void)
 	s3c_fb_set_platdata(&crag6410_lcd_pdata);
 	dwc2_hsotg_set_platdata(&crag6410_hsotg_pdata);
 
-	gpiod_add_lookup_table(&crag_pmic_gpiod_table);
+	software_node_register(&crag_dcdc1_swnode);
 	i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
 	gpiod_add_lookup_table(&crag_wm1250_ev1_gpiod_table);
 	i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 834d7c181971..957da3195974 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -16,6 +16,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/gpio/consumer.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 
 #include <linux/mfd/wm831x/core.h>
@@ -330,6 +331,8 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev,
 				 struct wm831x_buckv_pdata *pdata)
 {
 	struct wm831x *wm831x = dcdc->wm831x;
+	struct fwnode_handle *fwnode;
+	enum gpiod_flags flags;
 	int ret;
 	u16 ctrl;
 
@@ -341,8 +344,15 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev,
 	*/
 	dcdc->dvs_gpio_state = pdata->dvs_init_state;
 
-	dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs",
-			dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW);
+	flags = dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+	if (pdata->swnode) {
+		fwnode = software_node_fwnode(pdata->swnode);
+		dcdc->dvs_gpiod = devm_fwnode_gpiod_get(&pdev->dev, fwnode,
+						"dvs", flags, dcdc->name);
+	} else {
+		dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs", flags);
+	}
+
 	if (IS_ERR(dcdc->dvs_gpiod)) {
 		dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %ld\n",
 			dcdc->name, PTR_ERR(dcdc->dvs_gpiod));
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h
index 75aa94dadf1c..49501f155cc5 100644
--- a/include/linux/mfd/wm831x/pdata.h
+++ b/include/linux/mfd/wm831x/pdata.h
@@ -12,6 +12,7 @@
 
 struct wm831x;
 struct regulator_init_data;
+struct software_node;
 
 struct wm831x_backlight_pdata {
 	int isink;     /** ISINK to use, 1 or 2 */
@@ -50,6 +51,7 @@ struct wm831x_buckv_pdata {
 	int dvs_control_src; /** Hardware DVS source to use (1 or 2) */
 	int dvs_init_state;  /** DVS state to expect on startup */
 	int dvs_state_gpio;  /** CPU GPIO to use for monitoring status */
+	const struct software_node *swnode; /** Software node for DVS GPIOs */
 };
 
 /* Sources for status LED configuration.  Values are register values

-- 
Lee Jones


  reply	other threads:[~2026-11-05  8:53 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-25  5:03 [PATCH v4 0/4] ARM: s3c: crag6410: Convert to software nodes and properties Dmitry Torokhov
2026-10-25  5:03 ` [PATCH v4 1/4] mfd: wm831x: Support software nodes for DCDC regulators Dmitry Torokhov
2026-10-26 10:15   ` Charles Keepax
2026-10-28  9:38   ` Bartosz Golaszewski
2026-11-04 18:14   ` Lee Jones
2026-11-05  1:15     ` Dmitry Torokhov
2026-11-05  8:53       ` Lee Jones [this message]
2026-11-05 13:43         ` Arnd Bergmann
2026-11-05 13:55           ` Charles Keepax
2026-11-05 14:13             ` Lee Jones
2026-10-25  5:03 ` [PATCH v4 2/4] ARM: s3c: crag6410: convert PMIC DVS GPIO to software properties Dmitry Torokhov
2026-10-28  9:38   ` Bartosz Golaszewski
2026-10-25  5:03 ` [PATCH v4 3/4] ARM: s3c: crag6410: convert basic-mmio-gpio and LEDs " Dmitry Torokhov
2026-10-25  5:03 ` [PATCH v4 4/4] ARM: s3c: crag6410: convert WM1250 and SPI0 GPIO lookup tables to property entries Dmitry Torokhov
2026-10-26 13:51 ` [PATCH v4 0/4] ARM: s3c: crag6410: Convert to software nodes and properties Arnd Bergmann
2026-10-27  1:07   ` Dmitry Torokhov

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=20261105085321.GG1650678@google.com \
    --to=lee@kernel.org \
    --cc=alim.akhtar@samsung.com \
    --cc=arnd@arndb.de \
    --cc=brgl@bgdev.pl \
    --cc=broonie@kernel.org \
    --cc=ckeepax@opensource.cirrus.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=krzk@kernel.org \
    --cc=linusw@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=mfd@lists.linux.dev \
    --cc=patches@opensource.cirrus.com \
    --cc=peter.griffin@linaro.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox