Linux RTC
 help / color / mirror / Atom feed
* [PATCH v2 14/15] power: supply: bd71828-power: Support ROHM BD72720
From: Matti Vaittinen @ 2025-10-27 11:48 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 11665 bytes --]

The ROHM BD72720 is a power management IC with a charger and coulomb
counter block which is closely related to the charger / coulomb counter
found from the BD71815, BD71828, BD71879 which are all supported by the
bd71828-power driver. Due to the similarities it makes sense to support
also the BD72720 with the same driver.

Add basic support for the charger logic on ROHM BD72720.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Revision history:
 RFCv1 => v2:
 - Support using 9-bit register addresses (offset of 0x100) with the
   BD72720
 - Simplify probe and IC data as we don't need two regmaps
 - Drop two BD72720 specific functions as we no longer need different
   regmap for it.

Note: This patch depends on the series: "power: supply: add charger for
BD71828" by Andreas:
https://lore.kernel.org/all/20250918-bd71828-charger-v5-0-851164839c28@kemnade.info/

NOTE: Fuel-gauging is not supported. You can find an unmaintained
downstream reference-driver with a fuel-gauge example from:
https://github.com/RohmSemiconductor/Linux-Kernel-PMIC-Drivers/releases/tag/bd72720-reference-driver-v1
---
 drivers/power/supply/bd71828-power.c | 134 +++++++++++++++++++++++----
 1 file changed, 116 insertions(+), 18 deletions(-)

diff --git a/drivers/power/supply/bd71828-power.c b/drivers/power/supply/bd71828-power.c
index ce73c0f48397..438e220a9cb7 100644
--- a/drivers/power/supply/bd71828-power.c
+++ b/drivers/power/supply/bd71828-power.c
@@ -5,6 +5,7 @@
 #include <linux/kernel.h>
 #include <linux/mfd/rohm-bd71815.h>
 #include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
@@ -51,12 +52,14 @@ struct pwr_regs {
 	unsigned int chg_state;
 	unsigned int bat_temp;
 	unsigned int dcin_stat;
+	unsigned int dcin_online_mask;
 	unsigned int dcin_collapse_limit;
 	unsigned int chg_set1;
 	unsigned int chg_en;
 	unsigned int vbat_alm_limit_u;
 	unsigned int conf;
 	unsigned int vdcin;
+	unsigned int vdcin_himask;
 };
 
 static const struct pwr_regs pwr_regs_bd71828 = {
@@ -67,12 +70,14 @@ static const struct pwr_regs pwr_regs_bd71828 = {
 	.chg_state = BD71828_REG_CHG_STATE,
 	.bat_temp = BD71828_REG_BAT_TEMP,
 	.dcin_stat = BD71828_REG_DCIN_STAT,
+	.dcin_online_mask = BD7182x_MASK_DCIN_DET,
 	.dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
 	.chg_set1 = BD71828_REG_CHG_SET1,
 	.chg_en   = BD71828_REG_CHG_EN,
 	.vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
 	.conf = BD71828_REG_CONF,
 	.vdcin = BD71828_REG_VDCIN_U,
+	.vdcin_himask = BD7182x_MASK_VDCIN_U,
 };
 
 static const struct pwr_regs pwr_regs_bd71815 = {
@@ -85,6 +90,7 @@ static const struct pwr_regs pwr_regs_bd71815 = {
 	.chg_state = BD71815_REG_CHG_STATE,
 	.bat_temp = BD71815_REG_BAT_TEMP,
 	.dcin_stat = BD71815_REG_DCIN_STAT,
+	.dcin_online_mask = BD7182x_MASK_DCIN_DET,
 	.dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
 	.chg_set1 = BD71815_REG_CHG_SET1,
 	.chg_en   = BD71815_REG_CHG_SET1,
@@ -92,6 +98,31 @@ static const struct pwr_regs pwr_regs_bd71815 = {
 	.conf = BD71815_REG_CONF,
 
 	.vdcin = BD71815_REG_VM_DCIN_U,
+	.vdcin_himask = BD7182x_MASK_VDCIN_U,
+};
+
+static struct pwr_regs pwr_regs_bd72720 = {
+	.vbat_avg = BD72720_REG_VM_SA_VBAT_U,
+	.ibat = BD72720_REG_CC_CURCD_U,
+	.ibat_avg = BD72720_REG_CC_SA_CURCD_U,
+	.btemp_vth = BD72720_REG_VM_BTMP_U,
+	/*
+	 * Note, state 0x40 IMP_CHK. not documented
+	 * on other variants but was still handled in
+	 * existing code. No memory traces as to why.
+	 */
+	.chg_state = BD72720_REG_CHG_STATE,
+	.bat_temp = BD72720_REG_CHG_BAT_TEMP_STAT,
+	.dcin_stat = BD72720_REG_INT_VBUS_SRC,
+	.dcin_online_mask = BD72720_MASK_DCIN_DET,
+	.dcin_collapse_limit = -1, /* Automatic. Setting not supported */
+	.chg_set1 = BD72720_REG_CHG_SET_1,
+	.chg_en = BD72720_REG_CHG_EN,
+	/* 15mV note in data-sheet */
+	.vbat_alm_limit_u = BD72720_REG_ALM_VBAT_TH_U,
+	.conf = BD72720_REG_CONF, /* o XSTB, only PON. Seprate slave addr */
+	.vdcin = BD72720_REG_VM_VBUS_U, /* 10 bits not 11 as with other ICs */
+	.vdcin_himask = BD72720_MASK_VDCIN_U,
 };
 
 struct bd71828_power {
@@ -298,7 +329,7 @@ static int get_chg_online(struct bd71828_power *pwr, int *chg_online)
 		dev_err(pwr->dev, "Failed to read DCIN status\n");
 		return ret;
 	}
-	*chg_online = ((r & BD7182x_MASK_DCIN_DET) != 0);
+	*chg_online = ((r & pwr->regs->dcin_online_mask) != 0);
 
 	return 0;
 }
@@ -329,8 +360,8 @@ static int bd71828_bat_inserted(struct bd71828_power *pwr)
 	ret = val & BD7182x_MASK_CONF_PON;
 
 	if (ret)
-		regmap_update_bits(pwr->regmap, pwr->regs->conf,
-				   BD7182x_MASK_CONF_PON, 0);
+		if (regmap_update_bits(pwr->regmap, pwr->regs->conf, BD7182x_MASK_CONF_PON, 0))
+			dev_err(pwr->dev, "Failed to write CONF register\n");
 
 	return ret;
 }
@@ -358,11 +389,13 @@ static int bd71828_init_hardware(struct bd71828_power *pwr)
 	int ret;
 
 	/* TODO: Collapse limit should come from device-tree ? */
-	ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
-			   BD7182x_DCIN_COLLAPSE_DEFAULT);
-	if (ret) {
-		dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
-		return ret;
+	if (pwr->regs->dcin_collapse_limit != (unsigned int)-1) {
+		ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
+				   BD7182x_DCIN_COLLAPSE_DEFAULT);
+		if (ret) {
+			dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
+			return ret;
+		}
 	}
 
 	ret = pwr->bat_inserted(pwr);
@@ -419,7 +452,7 @@ static int bd71828_charger_get_property(struct power_supply *psy,
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		ret = bd7182x_read16_himask(pwr, pwr->regs->vdcin,
-					    BD7182x_MASK_VDCIN_U, &tmp);
+					    pwr->regs->vdcin_himask, &tmp);
 		if (ret)
 			return ret;
 
@@ -630,6 +663,9 @@ BD_ISR_AC(dcin_ovp_det, "DCIN OVER VOLTAGE", true)
 BD_ISR_DUMMY(dcin_mon_det, "DCIN voltage below threshold")
 BD_ISR_DUMMY(dcin_mon_res, "DCIN voltage above threshold")
 
+BD_ISR_DUMMY(vbus_curr_limit, "VBUS current limited")
+BD_ISR_DUMMY(vsys_ov_res, "VSYS over-voltage cleared")
+BD_ISR_DUMMY(vsys_ov_det, "VSYS over-voltage")
 BD_ISR_DUMMY(vsys_uv_res, "VSYS under-voltage cleared")
 BD_ISR_DUMMY(vsys_uv_det, "VSYS under-voltage")
 BD_ISR_DUMMY(vsys_low_res, "'VSYS low' cleared")
@@ -878,6 +914,51 @@ static int bd7182x_get_irqs(struct platform_device *pdev,
 		BDIRQ("bd71828-temp-125-over", bd71828_temp_vf125_det),
 		BDIRQ("bd71828-temp-125-under", bd71828_temp_vf125_res),
 	};
+	static const struct bd7182x_irq_res bd72720_irqs[] = {
+		BDIRQ("bd72720_int_vbus_rmv", BD_ISR_NAME(dcin_removed)),
+		BDIRQ("bd72720_int_vbus_det", bd7182x_dcin_detected),
+		BDIRQ("bd72720_int_vbus_mon_res", BD_ISR_NAME(dcin_mon_res)),
+		BDIRQ("bd72720_int_vbus_mon_det", BD_ISR_NAME(dcin_mon_det)),
+		BDIRQ("bd72720_int_vsys_mon_res", BD_ISR_NAME(vsys_mon_res)),
+		BDIRQ("bd72720_int_vsys_mon_det", BD_ISR_NAME(vsys_mon_det)),
+		BDIRQ("bd72720_int_vsys_uv_res", BD_ISR_NAME(vsys_uv_res)),
+		BDIRQ("bd72720_int_vsys_uv_det", BD_ISR_NAME(vsys_uv_det)),
+		BDIRQ("bd72720_int_vsys_lo_res", BD_ISR_NAME(vsys_low_res)),
+		BDIRQ("bd72720_int_vsys_lo_det", BD_ISR_NAME(vsys_low_det)),
+		BDIRQ("bd72720_int_vsys_ov_res", BD_ISR_NAME(vsys_ov_res)),
+		BDIRQ("bd72720_int_vsys_ov_det", BD_ISR_NAME(vsys_ov_det)),
+		BDIRQ("bd72720_int_bat_ilim", BD_ISR_NAME(vbus_curr_limit)),
+		BDIRQ("bd72720_int_chg_done", bd718x7_chg_done),
+		BDIRQ("bd72720_int_extemp_tout", BD_ISR_NAME(chg_wdg_temp)),
+		BDIRQ("bd72720_int_chg_wdt_exp", BD_ISR_NAME(chg_wdg)),
+		BDIRQ("bd72720_int_bat_mnt_out", BD_ISR_NAME(rechg_res)),
+		BDIRQ("bd72720_int_bat_mnt_in", BD_ISR_NAME(rechg_det)),
+		BDIRQ("bd72720_int_chg_trns", BD_ISR_NAME(chg_state_changed)),
+
+		BDIRQ("bd72720_int_vbat_mon_res", BD_ISR_NAME(bat_mon_res)),
+		BDIRQ("bd72720_int_vbat_mon_det", BD_ISR_NAME(bat_mon)),
+		BDIRQ("bd72720_int_vbat_sht_res", BD_ISR_NAME(bat_short_res)),
+		BDIRQ("bd72720_int_vbat_sht_det", BD_ISR_NAME(bat_short)),
+		BDIRQ("bd72720_int_vbat_lo_res", BD_ISR_NAME(bat_low_res)),
+		BDIRQ("bd72720_int_vbat_lo_det", BD_ISR_NAME(bat_low)),
+		BDIRQ("bd72720_int_vbat_ov_res", BD_ISR_NAME(bat_ov_res)),
+		BDIRQ("bd72720_int_vbat_ov_det", BD_ISR_NAME(bat_ov)),
+		BDIRQ("bd72720_int_bat_rmv", BD_ISR_NAME(bat_removed)),
+		BDIRQ("bd72720_int_bat_det", BD_ISR_NAME(bat_det)),
+		BDIRQ("bd72720_int_dbat_det", BD_ISR_NAME(bat_dead)),
+		BDIRQ("bd72720_int_bat_temp_trns", BD_ISR_NAME(temp_transit)),
+		BDIRQ("bd72720_int_lobtmp_res", BD_ISR_NAME(temp_bat_low_res)),
+		BDIRQ("bd72720_int_lobtmp_det", BD_ISR_NAME(temp_bat_low)),
+		BDIRQ("bd72720_int_ovbtmp_res", BD_ISR_NAME(temp_bat_hi_res)),
+		BDIRQ("bd72720_int_ovbtmp_det", BD_ISR_NAME(temp_bat_hi)),
+		BDIRQ("bd72720_int_ocur1_res", BD_ISR_NAME(bat_oc1_res)),
+		BDIRQ("bd72720_int_ocur1_det", BD_ISR_NAME(bat_oc1)),
+		BDIRQ("bd72720_int_ocur2_res", BD_ISR_NAME(bat_oc2_res)),
+		BDIRQ("bd72720_int_ocur2_det", BD_ISR_NAME(bat_oc2)),
+		BDIRQ("bd72720_int_ocur3_res", BD_ISR_NAME(bat_oc3_res)),
+		BDIRQ("bd72720_int_ocur3_det", BD_ISR_NAME(bat_oc3)),
+		BDIRQ("bd72720_int_cc_mon2_det", BD_ISR_NAME(bat_cc_mon)),
+	};
 	int num_irqs;
 	const struct bd7182x_irq_res *irqs;
 
@@ -890,6 +971,10 @@ static int bd7182x_get_irqs(struct platform_device *pdev,
 		irqs = &bd71815_irqs[0];
 		num_irqs = ARRAY_SIZE(bd71815_irqs);
 		break;
+	case ROHM_CHIP_TYPE_BD72720:
+		irqs = &bd72720_irqs[0];
+		num_irqs = ARRAY_SIZE(bd72720_irqs);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -958,21 +1043,27 @@ static int bd71828_power_probe(struct platform_device *pdev)
 	struct power_supply_config ac_cfg = {};
 	struct power_supply_config bat_cfg = {};
 	int ret;
-	struct regmap *regmap;
-
-	regmap = dev_get_regmap(pdev->dev.parent, NULL);
-	if (!regmap) {
-		dev_err(&pdev->dev, "No parent regmap\n");
-		return -EINVAL;
-	}
 
 	pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
 	if (!pwr)
 		return -ENOMEM;
 
-	pwr->regmap = regmap;
-	pwr->dev = &pdev->dev;
+	/*
+	 * The BD72720 MFD device registers two regmaps. Power-supply driver
+	 * uses the "wrap-map", which provides access to both of the I2C slave
+	 * addresses used by the BD72720
+	 */
 	pwr->chip_type = platform_get_device_id(pdev)->driver_data;
+	if (pwr->chip_type != ROHM_CHIP_TYPE_BD72720)
+		pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	else
+		pwr->regmap = dev_get_regmap(pdev->dev.parent, "wrap-map");
+	if (!pwr->regmap) {
+		dev_err(&pdev->dev, "No parent regmap\n");
+		return -EINVAL;
+	}
+
+	pwr->dev = &pdev->dev;
 
 	switch (pwr->chip_type) {
 	case ROHM_CHIP_TYPE_BD71828:
@@ -985,6 +1076,12 @@ static int bd71828_power_probe(struct platform_device *pdev)
 		pwr->get_temp = bd71815_get_temp;
 		pwr->regs = &pwr_regs_bd71815;
 		break;
+	case ROHM_CHIP_TYPE_BD72720:
+		pwr->bat_inserted = bd71828_bat_inserted;
+		pwr->regs = &pwr_regs_bd72720;
+		pwr->get_temp = bd71828_get_temp;
+		dev_dbg(pwr->dev, "Found ROHM BD72720\n");
+		break;
 	default:
 		dev_err(pwr->dev, "Unknown PMIC\n");
 		return -EINVAL;
@@ -1030,6 +1127,7 @@ static int bd71828_power_probe(struct platform_device *pdev)
 static const struct platform_device_id bd71828_charger_id[] = {
 	{ "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
 	{ "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
+	{ "bd72720-power", ROHM_CHIP_TYPE_BD72720 },
 	{ },
 };
 MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 13/15] power: supply: bd71828: Support wider register addresses
From: Matti Vaittinen @ 2025-10-27 11:48 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2413 bytes --]

The BD71828 power-supply driver assumes register addresses to be 8-bit.
The new BD72720 will use stacked register maps to hide paging which is
done using secondary I2C slave address. This requires use of 9-bit
register addresses in the power-supply driver (added offset 0x100 to
the 8-bit hardware register addresses).

The cost is slightly used memory consumption as the members in the
struct pwr_regs will be changed from u8 to unsigned int, which means 3
byte increase / member / instance.
This is currently 14 members (expected to possibly be increased when
adding new variants / new functionality which may introduce new
registers, but not expected to grow much) and 2 instances (will be 3
instances when BD72720 gets added).

So, even if the number of registers grew to 50 it'd be 150 bytes /
instance. Assuming we eventually supported 5 variants, it'd be
5 * 150 bytes, which stays very reasonable considering systems we are
dealing with.

As a side note, we can reduce the "wasted space / member / instance" from
3 bytes to 1 byte, by using u16 instead of the unsigned int if needed. I
rather use unsigned int to be initially prepared for devices with 32 bit
registers if there is no need to count bytes.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
---
Revision history:
 RFCv1 => v2:
 - New patch
---
 drivers/power/supply/bd71828-power.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/power/supply/bd71828-power.c b/drivers/power/supply/bd71828-power.c
index f667baedeb77..ce73c0f48397 100644
--- a/drivers/power/supply/bd71828-power.c
+++ b/drivers/power/supply/bd71828-power.c
@@ -44,19 +44,19 @@
 #define VBAT_LOW_TH			0x00D4
 
 struct pwr_regs {
-	u8 vbat_avg;
-	u8 ibat;
-	u8 ibat_avg;
-	u8 btemp_vth;
-	u8 chg_state;
-	u8 bat_temp;
-	u8 dcin_stat;
-	u8 dcin_collapse_limit;
-	u8 chg_set1;
-	u8 chg_en;
-	u8 vbat_alm_limit_u;
-	u8 conf;
-	u8 vdcin;
+	unsigned int vbat_avg;
+	unsigned int ibat;
+	unsigned int ibat_avg;
+	unsigned int btemp_vth;
+	unsigned int chg_state;
+	unsigned int bat_temp;
+	unsigned int dcin_stat;
+	unsigned int dcin_collapse_limit;
+	unsigned int chg_set1;
+	unsigned int chg_en;
+	unsigned int vbat_alm_limit_u;
+	unsigned int conf;
+	unsigned int vdcin;
 };
 
 static const struct pwr_regs pwr_regs_bd71828 = {
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 12/15] rtc: bd70528: Support BD72720 rtc
From: Matti Vaittinen @ 2025-10-27 11:47 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3216 bytes --]

The BD72720 has similar RTC block as a few other ROHM PMICs.

Add support for BD72720 RTC.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Revision history:
 RFCv1 =>:
 - No changes
---
 drivers/rtc/Kconfig       |  3 ++-
 drivers/rtc/rtc-bd70528.c | 21 ++++++++++++++-------
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2933c41c77c8..418f6c28847a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -561,7 +561,8 @@ config RTC_DRV_BD70528
 	depends on MFD_ROHM_BD71828
 	help
 	  If you say Y here you will get support for the RTC
-	  block on ROHM BD71815 and BD71828 Power Management IC.
+	  block on ROHM BD71815, BD71828 and BD72720 Power
+	  Management ICs.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-bd70528.
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 954ac4ef53e8..4c8599761b2e 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -7,6 +7,7 @@
 #include <linux/bcd.h>
 #include <linux/mfd/rohm-bd71815.h>
 #include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -262,13 +263,13 @@ static int bd70528_probe(struct platform_device *pdev)
 
 		/*
 		 * See also BD718XX_ALM_EN_OFFSET:
-		 * This works for BD71828 and BD71815 as they have same offset
-		 * between ALM0 start and ALM0_MASK. If new ICs are to be
-		 * added this requires proper check as ALM0_MASK is not located
-		 * at the end of ALM0 block - but after all ALM blocks so if
-		 * amount of ALMs differ the offset to enable/disable is likely
-		 * to be incorrect and enable/disable must be given as own
-		 * reg address here.
+		 * This works for BD71828, BD71815, and BD72720 as they all
+		 * have same offset between the ALM0 start and the ALM0_MASK.
+		 * If new ICs are to be added this requires proper check as
+		 * the  ALM0_MASK is not located at the end of ALM0 block -
+		 * but after all ALM blocks. If amount of ALMs differ, the
+		 * offset to enable/disable is likely to be incorrect and
+		 * enable/disable must be given as own reg address here.
 		 */
 		bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
 		hour_reg = BD71815_REG_HOUR;
@@ -278,6 +279,11 @@ static int bd70528_probe(struct platform_device *pdev)
 		bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
 		hour_reg = BD71828_REG_RTC_HOUR;
 		break;
+	case ROHM_CHIP_TYPE_BD72720:
+		bd_rtc->reg_time_start = BD72720_REG_RTC_START;
+		bd_rtc->bd718xx_alm_block_start = BD72720_REG_RTC_ALM_START;
+		hour_reg = BD72720_REG_RTC_HOUR;
+		break;
 	default:
 		dev_err(&pdev->dev, "Unknown chip\n");
 		return -ENOENT;
@@ -337,6 +343,7 @@ static int bd70528_probe(struct platform_device *pdev)
 static const struct platform_device_id bd718x7_rtc_id[] = {
 	{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
 	{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
+	{ "bd72720-rtc", ROHM_CHIP_TYPE_BD72720 },
 	{ },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 11/15] clk: clk-bd718x7: Support BD72720 clk gate
From: Matti Vaittinen @ 2025-10-27 11:47 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2483 bytes --]

The BD72720 has similar simple clk gate as a few other ROHM PMICs.

Add support for BD72720 clk gate.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Revision history:
 RFCv1 =>:
 - No changes
---
 drivers/clk/Kconfig       |  4 ++--
 drivers/clk/clk-bd718x7.c | 10 ++++++++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3a1611008e48..619bd63a3c77 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -475,8 +475,8 @@ config COMMON_CLK_BD718XX
 	tristate "Clock driver for 32K clk gates on ROHM PMICs"
 	depends on MFD_ROHM_BD718XX || MFD_ROHM_BD71828
 	help
-	  This driver supports ROHM BD71837, BD71847, BD71850, BD71815
-	  and BD71828 PMICs clock gates.
+	  This driver supports ROHM BD71837, BD71847, BD71850, BD71815,
+	  BD71828, and BD72720 PMICs clock gates.
 
 config COMMON_CLK_FIXED_MMIO
 	bool "Clock driver for Memory Mapped Fixed values"
diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c
index ac40b669d60b..1cae974e6d1d 100644
--- a/drivers/clk/clk-bd718x7.c
+++ b/drivers/clk/clk-bd718x7.c
@@ -19,7 +19,8 @@
 #define BD71828_REG_OUT32K	0x4B
 /* BD71837 and BD71847 */
 #define BD718XX_REG_OUT32K	0x2E
-
+/* BD72720 */
+#define BD72720_REG_OUT32K	0x9a
 /*
  * BD71837, BD71847, and BD71828 all use bit [0] to clk output control
  */
@@ -118,6 +119,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
 		c->reg = BD71815_REG_OUT32K;
 		c->mask = CLK_OUT_EN_MASK;
 		break;
+	case ROHM_CHIP_TYPE_BD72720:
+		c->reg = BD72720_REG_OUT32K;
+		c->mask = CLK_OUT_EN_MASK;
+		break;
 	default:
 		dev_err(&pdev->dev, "Unknown clk chip\n");
 		return -EINVAL;
@@ -146,6 +151,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
 	{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
 	{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
 	{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
+	{ "bd72720-clk", ROHM_CHIP_TYPE_BD72720 },
 	{ },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
@@ -161,6 +167,6 @@ static struct platform_driver bd71837_clk = {
 module_platform_driver(bd71837_clk);
 
 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and chip clk driver");
+MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD72720 chip clk driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:bd718xx-clk");
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 10/15] gpio: Support ROHM BD72720 gpios
From: Matti Vaittinen @ 2025-10-27 11:47 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 10849 bytes --]

The ROHM BD72720 has 6 pins which may be configured as GPIOs. The
GPIO1 ... GPIO5 and EPDEN pins. The configuration is done to OTP at the
manufacturing, and it can't be read at runtime. The device-tree is
required to tell the software which of the pins are used as GPIOs.

Keep the pin mapping static regardless the OTP. This way the user-space
can always access the BASE+N for GPIO(N+1) (N = 0 to 4), and BASE + 5
for the EPDEN pin. Do this by setting always the number of GPIOs to 6,
and by using the valid-mask to invalidate the pins which aren't configured
as GPIOs.

First two pins can be set to be either input or output by OTP. Direction
can't be changed by software. Rest of the pins can be set as outputs
only. All of the pins support generating interrupts.

Support the Input/Output state getting/setting and the output mode
configuration (open-drain/push-pull).

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

---
Revision history:
 RFCv1 => :
 - No changes
---
 drivers/gpio/Kconfig        |   9 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-bd72720.c | 281 ++++++++++++++++++++++++++++++++++++
 3 files changed, 291 insertions(+)
 create mode 100644 drivers/gpio/gpio-bd72720.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7ee3afbc2b05..0c612c5163c5 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1319,6 +1319,15 @@ config GPIO_BD71828
 	  This driver can also be built as a module. If so, the module
 	  will be called gpio-bd71828.
 
+config GPIO_BD72720
+	tristate "ROHM BD72720 and BD73900 PMIC GPIO support"
+	depends on MFD_ROHM_BD71828
+	help
+	  Support for GPIO on ROHM BD72720 and BD73900 PMICs. There are two
+	  pins which can be configured to GPI or GPO, and three pins which can
+	  be configured to GPO on the ROHM PMIC. The pin configuration is done
+	  on OTP at manufacturing.
+
 config GPIO_BD9571MWV
 	tristate "ROHM BD9571 GPIO support"
 	depends on MFD_BD9571MWV
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ec296fa14bfd..7a5d03db3021 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BCM_KONA)		+= gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BCM_XGS_IPROC)	+= gpio-xgs-iproc.o
 obj-$(CONFIG_GPIO_BD71815)		+= gpio-bd71815.o
 obj-$(CONFIG_GPIO_BD71828)		+= gpio-bd71828.o
+obj-$(CONFIG_GPIO_BD72720)		+= gpio-bd72720.o
 obj-$(CONFIG_GPIO_BD9571MWV)		+= gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BLZP1600)		+= gpio-blzp1600.o
 obj-$(CONFIG_GPIO_BRCMSTB)		+= gpio-brcmstb.o
diff --git a/drivers/gpio/gpio-bd72720.c b/drivers/gpio/gpio-bd72720.c
new file mode 100644
index 000000000000..6549dbf4c7ad
--- /dev/null
+++ b/drivers/gpio/gpio-bd72720.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support to GPIOs on ROHM BD72720 and BD79300
+ * Copyright 2025 ROHM Semiconductors.
+ * Author: Matti Vaittinen <mazziesaccount@gmail.com>
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/rohm-bd72720.h>
+
+#define BD72720_GPIO_OPEN_DRAIN		0
+#define BD72720_GPIO_CMOS		BIT(1)
+#define BD72720_INT_GPIO1_IN_SRC	4
+/*
+ * The BD72720 has several "one time programmable" (OTP) configurations which
+ * can be set at manufacturing phase. A set of these options allow using pins
+ * as GPIO. The OTP configuration can't be read at run-time, so drivers rely on
+ * device-tree to advertise the correct options.
+ *
+ * Both DVS[0,1] pins can be configured to be used for:
+ *  - OTP0: regulator RUN state control
+ *  - OTP1: GPI
+ *  - OTP2: GPO
+ *  - OTP3: Power sequencer output
+ *  Data-sheet also states that these PINs can always be used for IRQ but the
+ *  driver limits this by allowing them to be used for IRQs with OTP1 only.
+ *
+ * Pins GPIO_EXTEN0 (GPIO3), GPIO_EXTEN1 (GPIO4), GPIO_FAULT_B (GPIO5) have OTP
+ * options for a specific (non GPIO) purposes, but also an option to configure
+ * them to be used as a GPO.
+ *
+ * OTP settings can be separately configured for each pin.
+ *
+ * DT properties:
+ * "rohm,pin-dvs0" and "rohm,pin-dvs1" can be set to one of the values:
+ * "dvs-input", "gpi", "gpo".
+ *
+ * "rohm,pin-exten0", "rohm,pin-exten1" and "rohm,pin-fault_b" can be set to:
+ * "gpo"
+ */
+
+enum bd72720_gpio_state {
+	BD72720_PIN_UNKNOWN,
+	BD72720_PIN_GPI,
+	BD72720_PIN_GPO,
+};
+
+enum {
+	BD72720_GPIO1,
+	BD72720_GPIO2,
+	BD72720_GPIO3,
+	BD72720_GPIO4,
+	BD72720_GPIO5,
+	BD72720_GPIO_EPDEN,
+	BD72720_NUM_GPIOS
+};
+
+struct bd72720_gpio {
+	/* chip.parent points the MFD which provides DT node and regmap */
+	struct gpio_chip chip;
+	/* dev points to the platform device for devm and prints */
+	struct device *dev;
+	struct regmap *regmap;
+	int gpio_is_input;
+};
+
+static int bd72720gpi_get(struct bd72720_gpio *bdgpio, unsigned int reg_offset)
+{
+	int ret, val, shift;
+
+	ret = regmap_read(bdgpio->regmap, BD72720_REG_INT_ETC1_SRC, &val);
+	if (ret)
+		return ret;
+
+	shift = BD72720_INT_GPIO1_IN_SRC + reg_offset;
+
+	return (val >> shift) & 1;
+}
+
+static int bd72720gpo_get(struct bd72720_gpio *bdgpio,
+			  unsigned int offset)
+{
+	const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+			     BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+			     BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+	int ret, val;
+
+	ret = regmap_read(bdgpio->regmap, regs[offset], &val);
+	if (ret)
+		return ret;
+
+	return val & BD72720_GPIO_HIGH;
+}
+
+static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+
+	if (BIT(offset) & bdgpio->gpio_is_input)
+		return bd72720gpi_get(bdgpio, offset);
+
+	return bd72720gpo_get(bdgpio, offset);
+}
+
+static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset,
+			  int value)
+{
+	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+	const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+			     BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+			     BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+
+	if (BIT(offset) & bdgpio->gpio_is_input) {
+		dev_dbg(bdgpio->dev, "pin %d not output.\n", offset);
+		return -EINVAL;
+	}
+
+	if (value)
+		return regmap_set_bits(bdgpio->regmap, regs[offset],
+				      BD72720_GPIO_HIGH);
+
+	return regmap_clear_bits(bdgpio->regmap, regs[offset],
+					BD72720_GPIO_HIGH);
+}
+
+static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+				   unsigned long config)
+{
+	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+	const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+			     BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+			     BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+
+	/*
+	 * We can only set the output mode, which makes sense only when output
+	 * OTP configuration is used.
+	 */
+	if (BIT(offset) & bdgpio->gpio_is_input)
+		return -ENOTSUPP;
+
+	switch (pinconf_to_config_param(config)) {
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		return regmap_update_bits(bdgpio->regmap,
+					  regs[offset],
+					  BD72720_GPIO_DRIVE_MASK,
+					  BD72720_GPIO_OPEN_DRAIN);
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		return regmap_update_bits(bdgpio->regmap,
+					  regs[offset],
+					  BD72720_GPIO_DRIVE_MASK,
+					  BD72720_GPIO_CMOS);
+	default:
+		break;
+	}
+
+	return -ENOTSUPP;
+}
+
+static int bd72720gpo_direction_get(struct gpio_chip *chip,
+				    unsigned int offset)
+{
+	struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+
+	if (BIT(offset) & bdgpio->gpio_is_input)
+		return GPIO_LINE_DIRECTION_IN;
+
+	return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int bd72720_valid_mask(struct gpio_chip *gc,
+			      unsigned long *valid_mask,
+			      unsigned int ngpios)
+{
+	static const char * const properties[] = {
+		"rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0",
+		"rohm,pin-exten1", "rohm,pin-fault_b"
+	};
+	struct bd72720_gpio *g = gpiochip_get_data(gc);
+	const char *val;
+	int i, ret;
+
+	*valid_mask = BIT(BD72720_GPIO_EPDEN);
+
+	if (!gc->parent)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(properties); i++) {
+		ret = fwnode_property_read_string(dev_fwnode(gc->parent),
+						  properties[i], &val);
+
+		if (ret) {
+			if (ret == -EINVAL)
+				continue;
+
+			dev_err(g->dev, "pin %d (%s), bad configuration\n", i,
+				properties[i]);
+
+			return ret;
+		}
+
+		if (strcmp(val, "gpi") == 0) {
+			if (i != BD72720_GPIO1 && i != BD72720_GPIO2) {
+				dev_warn(g->dev,
+					 "pin %d (%s) does not support INPUT mode",
+					 i, properties[i]);
+				continue;
+			}
+
+			*valid_mask |= BIT(i);
+			g->gpio_is_input |= BIT(i);
+		} else if (strcmp(val, "gpo") == 0) {
+			*valid_mask |= BIT(i);
+		}
+	}
+
+	return 0;
+}
+
+/* Template for GPIO chip */
+static const struct gpio_chip bd72720gpo_chip = {
+	.label			= "bd72720",
+	.owner			= THIS_MODULE,
+	.get			= bd72720gpio_get,
+	.get_direction		= bd72720gpo_direction_get,
+	.set			= bd72720gpo_set,
+	.set_config		= bd72720_gpio_set_config,
+	.init_valid_mask	= bd72720_valid_mask,
+	.can_sleep		= true,
+	.ngpio			= BD72720_NUM_GPIOS,
+	.base			= -1,
+};
+
+static int gpo_bd72720_probe(struct platform_device *pdev)
+{
+	struct bd72720_gpio *g;
+	struct device *parent, *dev;
+
+	/*
+	 * Bind devm lifetime to this platform device => use dev for devm.
+	 * also the prints should originate from this device.
+	 */
+	dev = &pdev->dev;
+	/* The device-tree and regmap come from MFD => use parent for that */
+	parent = dev->parent;
+
+	g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
+	if (!g)
+		return -ENOMEM;
+
+	g->chip = bd72720gpo_chip;
+	g->dev = dev;
+	g->chip.parent = parent;
+	g->regmap = dev_get_regmap(parent, NULL);
+
+	return devm_gpiochip_add_data(dev, &g->chip, g);
+}
+
+static const struct platform_device_id bd72720_gpio_id[] = {
+	{ "bd72720-gpio" },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
+
+static struct platform_driver gpo_bd72720_driver = {
+	.driver = {
+		.name = "bd72720-gpio",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = gpo_bd72720_probe,
+	.id_table = bd72720_gpio_id,
+};
+module_platform_driver(gpo_bd72720_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
+MODULE_LICENSE("GPL");
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 09/15] regulator: bd71828: Support ROHM BD72720
From: Matti Vaittinen @ 2025-10-27 11:47 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 40718 bytes --]

ROHM BD72720 is a power management IC which integrates 10 buck and 11 LDO
regulators. This PMIC has plenty of commonalities with the BD71828 and
BD71879.

The BD72720 does also have similar 'run-level'-concept as the BD71828 had.
It allows controlling the regulator's 'en masse', although only BUCK1
and LDO1 can utilize this in BD72720. Similar to BD71828, this 'en
masse' -control is not supported by this driver.

Support the voltage and enable/disable state control for the BD72720.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
---
Revision history:
 RFCv1 =>:
 - No changes

There are some new variants planned. Most notably, the BD73900 should be
similar to the BD72720 what comes to the regulator control logic.

If the run-level control is needed, there are some downstream extensions
available at:
https://rohmsemiconductor.github.io/Linux-Kernel-PMIC-Drivers/BD72720/
---
 drivers/regulator/Kconfig             |   8 +-
 drivers/regulator/bd71828-regulator.c | 993 +++++++++++++++++++++++++-
 2 files changed, 992 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d84f3d054c59..660863f096e3 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -241,13 +241,13 @@ config REGULATOR_BD71815
 	  will be called bd71815-regulator.
 
 config REGULATOR_BD71828
-	tristate "ROHM BD71828 Power Regulator"
+	tristate "ROHM BD71828, BD72720 and BD73900 Power Regulators"
 	depends on MFD_ROHM_BD71828
 	select REGULATOR_ROHM
 	help
-	  This driver supports voltage regulators on ROHM BD71828 PMIC.
-	  This will enable support for the software controllable buck
-	  and LDO regulators.
+	  This driver supports voltage regulators on ROHM BD71828,
+	  BD71879, BD72720 and BD73900 PMICs. This will enable
+	  support for the software controllable buck and LDO regulators.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called bd71828-regulator.
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index 3d18dbfdb84e..61ba82c7c6f1 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -3,12 +3,15 @@
 // bd71828-regulator.c ROHM BD71828GW-DS1 regulator driver
 //
 
+#include <linux/cleanup.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -16,6 +19,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 
+#define BD72720_MASK_LDON_HEAD GENMASK(2, 0)
 struct reg_init {
 	unsigned int reg;
 	unsigned int mask;
@@ -64,6 +68,26 @@ static const struct reg_init bd71828_buck7_inits[] = {
 	},
 };
 
+#define BD72720_MASK_DVS_BUCK1_CTRL BIT(4)
+#define BD72720_MASK_DVS_LDO1_CTRL BIT(5)
+
+static const struct reg_init bd72720_buck1_inits[] = {
+	{
+		.reg = BD72720_REG_PS_CTRL_2,
+		.mask = BD72720_MASK_DVS_BUCK1_CTRL,
+		.val = 0, /* Disable "run-level" control */
+	},
+};
+
+static const struct reg_init bd72720_ldo1_inits[] = {
+	{
+		.reg = BD72720_REG_PS_CTRL_2,
+		.mask = BD72720_MASK_DVS_LDO1_CTRL,
+		.val = 0, /* Disable "run-level" control */
+	},
+};
+
+/* BD71828 Buck voltages */
 static const struct linear_range bd71828_buck1267_volts[] = {
 	REGULATOR_LINEAR_RANGE(500000, 0x00, 0xef, 6250),
 	REGULATOR_LINEAR_RANGE(2000000, 0xf0, 0xff, 0),
@@ -84,13 +108,79 @@ static const struct linear_range bd71828_buck5_volts[] = {
 	REGULATOR_LINEAR_RANGE(3300000, 0x10, 0x1f, 0),
 };
 
+/* BD71828 LDO voltages */
 static const struct linear_range bd71828_ldo_volts[] = {
 	REGULATOR_LINEAR_RANGE(800000, 0x00, 0x31, 50000),
 	REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0),
 };
 
+/* BD72720 Buck voltages */
+static const struct linear_range bd72720_buck1234_volts[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0x00, 0xc0, 6250),
+	REGULATOR_LINEAR_RANGE(1700000, 0xc1, 0xff, 0),
+};
+
+static const struct linear_range bd72720_buck589_volts[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0x00, 0x78, 10000),
+	REGULATOR_LINEAR_RANGE(1700000, 0x79, 0xff, 0),
+};
+
+static const struct linear_range bd72720_buck67_volts[] = {
+	REGULATOR_LINEAR_RANGE(1500000, 0x00, 0xb4, 10000),
+	REGULATOR_LINEAR_RANGE(3300000, 0xb5, 0xff, 0),
+};
+
+/*
+ * The BUCK10 on BD72720 has two modes of operation, depending on a LDON_HEAD
+ * setting. When LDON_HEAD is 0x0, the behaviour is as with other bucks, eg.
+ * voltage can be set to a values indicated below using the VSEL register.
+ *
+ * However, when LDON_HEAD is set to 0x1 ... 0x7, BUCK 10 voltage is, according
+ * to the data-sheet, "automatically adjusted following LDON_HEAD setting and
+ * clamped to BUCK10_VID setting".
+ *
+ * Again, reading the data-sheet shows a "typical connection" where the BUCK10
+ * is used to supply the LDOs 1-4. My assumption is that in practice, this
+ * means that the BUCK10 voltage will be adjusted based on the maximum output
+ * of the LDO 1-4 (to minimize power loss). This makes sense.
+ *
+ * Auto-adjusting regulators aren't something I really like to model in the
+ * driver though - and, if the auto-adjustment works as intended, then there
+ * should really be no need to software to care about the buck10 voltages.
+ * If enable/disable control is still needed, we can implement buck10 as a
+ * regulator with only the enable/disable ops - and device-tree can be used
+ * to model the supply-relations. I believe this could allow the regulator
+ * framework to automagically disable the BUCK10 if all LDOs that are being
+ * supplied by it are disabled.
+ */
+static const struct linear_range bd72720_buck10_volts[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0x00, 0xc0, 6250),
+	REGULATOR_LINEAR_RANGE(1700000, 0xc1, 0xff, 0),
+};
+
+/* BD72720 LDO voltages */
+static const struct linear_range bd72720_ldo1234_volts[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0x00, 0x50, 6250),
+	REGULATOR_LINEAR_RANGE(1000000, 0x51, 0x7f, 0),
+};
+
+static const struct linear_range bd72720_ldo57891011_volts[] = {
+	REGULATOR_LINEAR_RANGE(750000, 0x00, 0xff, 10000),
+};
+
+static const struct linear_range bd72720_ldo6_volts[] = {
+	REGULATOR_LINEAR_RANGE(600000, 0x00, 0x78, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0x79, 0x7f, 0),
+};
+
 static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
 
+/*
+ * BD72720 supports setting both the ramp-up and ramp-down values
+ * separately. Do we need to support ramp-down setting?
+ */
+static const unsigned int bd72720_ramp_delay[] = { 5000, 7500, 10000, 12500 };
+
 static int buck_set_hw_dvs_levels(struct device_node *np,
 				  const struct regulator_desc *desc,
 				  struct regulator_config *cfg)
@@ -171,6 +261,24 @@ static const struct regulator_ops bd71828_ldo6_ops = {
 	.is_enabled = regulator_is_enabled_regmap,
 };
 
+static const struct regulator_ops bd72720_regulator_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops bd72720_buck10_ldon_head_op = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
 static const struct bd71828_regulator_data bd71828_rdata[] = {
 	{
 		.desc = {
@@ -677,22 +785,890 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
 	},
 };
 
+#define BD72720_BUCK10_DESC_INDEX 10
+#define BD72720_NUM_BUCK_VOLTS 0x100
+#define BD72720_NUM_LDO_VOLTS 0x100
+#define BD72720_NUM_LDO12346_VOLTS 0x80
+
+static const struct bd71828_regulator_data bd72720_rdata[] = {
+	{
+		.desc = {
+			.name = "buck1",
+			.of_match = of_match_ptr("buck1"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK1,
+			.type = REGULATOR_VOLTAGE,
+
+			/*
+			 * The BD72720 BUCK1 and LDO1 support GPIO toggled
+			 * sub-RUN states called RUN0, RUN1, RUN2 and RUN3.
+			 * The "operating mode" (sub-RUN states or normal)
+			 * can be changed by a register.
+			 *
+			 * When the sub-RUN states are used, the voltage and
+			 * enable state depend on a state specific
+			 * configuration. The voltage and enable configuration
+			 * for BUCK1 and LDO1 can be defined for each sub-RUN
+			 * state using BD72720_REG_[BUCK,LDO]1_VSEL_R[0,1,2,3]
+			 * voltage selection registers and the bits
+			 * BD72720_MASK_RUN_[0,1,2,3]_EN in the enable registers.
+			 * The PMIC will change both the BUCK1 and LDO1 voltages
+			 * to the states defined in these registers when
+			 * "DVS GPIOs" are toggled.
+			 *
+			 * If RUN 0 .. RUN 4 states are to be used, the normal
+			 * voltage configuration mechanisms do not apply
+			 * and we should overwrite the ops and ignore the
+			 * voltage setting/getting registers which are setup
+			 * here. This is not supported for now. If you need
+			 * this functionality, you may try merging functionality
+			 * from a downstream driver:
+			 * https://rohmsemiconductor.github.io/Linux-Kernel-PMIC-Drivers/BD72720/
+			 */
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK1_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK1_VSEL_RB,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK1_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR, /* Deep idle in data-sheet */
+			.run_reg = BD72720_REG_BUCK1_VSEL_RB,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_reg = BD72720_REG_BUCK1_VSEL_I,
+			.idle_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_BUCK1_VSEL_S,
+			.suspend_mask = BD72720_MASK_BUCK_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_BUCK1_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_BUCK_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+		.reg_inits = bd72720_buck1_inits,
+		.reg_init_amnt = ARRAY_SIZE(bd72720_buck1_inits),
+	}, {
+		.desc = {
+			.name = "buck2",
+			.of_match = of_match_ptr("buck2"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK2,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK2_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK2_VSEL_R,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK2_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK2_VSEL_R,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_reg = BD72720_REG_BUCK2_VSEL_I,
+			.idle_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_BUCK2_VSEL_S,
+			.suspend_mask = BD72720_MASK_BUCK_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_BUCK2_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_BUCK_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck3",
+			.of_match = of_match_ptr("buck3"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK3,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK3_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK3_VSEL_R,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK3_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK3_VSEL_R,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_reg = BD72720_REG_BUCK3_VSEL_I,
+			.idle_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_BUCK3_VSEL_S,
+			.suspend_mask = BD72720_MASK_BUCK_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_BUCK3_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_BUCK_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck4",
+			.of_match = of_match_ptr("buck4"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK4,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK4_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK4_VSEL_R,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK4_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK4_VSEL_R,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_reg = BD72720_REG_BUCK4_VSEL_I,
+			.idle_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_BUCK4_VSEL_S,
+			.suspend_mask = BD72720_MASK_BUCK_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_BUCK4_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_BUCK_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck5",
+			.of_match = of_match_ptr("buck5"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK5,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck589_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck589_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK5_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK5_VSEL,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK5_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK5_VSEL,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck6",
+			.of_match = of_match_ptr("buck6"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK6,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck67_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck67_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK6_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK6_VSEL,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK6_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK6_VSEL,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck7",
+			.of_match = of_match_ptr("buck7"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK7,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck67_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck67_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK7_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK7_VSEL,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK7_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK7_VSEL,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck8",
+			.of_match = of_match_ptr("buck8"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK8,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck589_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck589_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK8_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK8_VSEL,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK8_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK8_VSEL,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck9",
+			.of_match = of_match_ptr("buck9"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK9,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck589_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck589_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK9_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK9_VSEL,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK9_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK9_VSEL,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck10",
+			.of_match = of_match_ptr("buck10"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_BUCK10,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_buck10_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_buck10_volts),
+			.n_voltages = BD72720_NUM_BUCK_VOLTS,
+			.enable_reg = BD72720_REG_BUCK10_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_BUCK10_VSEL,
+			.vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_BUCK10_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_BUCK10_VSEL,
+			.run_mask = BD72720_MASK_BUCK_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo1",
+			.of_match = of_match_ptr("ldo1"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO1,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+			.n_voltages = BD72720_NUM_LDO12346_VOLTS,
+			.enable_reg = BD72720_REG_LDO1_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO1_VSEL_RB,
+			.vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO1_MODE1,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO1_VSEL_RB,
+			.run_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_reg = BD72720_REG_LDO1_VSEL_I,
+			.idle_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_LDO1_VSEL_S,
+			.suspend_mask = BD72720_MASK_LDO12346_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_LDO1_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+		.reg_inits = bd72720_ldo1_inits,
+		.reg_init_amnt = ARRAY_SIZE(bd72720_ldo1_inits),
+	}, {
+		.desc = {
+			.name = "ldo2",
+			.of_match = of_match_ptr("ldo2"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO2,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+			.n_voltages = BD72720_NUM_LDO12346_VOLTS,
+			.enable_reg = BD72720_REG_LDO2_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO2_VSEL_R,
+			.vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO2_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO2_VSEL_R,
+			.run_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_reg = BD72720_REG_LDO2_VSEL_I,
+			.idle_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_LDO2_VSEL_S,
+			.suspend_mask = BD72720_MASK_LDO12346_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_LDO2_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo3",
+			.of_match = of_match_ptr("ldo3"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO3,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+			.n_voltages = BD72720_NUM_LDO12346_VOLTS,
+			.enable_reg = BD72720_REG_LDO3_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO3_VSEL_R,
+			.vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO3_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO3_VSEL_R,
+			.run_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_reg = BD72720_REG_LDO3_VSEL_I,
+			.idle_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_LDO3_VSEL_S,
+			.suspend_mask = BD72720_MASK_LDO12346_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_LDO3_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo4",
+			.of_match = of_match_ptr("ldo4"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO4,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo1234_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+			.n_voltages = BD72720_NUM_LDO12346_VOLTS,
+			.enable_reg = BD72720_REG_LDO4_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO4_VSEL_R,
+			.vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO4_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO4_VSEL_R,
+			.run_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_reg = BD72720_REG_LDO4_VSEL_I,
+			.idle_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_reg = BD72720_REG_LDO4_VSEL_S,
+			.suspend_mask = BD72720_MASK_LDO12346_VSEL,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_reg = BD72720_REG_LDO4_VSEL_DI,
+			.lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo5",
+			.of_match = of_match_ptr("ldo5"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO5,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo57891011_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+			.n_voltages = BD72720_NUM_LDO_VOLTS,
+			.enable_reg = BD72720_REG_LDO5_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO5_VSEL,
+			.vsel_mask = BD72720_MASK_LDO_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO5_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO5_VSEL,
+			.run_mask = BD72720_MASK_LDO_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo6",
+			.of_match = of_match_ptr("ldo6"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO6,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo6_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo6_volts),
+			.n_voltages = BD72720_NUM_LDO12346_VOLTS,
+			.enable_reg = BD72720_REG_LDO6_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO6_VSEL,
+			.vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO6_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO6_VSEL,
+			.run_mask = BD72720_MASK_LDO12346_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo7",
+			.of_match = of_match_ptr("ldo7"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO7,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo57891011_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+			.n_voltages = BD72720_NUM_LDO_VOLTS,
+			.enable_reg = BD72720_REG_LDO7_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO7_VSEL,
+			.vsel_mask = BD72720_MASK_LDO_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO7_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO7_VSEL,
+			.run_mask = BD72720_MASK_LDO_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo8",
+			.of_match = of_match_ptr("ldo8"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO8,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo57891011_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+			.n_voltages = BD72720_NUM_LDO_VOLTS,
+			.enable_reg = BD72720_REG_LDO8_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO8_VSEL,
+			.vsel_mask = BD72720_MASK_LDO_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO8_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO8_VSEL,
+			.run_mask = BD72720_MASK_LDO_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo9",
+			.of_match = of_match_ptr("ldo9"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO9,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo57891011_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+			.n_voltages = BD72720_NUM_LDO_VOLTS,
+			.enable_reg = BD72720_REG_LDO9_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO9_VSEL,
+			.vsel_mask = BD72720_MASK_LDO_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO9_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO9_VSEL,
+			.run_mask = BD72720_MASK_LDO_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo10",
+			.of_match = of_match_ptr("ldo10"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO10,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo57891011_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+			.n_voltages = BD72720_NUM_LDO_VOLTS,
+			.enable_reg = BD72720_REG_LDO10_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO10_VSEL,
+			.vsel_mask = BD72720_MASK_LDO_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO10_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO10_VSEL,
+			.run_mask = BD72720_MASK_LDO_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo11",
+			.of_match = of_match_ptr("ldo11"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD72720_LDO11,
+			.type = REGULATOR_VOLTAGE,
+			.ops = &bd72720_regulator_ops,
+			.linear_ranges = bd72720_ldo57891011_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+			.n_voltages = BD72720_NUM_LDO_VOLTS,
+			.enable_reg = BD72720_REG_LDO11_ON,
+			.enable_mask = BD72720_MASK_RUN_B_EN,
+			.vsel_reg = BD72720_REG_LDO11_VSEL,
+			.vsel_mask = BD72720_MASK_LDO_VSEL,
+
+			.ramp_delay_table = bd72720_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+			.ramp_reg = BD72720_REG_LDO11_MODE,
+			.ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND |
+				     ROHM_DVS_LEVEL_LPSR,
+			.run_reg = BD72720_REG_LDO11_VSEL,
+			.run_mask = BD72720_MASK_LDO_VSEL,
+			.idle_on_mask = BD72720_MASK_IDLE_EN,
+			.suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+			.lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+		},
+	},
+};
+
+static int bd72720_buck10_ldon_head_mode(struct device *dev,
+					 struct device_node *npreg,
+					 struct regmap *regmap,
+					 struct regulator_desc *buck10_desc)
+{
+	struct device_node *np __free(device_node) =
+		of_get_child_by_name(npreg, "buck10");
+	uint32_t ldon_head;
+	int ldon_val;
+	int ret;
+
+	if (!np) {
+		dev_err(dev, "failed to find buck10 regulator node\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(np, "rohm,ldon-head-millivolt", &ldon_head);
+	if (ret == -EINVAL)
+		return 0;
+	if (ret)
+		return ret;
+
+	/*
+	 * LDON_HEAD mode means the BUCK10 is used to supply LDOs 1-4 and
+	 * the BUCK 10 voltage is automatically set to follow LDO 1-4
+	 * settings. Thus the BUCK10 should not allow voltage [g/s]etting.
+	 */
+	buck10_desc->ops = &bd72720_buck10_ldon_head_op;
+
+	ldon_val = ldon_head / 50 + 1;
+	if (ldon_head > 300) {
+		dev_warn(dev, "Unsupported LDON_HEAD, clamping to 300 mV\n");
+		ldon_val = 7;
+	}
+
+	return regmap_update_bits(regmap, BD72720_REG_LDO1_MODE2,
+				  BD72720_MASK_LDON_HEAD, ldon_val);
+}
+
+static int bd72720_dt_parse(struct device *dev,
+			    struct regulator_desc *buck10_desc,
+			    struct regmap *regmap)
+{
+	struct device_node *nproot __free(device_node) =
+		of_get_child_by_name(dev->parent->of_node, "regulators");
+
+	if (!nproot) {
+		dev_err(dev, "failed to find regulators node\n");
+		return -ENODEV;
+	}
+
+	return bd72720_buck10_ldon_head_mode(dev, nproot, regmap, buck10_desc);
+}
+
 static int bd71828_probe(struct platform_device *pdev)
 {
-	int i, j, ret;
+	int i, j, ret, num_regulators;
 	struct regulator_config config = {
 		.dev = pdev->dev.parent,
 	};
+	enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
+	struct bd71828_regulator_data *rdata;
 
 	config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
 	if (!config.regmap)
 		return -ENODEV;
 
-	for (i = 0; i < ARRAY_SIZE(bd71828_rdata); i++) {
+	switch (chip) {
+	case ROHM_CHIP_TYPE_BD72720:
+		rdata = devm_kmemdup(&pdev->dev, bd72720_rdata,
+				     sizeof(bd72720_rdata), GFP_KERNEL);
+		if (!rdata)
+			return -ENOMEM;
+
+		ret = bd72720_dt_parse(&pdev->dev, &rdata[BD72720_BUCK10_DESC_INDEX].desc,
+				       config.regmap);
+		if (ret)
+			return ret;
+
+		num_regulators = ARRAY_SIZE(bd72720_rdata);
+		break;
+
+	case ROHM_CHIP_TYPE_BD71828:
+		rdata = devm_kmemdup(&pdev->dev, bd71828_rdata,
+				     sizeof(bd71828_rdata), GFP_KERNEL);
+		if (!rdata)
+			return -ENOMEM;
+
+		num_regulators = ARRAY_SIZE(bd71828_rdata);
+
+		break;
+	default:
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "Unsupported device\n");
+	}
+
+	for (i = 0; i < num_regulators; i++) {
 		struct regulator_dev *rdev;
-		const struct bd71828_regulator_data *rd;
+		struct bd71828_regulator_data *rd;
+
+		rd = &rdata[i];
 
-		rd = &bd71828_rdata[i];
+		config.driver_data = rd;
 		rdev = devm_regulator_register(&pdev->dev,
 					       &rd->desc, &config);
 		if (IS_ERR(rdev))
@@ -714,12 +1690,20 @@ static int bd71828_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct platform_device_id bd71828_pmic_id[] = {
+	{ "bd71828-pmic", ROHM_CHIP_TYPE_BD71828 },
+	{ "bd72720-pmic", ROHM_CHIP_TYPE_BD72720 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, bd71828_pmic_id);
+
 static struct platform_driver bd71828_regulator = {
 	.driver = {
 		.name = "bd71828-pmic",
 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 	},
 	.probe = bd71828_probe,
+	.id_table = bd71828_pmic_id,
 };
 
 module_platform_driver(bd71828_regulator);
@@ -727,4 +1711,3 @@ module_platform_driver(bd71828_regulator);
 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
 MODULE_DESCRIPTION("BD71828 voltage regulator driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:bd71828-pmic");
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 08/15] regulator: bd71828: rename IC specific entities
From: Matti Vaittinen @ 2025-10-27 11:46 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5265 bytes --]

The new ROHM BD72720 PMIC has similarities with the BD71828. It makes
sense to support the regulator control for both PMICs using the same
driver. It is often more clear to have the IC specific functions and
globals named starting with the chip-name. So, as a preparatory step,
prefix the BD71828 specific functions and globals with the bd71828.

It would be tempting to try also removing the chip ID from those
functions which will be common for both PMICs. I have bad experiences on
this as it tends to lead to problems when yet another IC is being
supported with the same driver, and we will have some functions used for
all, some for two of the three, and some for just one. At this point
I used to start inventing wildcards like BD718XX or BD7272X. This
approach is pretty much always failing as we tend to eventually have
something like BD73900 - where all the wildcard stuff will break down.

So, my approach these days is to:
 - keep the original chip-id prefix for anything that had it already
   (and avoid the churn).
 - use same prefix for all things that are used by multiple ICs -
   typically the chip-ID of the first chip. This typically matches also
   the driver and file names.
 - use specific chip-ID as a prefix for anything which is specific to
   just one chip.

As a preparatory step to adding the BD72720, add bd71828 prefix to all
commonly usable functions and globals.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Revision history:
 RFCv1 =>:
 - No changes
No functional changes intended.
---
 drivers/regulator/bd71828-regulator.c | 32 +++++++++++++--------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index dd871ffe979c..3d18dbfdb84e 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -28,7 +28,7 @@ struct bd71828_regulator_data {
 	int reg_init_amnt;
 };
 
-static const struct reg_init buck1_inits[] = {
+static const struct reg_init bd71828_buck1_inits[] = {
 	/*
 	 * DVS Buck voltages can be changed by register values or via GPIO.
 	 * Use register accesses by default.
@@ -40,7 +40,7 @@ static const struct reg_init buck1_inits[] = {
 	},
 };
 
-static const struct reg_init buck2_inits[] = {
+static const struct reg_init bd71828_buck2_inits[] = {
 	{
 		.reg = BD71828_REG_PS_CTRL_1,
 		.mask = BD71828_MASK_DVS_BUCK2_CTRL,
@@ -48,7 +48,7 @@ static const struct reg_init buck2_inits[] = {
 	},
 };
 
-static const struct reg_init buck6_inits[] = {
+static const struct reg_init bd71828_buck6_inits[] = {
 	{
 		.reg = BD71828_REG_PS_CTRL_1,
 		.mask = BD71828_MASK_DVS_BUCK6_CTRL,
@@ -56,7 +56,7 @@ static const struct reg_init buck6_inits[] = {
 	},
 };
 
-static const struct reg_init buck7_inits[] = {
+static const struct reg_init bd71828_buck7_inits[] = {
 	{
 		.reg = BD71828_REG_PS_CTRL_1,
 		.mask = BD71828_MASK_DVS_BUCK7_CTRL,
@@ -102,9 +102,9 @@ static int buck_set_hw_dvs_levels(struct device_node *np,
 	return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
 }
 
-static int ldo6_parse_dt(struct device_node *np,
-			 const struct regulator_desc *desc,
-			 struct regulator_config *cfg)
+static int bd71828_ldo6_parse_dt(struct device_node *np,
+				 const struct regulator_desc *desc,
+				 struct regulator_config *cfg)
 {
 	int ret, i;
 	uint32_t uv = 0;
@@ -212,8 +212,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
 			 */
 			.lpsr_on_mask = BD71828_MASK_LPSR_EN,
 		},
-		.reg_inits = buck1_inits,
-		.reg_init_amnt = ARRAY_SIZE(buck1_inits),
+		.reg_inits = bd71828_buck1_inits,
+		.reg_init_amnt = ARRAY_SIZE(bd71828_buck1_inits),
 	},
 	{
 		.desc = {
@@ -253,8 +253,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
 			.lpsr_reg = BD71828_REG_BUCK2_SUSP_VOLT,
 			.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
 		},
-		.reg_inits = buck2_inits,
-		.reg_init_amnt = ARRAY_SIZE(buck2_inits),
+		.reg_inits = bd71828_buck2_inits,
+		.reg_init_amnt = ARRAY_SIZE(bd71828_buck2_inits),
 	},
 	{
 		.desc = {
@@ -399,8 +399,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
 			.lpsr_reg = BD71828_REG_BUCK6_SUSP_VOLT,
 			.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
 		},
-		.reg_inits = buck6_inits,
-		.reg_init_amnt = ARRAY_SIZE(buck6_inits),
+		.reg_inits = bd71828_buck6_inits,
+		.reg_init_amnt = ARRAY_SIZE(bd71828_buck6_inits),
 	},
 	{
 		.desc = {
@@ -440,8 +440,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
 			.lpsr_reg = BD71828_REG_BUCK7_SUSP_VOLT,
 			.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
 		},
-		.reg_inits = buck7_inits,
-		.reg_init_amnt = ARRAY_SIZE(buck7_inits),
+		.reg_inits = bd71828_buck7_inits,
+		.reg_init_amnt = ARRAY_SIZE(bd71828_buck7_inits),
 	},
 	{
 		.desc = {
@@ -633,7 +633,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
 			 * LDO6 only supports enable/disable for all states.
 			 * Voltage for LDO6 is fixed.
 			 */
-			.of_parse_cb = ldo6_parse_dt,
+			.of_parse_cb = bd71828_ldo6_parse_dt,
 		},
 	}, {
 		.desc = {
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 06/15] mfd: rohm-bd71828: Use regmap_reg_range()
From: Matti Vaittinen @ 2025-10-27 11:46 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3249 bytes --]

The regmap range tables tend to be somewhat verbose. Using the
regmap_reg_range() can make the definitions slightly mode compact.

Tidy the regmap range tables by using the regmap_reg_range().

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
---
Revision history:
 RFCv1 => v2:
 - New patch
---
 drivers/mfd/rohm-bd71828.c | 64 +++++++++++---------------------------
 1 file changed, 18 insertions(+), 46 deletions(-)

diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
index 84a64c3b9c9f..2a43005b67ee 100644
--- a/drivers/mfd/rohm-bd71828.c
+++ b/drivers/mfd/rohm-bd71828.c
@@ -157,55 +157,27 @@ static struct mfd_cell bd71828_mfd_cells[] = {
 };
 
 static const struct regmap_range bd71815_volatile_ranges[] = {
-	{
-		.range_min = BD71815_REG_SEC,
-		.range_max = BD71815_REG_YEAR,
-	}, {
-		.range_min = BD71815_REG_CONF,
-		.range_max = BD71815_REG_BAT_TEMP,
-	}, {
-		.range_min = BD71815_REG_VM_IBAT_U,
-		.range_max = BD71815_REG_CC_CTRL,
-	}, {
-		.range_min = BD71815_REG_CC_STAT,
-		.range_max = BD71815_REG_CC_CURCD_L,
-	}, {
-		.range_min = BD71815_REG_VM_BTMP_MON,
-		.range_max = BD71815_REG_VM_BTMP_MON,
-	}, {
-		.range_min = BD71815_REG_INT_STAT,
-		.range_max = BD71815_REG_INT_UPDATE,
-	}, {
-		.range_min = BD71815_REG_VM_VSYS_U,
-		.range_max = BD71815_REG_REX_CTRL_1,
-	}, {
-		.range_min = BD71815_REG_FULL_CCNTD_3,
-		.range_max = BD71815_REG_CCNTD_CHG_2,
-	},
+	regmap_reg_range(BD71815_REG_SEC, BD71815_REG_YEAR),
+	regmap_reg_range(BD71815_REG_CONF, BD71815_REG_BAT_TEMP),
+	regmap_reg_range(BD71815_REG_VM_IBAT_U, BD71815_REG_CC_CTRL),
+	regmap_reg_range(BD71815_REG_CC_STAT, BD71815_REG_CC_CURCD_L),
+	regmap_reg_range(BD71815_REG_VM_BTMP_MON, BD71815_REG_VM_BTMP_MON),
+	regmap_reg_range(BD71815_REG_INT_STAT, BD71815_REG_INT_UPDATE),
+	regmap_reg_range(BD71815_REG_VM_VSYS_U, BD71815_REG_REX_CTRL_1),
+	regmap_reg_range(BD71815_REG_FULL_CCNTD_3, BD71815_REG_CCNTD_CHG_2),
 };
 
 static const struct regmap_range bd71828_volatile_ranges[] = {
-	{
-		.range_min = BD71828_REG_PS_CTRL_1,
-		.range_max = BD71828_REG_PS_CTRL_1,
-	}, {
-		.range_min = BD71828_REG_PS_CTRL_3,
-		.range_max = BD71828_REG_PS_CTRL_3,
-	}, {
-		.range_min = BD71828_REG_RTC_SEC,
-		.range_max = BD71828_REG_RTC_YEAR,
-	}, {
-		/*
-		 * For now make all charger registers volatile because many
-		 * needs to be and because the charger block is not that
-		 * performance critical.
-		 */
-		.range_min = BD71828_REG_CHG_STATE,
-		.range_max = BD71828_REG_CHG_FULL,
-	}, {
-		.range_min = BD71828_REG_INT_MAIN,
-		.range_max = BD71828_REG_IO_STAT,
-	},
+	regmap_reg_range(BD71828_REG_PS_CTRL_1, BD71828_REG_PS_CTRL_1),
+	regmap_reg_range(BD71828_REG_PS_CTRL_3, BD71828_REG_PS_CTRL_3),
+	regmap_reg_range(BD71828_REG_RTC_SEC, BD71828_REG_RTC_YEAR),
+	/*
+	 * For now make all charger registers volatile because many
+	 * needs to be and because the charger block is not that
+	 * performance critical.
+	 */
+	regmap_reg_range(BD71828_REG_CHG_STATE, BD71828_REG_CHG_FULL),
+	regmap_reg_range(BD71828_REG_INT_MAIN, BD71828_REG_IO_STAT),
 };
 
 static const struct regmap_access_table bd71815_volatile_regs = {
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 05/15] dt-bindings: leds: bd72720: Add BD72720
From: Matti Vaittinen @ 2025-10-27 11:46 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1904 bytes --]

Add the ROHM BD72720 documentation to the binding documents.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
---

NOTE: The Linux LED driver does currently have: values
bd72720-grnled and bd72720-ambled for the rohm,led-compatible. These are
handled identically to the existing bd71828-grnled and bd71828-ambled
and should be removed from the driver. Thus they are not documented in
the binding document.

Furthermore, the BD72720 Linux driver does not use the compatible property
from the LED node. The Linux driver is load and probed based on the PMIC
compatible in the MFD node. Thus no compatible string for the BD72720
LED node is added.

---
Revision history:
 RFCv1 =>:
 - No changes
---
 .../devicetree/bindings/leds/rohm,bd71828-leds.yaml        | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml b/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml
index b7a3ef76cbf4..64cc40523e3d 100644
--- a/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml
+++ b/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml
@@ -10,11 +10,12 @@ maintainers:
   - Matti Vaittinen <mazziesaccount@gmail.com>
 
 description: |
-  This module is part of the ROHM BD71828 MFD device. For more details
-  see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml.
+  This module is part of the ROHM BD71828 and BD72720 MFD device. For more
+  details see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
+  and Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
 
   The LED controller is represented as a sub-node of the PMIC node on the device
-  tree.
+  tree. This should be located under "leds" - node in PMIC node.
 
   The device has two LED outputs referred as GRNLED and AMBLED in data-sheet.
 
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 04/15] dt-bindings: mfd: ROHM BD72720
From: Matti Vaittinen @ 2025-10-27 11:45 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 10253 bytes --]

The ROHM BD72720 is a power management IC integrating regulators, GPIOs,
charger, LEDs, RTC and a clock gate.

Add dt-binding doc for ROHM BD72720.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Revision history:
 RFCv1 => v2:
 - Typofixes
---
 .../bindings/mfd/rohm,bd72720-pmic.yaml       | 269 ++++++++++++++++++
 1 file changed, 269 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml

diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
new file mode 100644
index 000000000000..b0d4bc01d199
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
@@ -0,0 +1,269 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd72720-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD72720 Power Management Integrated Circuit
+
+maintainers:
+  - Matti Vaittinen <mazziesaccount@gmail.com>
+
+description: |
+  BD72720 is a single-chip power management IC for battery-powered portable
+  devices. The BD72720 integrates 10 bucks and 11 LDOs, and a 3000 mA
+  switching charger. The IC also includes a Coulomb counter, a real-time
+  clock (RTC), GPIOs and a 32.768 kHz clock gate.
+
+# In addition to the properties found from the charger node, the ROHM BD72720
+# uses properties from a static battery node. Please see the:
+# Documentation/devicetree/bindings/power/supply/rohm,vdr-battery.yaml
+#
+# Following properties are used
+# when present:
+#
+# charge-full-design-microamp-hours: Battry capacity in mAh
+# voltage-max-design-microvolt:      Maximum voltage
+# voltage-min-design-microvolt:      Minimum voltage system is still operating.
+# degrade-cycle-microamp-hours:      Capacity lost due to aging at each full
+#                                    charge cycle.
+# ocv-capacity-celsius:              Array of OCV table temperatures. 1/table.
+# ocv-capacity-table-<N>:            Table of OCV voltage/SOC pairs. Corresponds
+#                                    N.th temperature in ocv-capacity-celsius
+#
+# ROHM specific properties:
+# rohm,voltage-vdr-thresh-microvolt: Threshold for starting the VDR correction
+# rohm,volt-drop-soc:                Table of capacity values matching the
+#                                    values in VDR tables.
+# rohm,volt-drop-high-temp-microvolt: VDR table for high temperature
+# rohm,volt-drop-normal-temp-microvolt: VDR table for normal temperature
+# rohm,volt-drop-low-temp-microvolt:  VDR table for low temperature
+# rohm,volt-drop-very-low-temp-microvolt: VDR table for very low temperature
+#
+# VDR tables are (usually) determined for a specific battery by ROHM.
+# The battery node would then be referred from the charger node:
+#
+# monitored-battery = <&battery>;
+
+properties:
+  compatible:
+    const: rohm,bd72720
+
+  reg:
+    description:
+      I2C slave address.
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  gpio-controller: true
+
+  "#gpio-cells":
+    const: 2
+    description: |
+      The first cell is the pin number and the second cell is used to specify
+      flags. See ../gpio/gpio.txt for more information.
+
+  clocks:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 0
+
+  clock-output-names:
+    const: bd71828-32k-out
+
+  rohm,clkout-open-drain:
+    description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 1
+
+  rohm,charger-sense-resistor-milli-ohms:
+    minimum: 10
+    maximum: 50
+    description: |
+      BD72720 has a SAR ADC for measuring charging currents. External sense
+      resistor (RSENSE in data sheet) should be used. If some other but
+      30 mOhm resistor is used the resistance value should be given here in
+      milli Ohms.
+
+  regulators:
+    $ref: ../regulator/rohm,bd77270-regulator.yaml
+    description:
+      List of child nodes that specify the regulators.
+
+  leds:
+    $ref: ../leds/rohm,bd71828-leds.yaml
+
+  rohm,pin-dvs0:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      BD72720 has 4 different OTP options to determine the use of dvs0-pin.
+      OTP0 - regulator RUN state control.
+      OTP1 - GPI.
+      OTP2 - GPO.
+      OTP3 - Power sequencer output.
+      This property specifies the use of the pin.
+    enum:
+      - dvs-input
+      - gpi
+      - gpo
+
+  rohm,pin-dvs1:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      see rohm,pin-dvs0
+    enum:
+      - dvs-input
+      - gpi
+      - gpo
+
+  rohm,pin-exten0:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: BD72720 has an OTP option to use exten0-pin for different
+      purposes. Set this property accordingly.
+    const: gpo
+
+  rohm,pin-exten1:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: BD72720 has an OTP option to use exten1-pin for different
+      purposes. Set this property accordingly.
+    const: gpo
+
+  rohm,pin-fault_b:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: BD72720 has an OTP option to use fault_b-pin for different
+      purposes. Set this property accordingly.
+    const: gpo
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - "#clock-cells"
+  - regulators
+  - gpio-controller
+  - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        pmic: pmic@4b {
+            compatible = "rohm,bd71828";
+            reg = <0x4b>;
+
+            interrupt-parent = <&gpio1>;
+            interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+            clocks = <&osc 0>;
+            #clock-cells = <0>;
+            clock-output-names = "bd71828-32k-out";
+
+            gpio-controller;
+            #gpio-cells = <2>;
+            gpio-reserved-ranges = <0 1>, <2 1>;
+
+            rohm,charger-sense-resistor-ohms = <10000000>;
+
+            regulators {
+                buck1: BUCK1 {
+                    regulator-name = "buck1";
+                    regulator-min-microvolt = <500000>;
+                    regulator-max-microvolt = <2000000>;
+                    regulator-ramp-delay = <2500>;
+                };
+                buck2: BUCK2 {
+                    regulator-name = "buck2";
+                    regulator-min-microvolt = <500000>;
+                    regulator-max-microvolt = <2000000>;
+                    regulator-ramp-delay = <2500>;
+                };
+                buck3: BUCK3 {
+                    regulator-name = "buck3";
+                    regulator-min-microvolt = <1200000>;
+                    regulator-max-microvolt = <2000000>;
+                };
+                buck4: BUCK4 {
+                    regulator-name = "buck4";
+                    regulator-min-microvolt = <1000000>;
+                    regulator-max-microvolt = <1800000>;
+                };
+                buck5: BUCK5 {
+                    regulator-name = "buck5";
+                    regulator-min-microvolt = <2500000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                buck6: BUCK6 {
+                    regulator-name = "buck6";
+                    regulator-min-microvolt = <500000>;
+                    regulator-max-microvolt = <2000000>;
+                    regulator-ramp-delay = <2500>;
+                };
+                buck7: BUCK7 {
+                    regulator-name = "buck7";
+                    regulator-min-microvolt = <500000>;
+                    regulator-max-microvolt = <2000000>;
+                    regulator-ramp-delay = <2500>;
+                };
+                ldo1: LDO1 {
+                    regulator-name = "ldo1";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo2: LDO2 {
+                    regulator-name = "ldo2";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo3: LDO3 {
+                    regulator-name = "ldo3";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo4: LDO4 {
+                    regulator-name = "ldo4";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo5: LDO5 {
+                    regulator-name = "ldo5";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+                ldo6: LDO6 {
+                    regulator-name = "ldo6";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <1800000>;
+                };
+                ldo7_reg: LDO7 {
+                    regulator-name = "ldo7";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+            };
+
+            leds {
+                compatible = "rohm,bd71828-leds";
+
+                led-1 {
+                    rohm,led-compatible = "bd71828-grnled";
+                    function = LED_FUNCTION_INDICATOR;
+                    color = <LED_COLOR_ID_GREEN>;
+                };
+                led-2 {
+                    rohm,led-compatible = "bd71828-ambled";
+                    function = LED_FUNCTION_CHARGING;
+                    color = <LED_COLOR_ID_AMBER>;
+                };
+            };
+        };
+    };
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 03/15] dt-bindings: power: supply: BD72720 managed battery
From: Matti Vaittinen @ 2025-10-27 11:45 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5527 bytes --]

The BD72720 PMIC has a battery charger + coulomb counter block. These
can be used to manage charging of a lithium-ion battery and to do fuel
gauging.

ROHM has developed a so called "zero-correction" -algorithm to improve
the fuel-gauging accuracy close to the point where battery is depleted.
This relies on battery specific "VDR" tables, which are measured from
the battery, and which describe the voltage drop rate. More thorough
explanation about the "zero correction" and "VDR" parameters is here:
https://lore.kernel.org/all/676253b9-ff69-7891-1f26-a8b5bb5a421b@fi.rohmeurope.com/

Document the VDR zero-correction specific battery properties used by the
BD72720 and some other ROHM chargers.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
---
Revision history:
 RFCv1 => v2:
 - Add units to rohm,volt-drop-soc (tenths of %)
 - Give real temperatures matching the VDR tables, instead of vague
   'high', 'normal', 'low', 'very low'. (Add table of temperatures and
   use number matching the right temperature index in the VDR table name).
 - Fix typoed 'algorithm' in commit message.

The parameters are describing the battery voltage drop rates - so they
are properties of the battery, not the charger. Thus they do not belong
in the charger node.

The right place for them is the battery node, which is described by the
generic "battery.yaml". I was not comfortable with adding these
properties to the generic battery.yaml because they are:
  - Meaningful only for those charger drivers which have the VDR
    algorithm implemented. (And even though the algorithm is not charger
    specific, AFAICS, it is currently only used by some ROHM PMIC
    drivers).
  - Technique of measuring the VDR tables for a battery is not widely
    known. AFAICS, only folks at ROHM are measuring those for some
    customer products. We do have those tables available for some of the
    products though (Kobo?).
---
 .../power/supply/rohm,vdr-battery.yaml        | 80 +++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/rohm,vdr-battery.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/rohm,vdr-battery.yaml b/Documentation/devicetree/bindings/power/supply/rohm,vdr-battery.yaml
new file mode 100644
index 000000000000..1ab3418d4338
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/rohm,vdr-battery.yaml
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/rohm,vdr-battery.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Battery managed by the BD72720 PMIC
+
+maintainers:
+  - Matti Vaittinen <mazziesaccount@gmail.com>
+
+description:
+  A battery which has VDR parameters measuerd for ROHM chargers.
+
+allOf:
+  - $ref: battery.yaml#
+
+properties:
+  rohm,voltage-vdr-thresh-microvolt:
+    description: Threshold for starting the VDR correction
+
+  rohm,volt-drop-soc:
+    description: Table of capacity values matching the values in VDR tables.
+      The value should be given as tenths of a percentage.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+
+  rohm,volt-drop-temperatures-millicelsius:
+    description: An array containing the temperature in milli celsius, for each
+      of the VDR lookup table.
+
+patternProperties:
+  '^rohm,volt-drop-[0-9]-microvolt':
+    description: Table of the voltage drop rate (VDR) values. Each entry in the
+      table should match a capacity value in the rohm,volt-drop-soc table.
+      Furthermore, the values should be obtained for the temperature given in
+      rohm,volt-drop-temperatures-millicelsius table at index matching the
+      number in this table's name.
+
+additionalProperties: false
+
+examples:
+  - |
+    power {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      battery: battery {
+        compatible = "simple-battery";
+
+        ocv-capacity-celsius = <25>;
+        ocv-capacity-table-0 = <4200000 100 4184314 100 4140723 95 4099487 90
+          4060656 85 4024350 80 3991121 75 3954379 70 3913265 65 3877821 60
+          3855577 55 3837466 50 3822194 45 3809012 40 3795984 35 3780647 30
+          3760505 25 3741532 20 3718837 15 3696698 10 3690594 5 3581427 0>;
+
+        rohm,volt-drop-soc = <1000 1000 950 900 850 800 750 700 650 600 550 500
+          450 400 350 300 250 200 150 100 50 00 (-50)>;
+
+        rohm,volt-drop-temperatures-millicelsius = <45000 25000 5000 0>;
+
+        rohm,volt-drop-0-microvolt =  <100 100 102 104 106 109 114 124
+          117 107 107 109 112 116 117 108 109 109 108 109 122 126 130>;
+
+        rohm,volt-drop-1-microvolt = <100 100 102 105 98 100 105 102
+          101 99 98 100 103 105 109 117 111 109 110 114 128 141 154>;
+
+        rohm,volt-drop-2-microvolt = <100 100 98 107 112 114 118 118 112
+          108 108 110 111 113 117 123 131 144 157 181 220 283 399>;
+
+        rohm,volt-drop-3-temp-microvolt = <86 86 105 109 114 110 115 115
+          110 108 110 112 114 118 124 134 136 160 177 201 241 322 403>;
+
+        rohm,voltage-vdr-thresh-microvolt = <4150000>;
+
+        charge-full-design-microamp-hours = <1799000>;
+        voltage-max-design-microvolt = <4200000>;
+        voltage-min-design-microvolt = <3500000>;
+        degrade-cycle-microamp-hours = <131>;
+      };
+    };
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 02/15] dt-bindings: Add trickle-charge upper limit
From: Matti Vaittinen @ 2025-10-27 11:45 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1418 bytes --]

Some of the chargers for lithium-ion batteries use a trickle-charging as
a first charging phase for very empty batteries, to "wake-up" the battery.
Trickle-charging is a low current, constant current phase. After the
voltage of the very empty battery has reached an upper limit for
trickle charging, the pre-charge phase is started with a higher current.

Allow defining the upper limit for trickle charging voltage, after which
the charging should be changed to the pre-charging.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

---
Revision history:
 RFCv1 =>:
 - No changes
---
 Documentation/devicetree/bindings/power/supply/battery.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/supply/battery.yaml b/Documentation/devicetree/bindings/power/supply/battery.yaml
index 491488e7b970..66bed24b3dee 100644
--- a/Documentation/devicetree/bindings/power/supply/battery.yaml
+++ b/Documentation/devicetree/bindings/power/supply/battery.yaml
@@ -66,6 +66,9 @@ properties:
   trickle-charge-current-microamp:
     description: current for trickle-charge phase
 
+  tricklecharge-upper-limit-microvolt:
+    description: limit when to change to precharge from trickle charge
+
   precharge-current-microamp:
     description: current for pre-charge phase
 
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 01/15] dt-bindings: regulator: ROHM BD72720
From: Matti Vaittinen @ 2025-10-27 11:44 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc
In-Reply-To: <cover.1761564043.git.mazziesaccount@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 7074 bytes --]

The ROHM BD72720 is a new PMIC with 10 BUCk and 11 LDO regulators.

The BD72720 is designed to support using the BUCK10 as a supply for
the LDOs 1 to 4. When the BUCK10 is used for this, it can be set to a
LDON_HEAD mode. In this mode, the BUCK10 voltage can't be controlled by
software, but the voltage is adjusted by PMIC to match the LDO1 .. LDO4
voltages with a given offset. Offset can be 50mV .. 300mV and is
changeable at 50mV steps.

Add 'ldon-head-millivolt' property to denote a board which is designed
to utilize the LDON_HEAD mode.

All other properties are already existing.

Add dt-binding doc for ROHM BD72720 regulators to make it usable.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Revision history:
 RFCv1 =>:
 - No changes
---
 .../regulator/rohm,bd72720-regulator.yaml     | 153 ++++++++++++++++++
 1 file changed, 153 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd72720-regulator.yaml

diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd72720-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd72720-regulator.yaml
new file mode 100644
index 000000000000..665086f56928
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd72720-regulator.yaml
@@ -0,0 +1,153 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd72720-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD72720 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen <mazziesaccount@gmail.com>
+
+description: |
+  This module is part of the ROHM BD72720 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml.
+
+  The regulator controller is represented as a sub-node of the PMIC node
+  on the device tree.
+
+  Regulator nodes should be named to BUCK_<number> and LDO_<number>.
+  The valid names for BD72720 regulator nodes are
+  buck1, buck2, buck3, buck4, buck5, buck6, buck7, buck8, buck9, buck10
+  ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, ldo8, ldo9, ldo10, ldo11
+
+patternProperties:
+  "^ldo[1-11]$":
+    type: object
+    description:
+      Properties for single LDO regulator.
+    $ref: regulator.yaml#
+
+    properties:
+      regulator-name:
+        pattern: "^ldo[1-11]$"
+        description:
+          should be "ldo1", ..., "ldo11"
+
+      rohm,dvs-run-voltage:
+        description:
+          PMIC default "RUN" state voltage in uV. See below table for
+          LDOs which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-idle-voltage:
+        description:
+          PMIC default "IDLE" state voltage in uV. See below table for
+          LDOs which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-suspend-voltage:
+        description:
+          PMIC default "SUSPEND" state voltage in uV. See below table for
+          LDOs which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-lpsr-voltage:
+        description:
+          PMIC default "deep-idle" state voltage in uV. See below table for
+          LDOs which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+        # Supported default DVS states:
+        #     ldo        |    run     |   idle    | suspend   | lpsr
+        # --------------------------------------------------------------
+        # 1, 2, 3, and 4 | supported  | supported | supported | supported
+        # --------------------------------------------------------------
+        # 5 - 11         |                    supported (*)
+        # --------------------------------------------------------------
+        #
+        # (*) All states use same voltage but have own enable / disable
+        #      settings. Voltage 0 can be specified for a state to make
+        #      regulator disabled on that state.
+
+    unevaluatedProperties: false
+
+  "^buck[1-10]$":
+    type: object
+    description:
+      Properties for single BUCK regulator.
+    $ref: regulator.yaml#
+
+    properties:
+      regulator-name:
+        pattern: "^buck[1-10]$"
+        description:
+          should be "buck1", ..., "buck10"
+
+      rohm,ldon-head-millivolt:
+        description:
+          Set this on boards where BUCK10 is used to supply LDOs 1-4. The bucki
+          voltage will be changed by the PMIC to follow the LDO output voltages
+          with the offset voltage given here. This will improve the LDO efficiency.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 50
+        maximum: 300
+
+      rohm,dvs-run-voltage:
+        description:
+          PMIC default "RUN" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-idle-voltage:
+        description:
+          PMIC default "IDLE" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-suspend-voltage:
+        description:
+          PMIC default "SUSPEND" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-lpsr-voltage:
+        description:
+          PMIC default "deep-idle" state voltage in uV. See below table for
+          bucks which support this. 0 means disabled.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 3300000
+
+        # Supported default DVS states:
+        #     buck       |    run     |   idle    | suspend   | lpsr
+        # --------------------------------------------------------------
+        # 1, 2, 3, and 4 | supported  | supported | supported | supported
+        # --------------------------------------------------------------
+        # 5 - 10    |                    supported (*)
+        # --------------------------------------------------------------
+        #
+        # (*) All states use same voltage but have own enable / disable
+        #      settings. Voltage 0 can be specified for a state to make
+        #      regulator disabled on that state.
+
+    required:
+      - regulator-name
+
+    unevaluatedProperties: false
+
+additionalProperties: false
-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* [PATCH v2 00/15] Support ROHM BD72720 PMIC
From: Matti Vaittinen @ 2025-10-27 11:44 UTC (permalink / raw)
  To: Matti Vaittinen, Matti Vaittinen
  Cc: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Sebastian Reichel, Liam Girdwood, Mark Brown,
	Michael Turquette, Stephen Boyd, Matti Vaittinen, Linus Walleij,
	Bartosz Golaszewski, Andreas Kemnade, Alexandre Belloni,
	linux-leds, devicetree, linux-kernel, linux-pm, linux-clk,
	linux-gpio, linux-rtc

[-- Attachment #1: Type: text/plain, Size: 3225 bytes --]

The ROHM BD72720 is a new power management IC for portable, battery
powered devices. It integrates 10 BUCKs and 11 LDOs, RTC, charger, LEDs,
GPIOs and a clock gate. To me the BD72720 seems like a successor to the
BD71828 and BD71815 PMICs.

This series depends on the series: "[PATCH v5 0/3] power: supply: add
charger for BD71828":
https://lore.kernel.org/all/20250918-bd71828-charger-v5-0-851164839c28@kemnade.info/
sent by Andreas. The power-supplly and MAINTAINERs patches (2/3 and 3/3)
from that serties aren't merged yet.

Revision history:
  RFCv1 => v2:
  - Drop RFC status
  - Use stacked regmaps to hide secondary map from the sub-drivers
  - Quite a few styling fixes and improvements as suggested by
    reviewers. More accurate changelog in individual patches.
  - Link to v1:
    https://lore.kernel.org/all/cover.1759824376.git.mazziesaccount@gmail.com/

---

Matti Vaittinen (15):
  dt-bindings: regulator: ROHM BD72720
  dt-bindings: Add trickle-charge upper limit
  dt-bindings: power: supply: BD72720 managed battery
  dt-bindings: mfd: ROHM BD72720
  dt-bindings: leds: bd72720: Add BD72720
  mfd: rohm-bd71828: Use regmap_reg_range()
  mfd: bd71828: Support ROHM BD72720
  regulator: bd71828: rename IC specific entities
  regulator: bd71828: Support ROHM BD72720
  gpio: Support ROHM BD72720 gpios
  clk: clk-bd718x7: Support BD72720 clk gate
  rtc: bd70528: Support BD72720 rtc
  power: supply: bd71828: Support wider register addresses
  power: supply: bd71828-power: Support ROHM BD72720
  MAINTAINERS: Add ROHM BD72720 PMIC

 .../bindings/leds/rohm,bd71828-leds.yaml      |    7 +-
 .../bindings/mfd/rohm,bd72720-pmic.yaml       |  269 +++++
 .../bindings/power/supply/battery.yaml        |    3 +
 .../power/supply/rohm,vdr-battery.yaml        |   80 ++
 .../regulator/rohm,bd72720-regulator.yaml     |  153 +++
 MAINTAINERS                                   |    2 +
 drivers/clk/Kconfig                           |    4 +-
 drivers/clk/clk-bd718x7.c                     |   10 +-
 drivers/gpio/Kconfig                          |    9 +
 drivers/gpio/Makefile                         |    1 +
 drivers/gpio/gpio-bd72720.c                   |  281 +++++
 drivers/mfd/Kconfig                           |   18 +-
 drivers/mfd/rohm-bd71828.c                    |  546 ++++++++-
 drivers/power/supply/bd71828-power.c          |  160 ++-
 drivers/regulator/Kconfig                     |    8 +-
 drivers/regulator/bd71828-regulator.c         | 1025 ++++++++++++++++-
 drivers/rtc/Kconfig                           |    3 +-
 drivers/rtc/rtc-bd70528.c                     |   21 +-
 include/linux/mfd/rohm-bd72720.h              |  634 ++++++++++
 include/linux/mfd/rohm-generic.h              |    1 +
 20 files changed, 3106 insertions(+), 129 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/rohm,vdr-battery.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd72720-regulator.yaml
 create mode 100644 drivers/gpio/gpio-bd72720.c
 create mode 100644 include/linux/mfd/rohm-bd72720.h

-- 
2.51.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH v2 0/4] fix the SpacemiT P1 Kconfig and resend the K1 I2C ILCR patch.
From: Aurelien Jarno @ 2025-10-27 10:24 UTC (permalink / raw)
  To: Troy Mitchell
  Cc: Lee Jones, Yixun Lan, Alex Elder, Andi Shyti, Alexandre Belloni,
	Liam Girdwood, Mark Brown, linux-kernel, linux-riscv, spacemit,
	linux-i2c, linux-rtc, kernel test robot
In-Reply-To: <20251027-p1-kconfig-fix-v2-0-49688f30bae8@linux.spacemit.com>

Hi,

On 2025-10-27 13:48, Troy Mitchell wrote:
> Since P1 Kconfig directly selects K1_I2C, after the I2C ILCR patch was
> merged, the driver would fail [1] when COMMON_CLK was not selected.
> 
> This series fixes the P1 Kconfig and resends the I2C ILCR patch(This
> patch has reverted by maintainer [2]). In addition, the Kconfig for
> P1's two subdevices, regulator and RTC, has been updated to use
> 'depends on MFD_SPACEMIT_P1' instead of 'select'.
> 
> Link: https://lore.kernel.org/oe-kbuild-all/202510202150.2qXd8e7Y-lkp@intel.com/ [1]
> Link: https://lore.kernel.org/all/sdhkjmi5l2m4ua4zqkwkecbihul5bc2dbmitudwfd57y66mdht@6ipjfyz7dtmx/ [2]
> 
> Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>

I think this series misses a patch to add a default value for 
MFD_SPACEMIT_P1. Otherwise it doesn't make sense to define a default 
value for the ones depending on it (RTC_DRV_SPACEMIT_P1, 
REGULATOR_SPACEMIT_P1).

Regards
Aurelien

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien@aurel32.net                     http://aurel32.net

^ permalink raw reply

* [PATCH v2 3/4] rtc: spacemit: MFD_SPACEMIT_P1 as dependencies
From: Troy Mitchell @ 2025-10-27  5:48 UTC (permalink / raw)
  To: Lee Jones, Yixun Lan, Alex Elder, Andi Shyti, Alexandre Belloni,
	Liam Girdwood, Mark Brown
  Cc: linux-kernel, linux-riscv, spacemit, linux-i2c, linux-rtc,
	Troy Mitchell
In-Reply-To: <20251027-p1-kconfig-fix-v2-0-49688f30bae8@linux.spacemit.com>

RTC_DRV_SPACEMIT_P1 is a subdevice of P1 and should depend on
MFD_SPACEMIT_P1 rather than selecting it directly. Using 'select'
does not always respect the parent's dependencies, so 'depends on'
is the safer and more correct choice.

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
 drivers/rtc/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2933c41c77c88e60df721fe65b9c8afb995ae51e..1ea0123e386f2b140e1a63a182d1781f6a17e835 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -409,7 +409,7 @@ config RTC_DRV_MAX77686
 config RTC_DRV_SPACEMIT_P1
 	tristate "SpacemiT P1 RTC"
 	depends on ARCH_SPACEMIT || COMPILE_TEST
-	select MFD_SPACEMIT_P1
+	depends on MFD_SPACEMIT_P1
 	default ARCH_SPACEMIT
 	help
 	  Enable support for the RTC function in the SpacemiT P1 PMIC.

-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 4/4] regulator: spacemit: MFD_SPACEMIT_P1 as dependencies
From: Troy Mitchell @ 2025-10-27  5:48 UTC (permalink / raw)
  To: Lee Jones, Yixun Lan, Alex Elder, Andi Shyti, Alexandre Belloni,
	Liam Girdwood, Mark Brown
  Cc: linux-kernel, linux-riscv, spacemit, linux-i2c, linux-rtc,
	Troy Mitchell
In-Reply-To: <20251027-p1-kconfig-fix-v2-0-49688f30bae8@linux.spacemit.com>

REGULATOR_SPACEMIT_P1 is a subdevice of P1 and should depend on
MFD_SPACEMIT_P1 rather than selecting it directly. Using 'select'
does not always respect the parent's dependencies, so 'depends on'
is the safer and more correct choice.

Since MFD_SPACEMIT_P1 already depends on I2C_K1, the dependency
in REGULATOR_SPACEMIT_P1 is now redundant.

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
 drivers/regulator/Kconfig | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d84f3d054c59d86d91d859808aa73a3b609d16d0..f5ee804077cfcb300ca5cf5d865b6684943cd749 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1455,8 +1455,7 @@ config REGULATOR_SLG51000
 config REGULATOR_SPACEMIT_P1
 	tristate "SpacemiT P1 regulators"
 	depends on ARCH_SPACEMIT || COMPILE_TEST
-	depends on I2C
-	select MFD_SPACEMIT_P1
+	depends on MFD_SPACEMIT_P1
 	default ARCH_SPACEMIT
 	help
 	  Enable support for regulators implemented by the SpacemiT P1

-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 2/4] i2c: spacemit: configure ILCR for accurate SCL frequency
From: Troy Mitchell @ 2025-10-27  5:48 UTC (permalink / raw)
  To: Lee Jones, Yixun Lan, Alex Elder, Andi Shyti, Alexandre Belloni,
	Liam Girdwood, Mark Brown
  Cc: linux-kernel, linux-riscv, spacemit, linux-i2c, linux-rtc,
	Troy Mitchell
In-Reply-To: <20251027-p1-kconfig-fix-v2-0-49688f30bae8@linux.spacemit.com>

The SpacemiT I2C controller's SCL (Serial Clock Line) frequency for
master mode operations is determined by the ILCR (I2C Load Count Register).
Previously, the driver relied on the hardware's reset default
values for this register.

The hardware's default ILCR values (SLV=0x156, FLV=0x5d) yield SCL
frequencies lower than intended. For example, with the default
31.5 MHz input clock, these default settings result in an SCL
frequency of approximately 93 kHz (standard mode) when targeting 100 kHz,
and approximately 338 kHz (fast mode) when targeting 400 kHz.
These frequencies are below the 100 kHz/400 kHz nominal speeds.

This patch integrates the SCL frequency management into
the Common Clock Framework (CCF). Specifically, the ILCR register,
which acts as a frequency divider for the SCL clock, is now registered
as a managed clock (scl_clk) within the CCF.

This patch also cleans up unnecessary whitespace
in the included header files.

Reviewed-by: Yixun Lan <dlan@gentoo.org>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
This patch was affected by the P1 Kconfig, which caused the maintainer
to revert it.
The current commit is a direct cherry-pick and reserves the original changelog.
This note is to clarify for anyone who sees the cover letter marked as v2
while the changelog entries reach v4.
---
Changelog in v4:
- initialize clk_init_data with {} so that init.flags is implicitly set to 0
- minor cleanup and style fixes for better readability
- remove unused spacemit_i2c_scl_clk_exclusive_put() cleanup callback
- replace clk_set_rate_exclusive()/clk_rate_exclusive_put() pair with clk_set_rate()
- simplify LCR LV field macros by using FIELD_GET/FIELD_MAX helpers
- Link to v3: https://lore.kernel.org/all/20250814-k1-i2c-ilcr-v3-1-317723e74bcd@linux.spacemit.com/

Changelog in v3:
- use MASK macro in `recalc_rate` function
- rename clock name
- Link to v2: https://lore.kernel.org/r/20250718-k1-i2c-ilcr-v2-1-b4c68f13dcb1@linux.spacemit.com

Changelog in v2:
- Align line breaks.
- Check `lv` in `clk_set_rate` function.
- Force fast mode when SCL frequency is illegal or unavailable.
- Change "linux/bits.h" to <linux/bits.h>
- Kconfig: Add dependency on CCF.
- Link to v1: https://lore.kernel.org/all/20250710-k1-i2c-ilcr-v1-1-188d1f460c7d@linux.spacemit.com/
---
 drivers/i2c/busses/Kconfig  |   2 +-
 drivers/i2c/busses/i2c-k1.c | 159 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 146 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index fd81e49638aaa161ae264a722e9e06adc7914cda..fedf5d31f9035b73a27a7f8a764bf5c26975d0e1 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -798,7 +798,7 @@ config I2C_JZ4780
 config I2C_K1
 	tristate "SpacemiT K1 I2C adapter"
 	depends on ARCH_SPACEMIT || COMPILE_TEST
-	depends on OF
+	depends on OF && COMMON_CLK
 	help
 	  This option enables support for the I2C interface on the SpacemiT K1
 	  platform.
diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
index 6b918770e612e098b8ad17418f420d87c94df166..e38a0ba71734ca602854c85672dcb61423453515 100644
--- a/drivers/i2c/busses/i2c-k1.c
+++ b/drivers/i2c/busses/i2c-k1.c
@@ -4,18 +4,21 @@
  */
 
 #include <linux/bitfield.h>
- #include <linux/clk.h>
- #include <linux/i2c.h>
- #include <linux/iopoll.h>
- #include <linux/module.h>
- #include <linux/of_address.h>
- #include <linux/platform_device.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
 
 /* spacemit i2c registers */
 #define SPACEMIT_ICR		 0x0		/* Control register */
 #define SPACEMIT_ISR		 0x4		/* Status register */
 #define SPACEMIT_IDBR		 0xc		/* Data buffer register */
 #define SPACEMIT_IRCR		 0x18		/* Reset cycle counter */
+#define SPACEMIT_ILCR		 0x10		/* Load Count Register */
 #define SPACEMIT_IBMR		 0x1c		/* Bus monitor register */
 
 /* SPACEMIT_ICR register fields */
@@ -87,6 +90,13 @@
 #define SPACEMIT_BMR_SDA         BIT(0)		/* SDA line level */
 #define SPACEMIT_BMR_SCL         BIT(1)		/* SCL line level */
 
+#define SPACEMIT_LCR_LV_STANDARD_SHIFT		0
+#define SPACEMIT_LCR_LV_FAST_SHIFT		9
+#define SPACEMIT_LCR_LV_STANDARD_MASK		GENMASK(8, 0)
+#define SPACEMIT_LCR_LV_FAST_MASK		GENMASK(17, 9)
+#define SPACEMIT_LCR_LV_STANDARD_MAX_VALUE	FIELD_MAX(SPACEMIT_LCR_LV_STANDARD_MASK)
+#define SPACEMIT_LCR_LV_FAST_MAX_VALUE		FIELD_MAX(SPACEMIT_LCR_LV_FAST_MASK)
+
 /* i2c bus recover timeout: us */
 #define SPACEMIT_I2C_BUS_BUSY_TIMEOUT		100000
 
@@ -104,11 +114,20 @@ enum spacemit_i2c_state {
 	SPACEMIT_STATE_WRITE,
 };
 
+enum spacemit_i2c_mode {
+	SPACEMIT_MODE_STANDARD,
+	SPACEMIT_MODE_FAST
+};
+
 /* i2c-spacemit driver's main struct */
 struct spacemit_i2c_dev {
 	struct device *dev;
 	struct i2c_adapter adapt;
 
+	struct clk_hw scl_clk_hw;
+	struct clk *scl_clk;
+	enum spacemit_i2c_mode mode;
+
 	/* hardware resources */
 	void __iomem *base;
 	int irq;
@@ -129,6 +148,79 @@ struct spacemit_i2c_dev {
 	u32 status;
 };
 
+static void spacemit_i2c_scl_clk_disable_unprepare(void *data)
+{
+	struct spacemit_i2c_dev *i2c = data;
+
+	clk_disable_unprepare(i2c->scl_clk);
+}
+
+static int spacemit_i2c_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
+	u32 lv, lcr, mask, shift, max_lv;
+
+	lv = DIV_ROUND_UP(parent_rate, rate);
+
+	if (i2c->mode == SPACEMIT_MODE_STANDARD) {
+		mask = SPACEMIT_LCR_LV_STANDARD_MASK;
+		shift = SPACEMIT_LCR_LV_STANDARD_SHIFT;
+		max_lv = SPACEMIT_LCR_LV_STANDARD_MAX_VALUE;
+	} else if (i2c->mode == SPACEMIT_MODE_FAST) {
+		mask = SPACEMIT_LCR_LV_FAST_MASK;
+		shift = SPACEMIT_LCR_LV_FAST_SHIFT;
+		max_lv = SPACEMIT_LCR_LV_FAST_MAX_VALUE;
+	}
+
+	if (!lv || lv > max_lv) {
+		dev_err(i2c->dev, "set scl clock failed: lv 0x%x", lv);
+		return -EINVAL;
+	}
+
+	lcr = readl(i2c->base + SPACEMIT_ILCR);
+	lcr &= ~mask;
+	lcr |= lv << shift;
+	writel(lcr, i2c->base + SPACEMIT_ILCR);
+
+	return 0;
+}
+
+static long spacemit_i2c_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+					unsigned long *parent_rate)
+{
+	u32 lv, freq;
+
+	lv = DIV_ROUND_UP(*parent_rate, rate);
+	freq = DIV_ROUND_UP(*parent_rate, lv);
+
+	return freq;
+}
+
+static unsigned long spacemit_i2c_clk_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
+	u32 lcr, lv = 0;
+
+	lcr = readl(i2c->base + SPACEMIT_ILCR);
+
+	if (i2c->mode == SPACEMIT_MODE_STANDARD)
+		lv = FIELD_GET(SPACEMIT_LCR_LV_STANDARD_MASK, lcr);
+	else if (i2c->mode == SPACEMIT_MODE_FAST)
+		lv = FIELD_GET(SPACEMIT_LCR_LV_FAST_MASK, lcr);
+	else
+		return 0;
+
+	return DIV_ROUND_UP(parent_rate, lv);
+}
+
+static const struct clk_ops spacemit_i2c_clk_ops = {
+	.set_rate = spacemit_i2c_clk_set_rate,
+	.round_rate = spacemit_i2c_clk_round_rate,
+	.recalc_rate = spacemit_i2c_clk_recalc_rate,
+};
+
 static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
 {
 	u32 val;
@@ -147,6 +239,26 @@ static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
 	writel(val, i2c->base + SPACEMIT_ICR);
 }
 
+static struct clk *spacemit_i2c_register_scl_clk(struct spacemit_i2c_dev *i2c,
+						 struct clk *parent)
+{
+	struct clk_init_data init = {};
+	char name[32];
+
+	snprintf(name, sizeof(name), "%s_scl_clk", dev_name(i2c->dev));
+
+	init.name = name;
+	init.ops = &spacemit_i2c_clk_ops;
+	init.parent_data = (struct clk_parent_data[]) {
+		{ .fw_name = "func" },
+	};
+	init.num_parents = 1;
+
+	i2c->scl_clk_hw.init = &init;
+
+	return devm_clk_register(i2c->dev, &i2c->scl_clk_hw);
+}
+
 static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
 {
 	writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
@@ -246,7 +358,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
 	 */
 	val |= SPACEMIT_CR_DRFIE;
 
-	if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
+	if (i2c->mode == SPACEMIT_MODE_FAST)
 		val |= SPACEMIT_CR_MODE_FAST;
 
 	/* disable response to general call */
@@ -538,14 +650,15 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
 		dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
 
 	/* For now, this driver doesn't support high-speed. */
-	if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
-		dev_warn(dev, "unsupported clock frequency %u; using %u\n",
-			 i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
+	if (i2c->clock_freq > SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ &&
+	    i2c->clock_freq <= SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
+		i2c->mode = SPACEMIT_MODE_FAST;
+	} else if (i2c->clock_freq && i2c->clock_freq <= SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
+		i2c->mode = SPACEMIT_MODE_STANDARD;
+	} else {
+		dev_warn(i2c->dev, "invalid clock-frequency, fallback to fast mode");
+		i2c->mode = SPACEMIT_MODE_FAST;
 		i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
-	} else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
-		dev_warn(dev, "unsupported clock frequency %u; using %u\n",
-			 i2c->clock_freq,  SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
-		i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
 	}
 
 	i2c->dev = &pdev->dev;
@@ -567,10 +680,28 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
 	if (IS_ERR(clk))
 		return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
 
+	i2c->scl_clk = spacemit_i2c_register_scl_clk(i2c, clk);
+	if (IS_ERR(i2c->scl_clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(i2c->scl_clk),
+				     "failed to register scl clock\n");
+
 	clk = devm_clk_get_enabled(dev, "bus");
 	if (IS_ERR(clk))
 		return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
 
+	ret = clk_set_rate(i2c->scl_clk, i2c->clock_freq);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "failed to set rate for SCL clock");
+
+	ret = clk_prepare_enable(i2c->scl_clk);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "failed to prepare and enable clock");
+
+	ret = devm_add_action_or_reset(dev, spacemit_i2c_scl_clk_disable_unprepare, i2c);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "failed to register cleanup action for clk disable and unprepare");
+
 	spacemit_i2c_reset(i2c);
 
 	i2c_set_adapdata(&i2c->adapt, i2c);

-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 1/4] mfd: simple-mfd-i2c: remove select I2C_K1
From: Troy Mitchell @ 2025-10-27  5:48 UTC (permalink / raw)
  To: Lee Jones, Yixun Lan, Alex Elder, Andi Shyti, Alexandre Belloni,
	Liam Girdwood, Mark Brown
  Cc: linux-kernel, linux-riscv, spacemit, linux-i2c, linux-rtc,
	Troy Mitchell, kernel test robot
In-Reply-To: <20251027-p1-kconfig-fix-v2-0-49688f30bae8@linux.spacemit.com>

select will force a symbol to a specific value without considering
its dependencies. As a result, the i2c-k1 driver will fail to build
when OF or COMMON_CLK are disabled.

The reason for removing I2C_K1 instead of adding a depends on condition
is to keep the possibility for other SoCs to use this PMIC.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202510211523.sSEVqPUQ-lkp@intel.com/
Acked-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
Changelog in v2:
- nothing
Link to v1: https://lore.kernel.org/all/20251022-p1-kconfig-fix-v1-1-c142d51e1b08@linux.spacemit.com/
---
 drivers/mfd/Kconfig | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6cec1858947bf7ab5ee78beb730c95dabcb43a98..ea367c7e97f116d7585411fff5ba6bcd36882524 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1258,7 +1258,6 @@ config MFD_SPACEMIT_P1
 	tristate "SpacemiT P1 PMIC"
 	depends on ARCH_SPACEMIT || COMPILE_TEST
 	depends on I2C
-	select I2C_K1
 	select MFD_SIMPLE_MFD_I2C
 	help
 	  This option supports the I2C-based SpacemiT P1 PMIC, which

-- 
2.51.1


^ permalink raw reply related

* [PATCH v2 0/4] fix the SpacemiT P1 Kconfig and resend the K1 I2C ILCR patch.
From: Troy Mitchell @ 2025-10-27  5:48 UTC (permalink / raw)
  To: Lee Jones, Yixun Lan, Alex Elder, Andi Shyti, Alexandre Belloni,
	Liam Girdwood, Mark Brown
  Cc: linux-kernel, linux-riscv, spacemit, linux-i2c, linux-rtc,
	Troy Mitchell, kernel test robot

Since P1 Kconfig directly selects K1_I2C, after the I2C ILCR patch was
merged, the driver would fail [1] when COMMON_CLK was not selected.

This series fixes the P1 Kconfig and resends the I2C ILCR patch(This
patch has reverted by maintainer [2]). In addition, the Kconfig for
P1's two subdevices, regulator and RTC, has been updated to use
'depends on MFD_SPACEMIT_P1' instead of 'select'.

Link: https://lore.kernel.org/oe-kbuild-all/202510202150.2qXd8e7Y-lkp@intel.com/ [1]
Link: https://lore.kernel.org/all/sdhkjmi5l2m4ua4zqkwkecbihul5bc2dbmitudwfd57y66mdht@6ipjfyz7dtmx/ [2]

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
Troy Mitchell (4):
      mfd: simple-mfd-i2c: remove select I2C_K1
      i2c: spacemit: configure ILCR for accurate SCL frequency
      rtc: spacemit: MFD_SPACEMIT_P1 as dependencies
      regulator: spacemit: MFD_SPACEMIT_P1 as dependencies

 drivers/i2c/busses/Kconfig  |   2 +-
 drivers/i2c/busses/i2c-k1.c | 159 ++++++++++++++++++++++++++++++++++++++++----
 drivers/mfd/Kconfig         |   1 -
 drivers/regulator/Kconfig   |   3 +-
 drivers/rtc/Kconfig         |   2 +-
 5 files changed, 148 insertions(+), 19 deletions(-)
---
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
change-id: 20251021-p1-kconfig-fix-6d2b59d03b8f

Best regards,
-- 
Troy Mitchell <troy.mitchell@linux.spacemit.com>


^ permalink raw reply

* [PATCH AUTOSEL 6.17-5.15] rtc: pcf2127: clear minute/second interrupt
From: Sasha Levin @ 2025-10-26 14:48 UTC (permalink / raw)
  To: patches, stable
  Cc: Josua Mayer, Bruno Thomsen, Alexandre Belloni, Sasha Levin,
	linux-rtc
In-Reply-To: <20251026144958.26750-1-sashal@kernel.org>

From: Josua Mayer <josua@solid-run.com>

[ Upstream commit a6f1a4f05970664004a9370459c6799c1b2f2dcf ]

PCF2127 can generate interrupt every full second or minute configured
from control and status register 1, bits MI (1) and SI (0).

On interrupt control register 2 bit MSF (7) is set and must be cleared
to continue normal operation.

While the driver never enables this interrupt on its own, users or
firmware may do so - e.g. as an easy way to test the interrupt.

Add preprocessor definition for MSF bit and include it in the irq
bitmask to ensure minute and second interrupts are cleared when fired.

This fixes an issue where the rtc enters a test mode and becomes
unresponsive after a second interrupt has fired and is not cleared in
time. In this state register writes to control registers have no
effect and the interrupt line is kept asserted [1]:

[1] userspace commands to put rtc into unresponsive state:
$ i2cget -f -y 2 0x51 0x00
0x04
$ i2cset -f -y 2 0x51 0x00 0x05 # set bit 0 SI
$ i2cget -f -y 2 0x51 0x00
0x84 # bit 8 EXT_TEST set
$ i2cset -f -y 2 0x51 0x00 0x05 # try overwrite control register
$ i2cget -f -y 2 0x51 0x00
0x84 # no change

Signed-off-by: Josua Mayer <josua@solid-run.com>
Reviewed-by: Bruno Thomsen <bruno.thomsen@gmail.com>
Link: https://lore.kernel.org/r/20250825-rtc-irq-v1-1-0133319406a7@solid-run.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

YES
Clearing the PCF2127 minute/second status flag in the IRQ handler
prevents the controller from locking into EXT_TEST mode when firmware or
userspace enable MI/SI for basic interrupt testing. The patch simply
defines the missing MSF bit and adds it to the mask we already use when
acknowledging CTRL2 status flags, so the interrupt line is released and
register writes start working again.

- `drivers/rtc/rtc-pcf2127.c:45` now names `PCF2127_BIT_CTRL2_MSF`, the
  documented status bit that latches when MI/SI fire; before this change
  the driver never referenced it and therefore never cleared it.
- Including the new bit in `PCF2127_CTRL2_IRQ_MASK` (`drivers/rtc/rtc-
  pcf2127.c:97-101`) ensures the IRQ acknowledge path clears MSF
  alongside AF/WDTF/TSF2. With the old mask, once the second interrupt
  hit the device stayed in test mode and ignored control-register
  writes, exactly as reproduced in the commit message.
- The actual clearing happens in the existing handler (`drivers/rtc/rtc-
  pcf2127.c:792-794`), so no new logic is introduced—only the correct
  bit is now masked off. PCF2131 handling remains untouched, so the
  change is tightly scoped to the affected variants.
- This is a real user-visible hang (persistent interrupt line, inability
  to reconfigure the RTC) triggered by a plausible configuration, while
  the fix is minimal and mirrors how the PCF2123 driver already clears
  its MSF flag (`drivers/rtc/rtc-pcf2123.c:70-78`), keeping regression
  risk low.

Given the clear failure mode and the tiny, well-contained fix, this is
an excellent candidate for stable backporting.

 drivers/rtc/rtc-pcf2127.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 2e1ac0c42e932..3ba1de30e89c2 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -42,6 +42,7 @@
 #define PCF2127_BIT_CTRL2_AF			BIT(4)
 #define PCF2127_BIT_CTRL2_TSF2			BIT(5)
 #define PCF2127_BIT_CTRL2_WDTF			BIT(6)
+#define PCF2127_BIT_CTRL2_MSF			BIT(7)
 /* Control register 3 */
 #define PCF2127_REG_CTRL3		0x02
 #define PCF2127_BIT_CTRL3_BLIE			BIT(0)
@@ -96,7 +97,8 @@
 #define PCF2127_CTRL2_IRQ_MASK ( \
 		PCF2127_BIT_CTRL2_AF | \
 		PCF2127_BIT_CTRL2_WDTF | \
-		PCF2127_BIT_CTRL2_TSF2)
+		PCF2127_BIT_CTRL2_TSF2 | \
+		PCF2127_BIT_CTRL2_MSF)
 
 #define PCF2127_MAX_TS_SUPPORTED	4
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.17-6.6] rtc: pcf2127: fix watchdog interrupt mask on pcf2131
From: Sasha Levin @ 2025-10-26 14:48 UTC (permalink / raw)
  To: patches, stable; +Cc: Bruno Thomsen, Alexandre Belloni, Sasha Levin, linux-rtc
In-Reply-To: <20251026144958.26750-1-sashal@kernel.org>

From: Bruno Thomsen <bruno.thomsen@gmail.com>

[ Upstream commit 87064da2db7be537a7da20a25c18ba912c4db9e1 ]

When using interrupt pin (INT A) as watchdog output all other
interrupt sources need to be disabled to avoid additional
resets. Resulting INT_A_MASK1 value is 55 (0x37).

Signed-off-by: Bruno Thomsen <bruno.thomsen@gmail.com>
Link: https://lore.kernel.org/r/20250902182235.6825-1-bruno.thomsen@gmail.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

YES — this change should go to stable.

- `drivers/rtc/rtc-pcf2127.c:611-623` now masks every INT A source
  except the watchdog bit on PCF2131 when `reset-source` is in use, so
  the INT A pin stays dedicated to driving the external reset pulse
  instead of reasserting on alarm/periodic/tamper events.
- Before this fix, `drivers/rtc/rtc-pcf2127.c:1174-1182` left all INT A
  mask bits cleared, and the probe path unconditionally enables several
  interrupt sources (see `pcf2127_enable_ts()` at `drivers/rtc/rtc-
  pcf2127.c:1128-1163`). With INT A wired as the watchdog output, any of
  those interrupts could immediately toggle the line and spuriously
  reset the system—effectively breaking boards that request
  watchdog/reset operation.
- The new masking runs only when CONFIG_WATCHDOG is enabled and the DT
  property requests watchdog output (`drivers/rtc/rtc-
  pcf2127.c:575-617`), so normal RTC users keep their interrupt
  functionality. If the write were to fail, behaviour simply falls back
  to the pre-fix state, so the delta carries minimal regression risk.
- The patch is tiny, self-contained to this driver, and fixes a user-
  visible bug (unwanted resets) without altering interfaces, making it
  an appropriate and low-risk stable backport candidate.

Suggested follow-up for maintainers: consider backporting anywhere
PCF2131 watchdog/reset support exists alongside unmasked INT A sources.

 drivers/rtc/rtc-pcf2127.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index 3ba1de30e89c2..bb4fe81d3d62c 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -608,6 +608,21 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127)
 			set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status);
 	}
 
+	/*
+	 * When using interrupt pin (INT A) as watchdog output, only allow
+	 * watchdog interrupt (PCF2131_BIT_INT_WD_CD) and disable (mask) all
+	 * other interrupts.
+	 */
+	if (pcf2127->cfg->type == PCF2131) {
+		ret = regmap_write(pcf2127->regmap,
+				   PCF2131_REG_INT_A_MASK1,
+				   PCF2131_BIT_INT_BLIE |
+				   PCF2131_BIT_INT_BIE |
+				   PCF2131_BIT_INT_AIE |
+				   PCF2131_BIT_INT_SI |
+				   PCF2131_BIT_INT_MI);
+	}
+
 	return devm_watchdog_register_device(dev, &pcf2127->wdd);
 }
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.17] rtc: zynqmp: Restore alarm functionality after kexec transition
From: Sasha Levin @ 2025-10-26 14:48 UTC (permalink / raw)
  To: patches, stable
  Cc: Harini T, Alexandre Belloni, Sasha Levin, michal.simek, linux-rtc,
	linux-arm-kernel
In-Reply-To: <20251026144958.26750-1-sashal@kernel.org>

From: Harini T <harini.t@amd.com>

[ Upstream commit e22f4d1321e0055065f274e20bf6d1dbf4b500f5 ]

During kexec reboots, RTC alarms that are fired during the kernel
transition experience delayed execution. The new kernel would eventually
honor these alarms, but the interrupt handlers would only execute after
the driver probe is completed rather than at the intended alarm time.

This is because pending alarm interrupt status from the previous kernel
is not properly cleared during driver initialization, causing timing
discrepancies in alarm delivery.

To ensure precise alarm timing across kexec transitions, enhance the
probe function to:
1. Clear any pending alarm interrupt status from previous boot.
2. Detect existing valid alarms and preserve their state.
3. Re-enable alarm interrupts for future alarms.

Signed-off-by: Harini T <harini.t@amd.com>
Link: https://lore.kernel.org/r/20250730142110.2354507-1-harini.t@amd.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

YES
- `drivers/rtc/rtc-zynqmp.c:303-307` clears a latched `RTC_INT_ALRM` bit
  left behind by the kexec’d kernel so the new instance doesn’t mis-
  handle a stale interrupt; this matches the existing acknowledge flow
  in `xlnx_rtc_alarm_irq_enable()` (`drivers/rtc/rtc-zynqmp.c:125-152`),
  but now happens eagerly during probe to avoid delayed/duplicate
  delivery.
- `drivers/rtc/rtc-zynqmp.c:309-312` inspects the hardware alarm
  register and only preserves state when the stored alarm time is still
  in the future, preventing stray enables after a cold boot while
  keeping real alarms armed across the handover.
- Because the prior kernel disables the alarm IRQ in the ISR
  (`drivers/rtc/rtc-zynqmp.c:268-272`), the new code re-arms it when a
  valid alarm is detected (`drivers/rtc/rtc-zynqmp.c:355-357`); without
  this, alarms that were scheduled before the kexec never fire under the
  new kernel, which is a user-visible regression.
- The change is tightly scoped to probe-time initialization, uses
  existing register helpers, and introduces no ABI or architectural
  churn; risk is low compared with the clear functional gain of
  delivering RTC alarms correctly after kexec on ZynqMP hardware.

Next step you may want: 1) run the RTC selftests or a quick kexec/alarm
smoke test on target hardware to validate the restored behavior.

 drivers/rtc/rtc-zynqmp.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c
index f39102b66eac2..3baa2b481d9f2 100644
--- a/drivers/rtc/rtc-zynqmp.c
+++ b/drivers/rtc/rtc-zynqmp.c
@@ -277,6 +277,10 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
 static int xlnx_rtc_probe(struct platform_device *pdev)
 {
 	struct xlnx_rtc_dev *xrtcdev;
+	bool is_alarm_set = false;
+	u32 pending_alrm_irq;
+	u32 current_time;
+	u32 alarm_time;
 	int ret;
 
 	xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
@@ -296,6 +300,17 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
 	if (IS_ERR(xrtcdev->reg_base))
 		return PTR_ERR(xrtcdev->reg_base);
 
+	/* Clear any pending alarm interrupts from previous kernel/boot */
+	pending_alrm_irq = readl(xrtcdev->reg_base + RTC_INT_STS) & RTC_INT_ALRM;
+	if (pending_alrm_irq)
+		writel(pending_alrm_irq, xrtcdev->reg_base + RTC_INT_STS);
+
+	/* Check if a valid alarm is already set from previous kernel/boot */
+	alarm_time = readl(xrtcdev->reg_base + RTC_ALRM);
+	current_time = readl(xrtcdev->reg_base + RTC_CUR_TM);
+	if (alarm_time > current_time && alarm_time != 0)
+		is_alarm_set = true;
+
 	xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm");
 	if (xrtcdev->alarm_irq < 0)
 		return xrtcdev->alarm_irq;
@@ -337,6 +352,10 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
 
 	xlnx_init_rtc(xrtcdev);
 
+	/* Re-enable alarm interrupt if a valid alarm was found */
+	if (is_alarm_set)
+		writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN);
+
 	device_init_wakeup(&pdev->dev, true);
 
 	return devm_rtc_register_device(xrtcdev->rtc);
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH v1 2/2] rtc: Add support for MT6685 Clock IC's RTC over SPMI
From: kernel test robot @ 2025-10-26  5:13 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno, alexandre.belloni
  Cc: oe-kbuild-all, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, linux-rtc, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, kernel
In-Reply-To: <20251024083318.25890-3-angelogioacchino.delregno@collabora.com>

Hi AngeloGioacchino,

kernel test robot noticed the following build errors:

[auto build test ERROR on abelloni/rtc-next]
[also build test ERROR on robh/for-next linus/master v6.18-rc2 next-20251024]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/AngeloGioacchino-Del-Regno/dt-bindings-rtc-Add-MediaTek-MT6685-PM-Clock-IC-Real-Time-Clock/20251024-164423
base:   https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git rtc-next
patch link:    https://lore.kernel.org/r/20251024083318.25890-3-angelogioacchino.delregno%40collabora.com
patch subject: [PATCH v1 2/2] rtc: Add support for MT6685 Clock IC's RTC over SPMI
config: sparc64-randconfig-r062-20251026 (https://download.01.org/0day-ci/archive/20251026/202510261223.NRLximA4-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 9.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251026/202510261223.NRLximA4-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510261223.NRLximA4-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   drivers/rtc/rtc-mt6685.c: In function 'rtc_mt6685_probe':
   drivers/rtc/rtc-mt6685.c:380:13: error: implicit declaration of function 'devm_spmi_subdevice_alloc_and_add' [-Werror=implicit-function-declaration]
     380 |  sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
         |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/rtc/rtc-mt6685.c:380:11: warning: assignment to 'struct spmi_subdevice *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     380 |  sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
         |           ^
   In file included from drivers/rtc/rtc-mt6685.c:20:
>> drivers/rtc/rtc-mt6685.c:397:51: error: dereferencing pointer to incomplete type 'struct spmi_subdevice'
     397 |  rtc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &mt6685_rtc_regmap_config);
         |                                                   ^~
   include/linux/regmap.h:775:6: note: in definition of macro '__regmap_lockdep_wrapper'
     775 |   fn(__VA_ARGS__, &_key,     \
         |      ^~~~~~~~~~~
   drivers/rtc/rtc-mt6685.c:397:16: note: in expansion of macro 'devm_regmap_init_spmi_ext'
     397 |  rtc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &mt6685_rtc_regmap_config);
         |                ^~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +397 drivers/rtc/rtc-mt6685.c

   358	
   359	static int rtc_mt6685_probe(struct platform_device *pdev)
   360	{
   361		struct regmap_config mt6685_rtc_regmap_config = {
   362			.reg_bits = 16,
   363			.val_bits = 8,
   364			.max_register = 0x60,
   365			.fast_io = true,
   366			.use_single_read = true,
   367			.use_single_write = true,
   368		};
   369		struct device *dev = &pdev->dev;
   370		struct spmi_subdevice *sub_sdev;
   371		struct spmi_device *sparent;
   372		struct mt6685_rtc *rtc;
   373		int ret;
   374	
   375		rtc = devm_kzalloc(dev, sizeof(struct mt6685_rtc), GFP_KERNEL);
   376		if (!rtc)
   377			return -ENOMEM;
   378	
   379		sparent = to_spmi_device(dev->parent);
 > 380		sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
   381		if (IS_ERR(sub_sdev))
   382			return PTR_ERR(sub_sdev);
   383	
   384		ret = of_property_read_u32(pdev->dev.of_node, "reg",
   385					   &mt6685_rtc_regmap_config.reg_base);
   386		if (ret)
   387			return ret;
   388	
   389		rtc->irq = platform_get_irq(pdev, 0);
   390		if (rtc->irq < 0)
   391			return rtc->irq;
   392	
   393		rtc->mclk = devm_clk_get(dev, 0);
   394		if (IS_ERR(rtc->mclk))
   395			return PTR_ERR(rtc->mclk);
   396	
 > 397		rtc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &mt6685_rtc_regmap_config);
   398		if (IS_ERR(rtc->regmap))
   399			return PTR_ERR(rtc->regmap);
   400	
   401		rtc->rdev = devm_rtc_allocate_device(dev);
   402		if (IS_ERR(rtc->rdev))
   403			return PTR_ERR(rtc->rdev);
   404	
   405		platform_set_drvdata(pdev, rtc);
   406	
   407		/* Clock is required to auto-synchronize IRQ enable to RTC */
   408		ret = clk_prepare_enable(rtc->mclk);
   409		if (ret)
   410			return ret;
   411	
   412		ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
   413						rtc_mt6685_irq_handler_thread,
   414						IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
   415						"mt6685-rtc", rtc);
   416		clk_disable_unprepare(rtc->mclk);
   417		if (ret)
   418			return dev_err_probe(&pdev->dev, ret, "Cannot request alarm IRQ");
   419	
   420		device_init_wakeup(&pdev->dev, true);
   421	
   422		rtc->rdev->ops = &rtc_mt6685_ops;
   423		rtc->rdev->range_min = RTC_TIMESTAMP_BEGIN_1900;
   424		rtc->rdev->range_max = mktime64(2027, 12, 31, 23, 59, 59);
   425		rtc->rdev->start_secs = mktime64(1968, 1, 1, 0, 0, 0);
   426		rtc->rdev->set_start_time = true;
   427	
   428		return devm_rtc_register_device(rtc->rdev);
   429	}
   430	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH v1 2/2] rtc: Add support for MT6685 Clock IC's RTC over SPMI
From: kernel test robot @ 2025-10-26  1:37 UTC (permalink / raw)
  To: AngeloGioacchino Del Regno, alexandre.belloni
  Cc: oe-kbuild-all, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, linux-rtc, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, kernel
In-Reply-To: <20251024083318.25890-3-angelogioacchino.delregno@collabora.com>

Hi AngeloGioacchino,

kernel test robot noticed the following build errors:

[auto build test ERROR on abelloni/rtc-next]
[also build test ERROR on robh/for-next linus/master v6.18-rc2 next-20251024]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/AngeloGioacchino-Del-Regno/dt-bindings-rtc-Add-MediaTek-MT6685-PM-Clock-IC-Real-Time-Clock/20251024-164423
base:   https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git rtc-next
patch link:    https://lore.kernel.org/r/20251024083318.25890-3-angelogioacchino.delregno%40collabora.com
patch subject: [PATCH v1 2/2] rtc: Add support for MT6685 Clock IC's RTC over SPMI
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20251026/202510260921.IcI6vsTN-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251026/202510260921.IcI6vsTN-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510260921.IcI6vsTN-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/rtc/rtc-mt6685.c: In function 'rtc_mt6685_probe':
>> drivers/rtc/rtc-mt6685.c:380:20: error: implicit declaration of function 'devm_spmi_subdevice_alloc_and_add' [-Wimplicit-function-declaration]
     380 |         sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/rtc/rtc-mt6685.c:380:18: error: assignment to 'struct spmi_subdevice *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     380 |         sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
         |                  ^
   In file included from drivers/rtc/rtc-mt6685.c:20:
>> drivers/rtc/rtc-mt6685.c:397:58: error: invalid use of undefined type 'struct spmi_subdevice'
     397 |         rtc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &mt6685_rtc_regmap_config);
         |                                                          ^~
   include/linux/regmap.h:782:52: note: in definition of macro '__regmap_lockdep_wrapper'
     782 | #define __regmap_lockdep_wrapper(fn, name, ...) fn(__VA_ARGS__, NULL, NULL)
         |                                                    ^~~~~~~~~~~
   drivers/rtc/rtc-mt6685.c:397:23: note: in expansion of macro 'devm_regmap_init_spmi_ext'
     397 |         rtc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &mt6685_rtc_regmap_config);
         |                       ^~~~~~~~~~~~~~~~~~~~~~~~~


vim +/devm_spmi_subdevice_alloc_and_add +380 drivers/rtc/rtc-mt6685.c

   358	
   359	static int rtc_mt6685_probe(struct platform_device *pdev)
   360	{
   361		struct regmap_config mt6685_rtc_regmap_config = {
   362			.reg_bits = 16,
   363			.val_bits = 8,
   364			.max_register = 0x60,
   365			.fast_io = true,
   366			.use_single_read = true,
   367			.use_single_write = true,
   368		};
   369		struct device *dev = &pdev->dev;
   370		struct spmi_subdevice *sub_sdev;
   371		struct spmi_device *sparent;
   372		struct mt6685_rtc *rtc;
   373		int ret;
   374	
   375		rtc = devm_kzalloc(dev, sizeof(struct mt6685_rtc), GFP_KERNEL);
   376		if (!rtc)
   377			return -ENOMEM;
   378	
   379		sparent = to_spmi_device(dev->parent);
 > 380		sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
   381		if (IS_ERR(sub_sdev))
   382			return PTR_ERR(sub_sdev);
   383	
   384		ret = of_property_read_u32(pdev->dev.of_node, "reg",
   385					   &mt6685_rtc_regmap_config.reg_base);
   386		if (ret)
   387			return ret;
   388	
   389		rtc->irq = platform_get_irq(pdev, 0);
   390		if (rtc->irq < 0)
   391			return rtc->irq;
   392	
   393		rtc->mclk = devm_clk_get(dev, 0);
   394		if (IS_ERR(rtc->mclk))
   395			return PTR_ERR(rtc->mclk);
   396	
 > 397		rtc->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &mt6685_rtc_regmap_config);
   398		if (IS_ERR(rtc->regmap))
   399			return PTR_ERR(rtc->regmap);
   400	
   401		rtc->rdev = devm_rtc_allocate_device(dev);
   402		if (IS_ERR(rtc->rdev))
   403			return PTR_ERR(rtc->rdev);
   404	
   405		platform_set_drvdata(pdev, rtc);
   406	
   407		/* Clock is required to auto-synchronize IRQ enable to RTC */
   408		ret = clk_prepare_enable(rtc->mclk);
   409		if (ret)
   410			return ret;
   411	
   412		ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
   413						rtc_mt6685_irq_handler_thread,
   414						IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
   415						"mt6685-rtc", rtc);
   416		clk_disable_unprepare(rtc->mclk);
   417		if (ret)
   418			return dev_err_probe(&pdev->dev, ret, "Cannot request alarm IRQ");
   419	
   420		device_init_wakeup(&pdev->dev, true);
   421	
   422		rtc->rdev->ops = &rtc_mt6685_ops;
   423		rtc->rdev->range_min = RTC_TIMESTAMP_BEGIN_1900;
   424		rtc->rdev->range_max = mktime64(2027, 12, 31, 23, 59, 59);
   425		rtc->rdev->start_secs = mktime64(1968, 1, 1, 0, 0, 0);
   426		rtc->rdev->set_start_time = true;
   427	
   428		return devm_rtc_register_device(rtc->rdev);
   429	}
   430	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox