[PATCH v2 07/10] regulator: bd71828: Support ROHM BD73800

Matti Vaittinen <[email protected]> Tue, 4 Aug 2026 13:22:39 +0300
Newsgroups org.kernel.vger.linux-devicetree,dev.linux.lists.mfd,org.kernel.vger.linux-clk,org.kernel.vger.linux-gpio,org.kernel.vger.linux-kernel,org.kernel.vger.linux-rtc
Message-ID <f81e7214f9c02fb1a92d12944bc6b8790d5ea6a8.1785838585.git.mazziesaccount@gmail.com>
From: Matti Vaittinen <[email protected]>

The ROHM BD73800 is a power management IC which integrates 8 BUCKs and 4
LDOs. The PMIC has internal state-machine and it can support transitions
to RUN, SUSPEND and IDLE states. The LDOs 1 and 3 have two different
voltage range configurations that can be set at the manufacturing phase
by OTP. By default driver assumes low voltage ranges to be used because
the data-sheet indicates the higher voltage ranges to be an 'OTP option'.
The high voltage range can be indicated via device-tree property.

Signed-off-by: Matti Vaittinen <[email protected]>

---
Revision history:
v1 => v2:
 - Simplified DT parsing as was suggested by Mark
 - Fix buck5 vsel_mask
---
 drivers/regulator/Kconfig             |   4 +-
 drivers/regulator/bd71828-regulator.c | 558 +++++++++++++++++++++++++-
 2 files changed, 559 insertions(+), 3 deletions(-)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 89789ac7a786..13928af8cad4 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -241,12 +241,12 @@ config REGULATOR_BD71815
 	  will be called bd71815-regulator.
 
 config REGULATOR_BD71828
-	tristate "ROHM BD71828, BD72720 and BD73900 Power Regulators"
+	tristate "ROHM BD71828, BD72720 and BD73[8/9]00 Power Regulators"
 	depends on MFD_ROHM_BD71828
 	select REGULATOR_ROHM
 	help
 	  This driver supports voltage regulators on ROHM BD71828,
-	  BD71879, BD72720 and BD73900 PMICs. This will enable
+	  BD71879, BD72720 and BD73[8/9]00 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
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index 2ced81df0c02..dea551cf658a 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 // Copyright (C) 2019 ROHM Semiconductors
 // bd71828-regulator.c ROHM BD71828GW-DS1 regulator driver
-//
 
 #include <linux/cleanup.h>
 #include <linux/delay.h>
@@ -10,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/mfd/rohm-bd71828.h>
 #include <linux/mfd/rohm-bd72720.h>
+#include <linux/mfd/rohm-bd73800.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -31,6 +31,13 @@ struct bd71828_regulator_data {
 	int reg_init_amnt;
 };
 
+/*
+ * LDO1 and LDO3 node names are used also in the driver to find OTP setting for
+ * the used voltage range.
+ */
+#define LDO1_NODE_NAME "ldo1"
+#define LDO3_NODE_NAME "ldo3"
+
 static const struct reg_init bd71828_buck1_inits[] = {
 	/*
 	 * DVS Buck voltages can be changed by register values or via GPIO.
@@ -172,6 +179,55 @@ static const struct linear_range bd72720_ldo6_volts[] = {
 	REGULATOR_LINEAR_RANGE(1800000, 0x79, 0x7f, 0),
 };
 
+static const struct linear_range bd73800_buck12348_volts[] = {
+	REGULATOR_LINEAR_RANGE(500000, 0x00, 0x50, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0x51, 0xff, 0),
+};
+
+static const unsigned int bd73800_buck5_volt_range_sel[] = {
+	0x0, 0x0, 0x1, 0x1,
+};
+
+static const struct linear_range bd73800_buck5_volts[] = {
+	/* range selector 0 */
+	REGULATOR_LINEAR_RANGE(500000, 0x00, 0x50, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0x51, 0x7f, 0),
+	/* range selector 1 */
+	REGULATOR_LINEAR_RANGE(300000, 0x00, 0x46, 10000),
+	REGULATOR_LINEAR_RANGE(1000000, 0x47, 0x7f, 0),
+};
+
+/*
+ * BUCK5 has two different pickable ranges, each having voltages matching
+ * selectors 0x0 to 0x7f. This gives 0x7f + 1 different voltages for each of
+ * the ranges.
+ */
+#define BD73800_NUM_BUCK5_VOLTS ((0x7f + 1) * 2)
+
+static const struct linear_range bd73800_buck67_volts[] = {
+	REGULATOR_LINEAR_RANGE(1500000, 0x00, 0xc8, 10000),
+	REGULATOR_LINEAR_RANGE(3500000, 0xc9, 0xff, 0),
+};
+
+/*
+ * On the BD73800 the LDO1 and LDO3 support two different voltage areas.
+ * Whether to use 'high' or 'low' ranges is configured by OTP. There seems
+ * to be no register to read the configured area so it must be given via
+ * device-tree properties.
+ */
+static const struct linear_range bd73800_ldo13_low_volts[] = {
+	REGULATOR_LINEAR_RANGE(600000, 0x00, 0x78, 10000),
+	REGULATOR_LINEAR_RANGE(1800000, 0x79, 0xff, 0),
+};
+
+static const struct linear_range bd73800_ldo13_high_volts[] = {
+	REGULATOR_LINEAR_RANGE(750000, 0x00, 0xff, 10000),
+};
+
+static const struct linear_range bd73800_ldo24_volts[] = {
+	REGULATOR_LINEAR_RANGE(750000, 0x00, 0xff, 10000),
+};
+
 static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
 
 /*
@@ -225,6 +281,36 @@ static int bd71828_ldo6_parse_dt(struct device_node *np,
 	return 0;
 }
 
+/* Operations for all other BUCKs but BUCK 5 */
+static const struct regulator_ops bd73800_buck_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_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops bd73800_buck5_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_pickable_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+	.set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops bd73800_ldo_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,
+};
+
 static const struct regulator_ops bd71828_buck_ops = {
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
@@ -1565,6 +1651,412 @@ static const struct bd71828_regulator_data bd72720_rdata[] = {
 	},
 };
 
+static const struct bd71828_regulator_data bd73800_rdata[] = {
+	{
+		.desc = {
+			.name = "buck1",
+			.of_match = of_match_ptr("buck1"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK1,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck12348_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK1_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK1_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK1_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK1_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK1_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK1_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck2",
+			.of_match = of_match_ptr("buck2"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK2,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck12348_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK2_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK2_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK2_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK2_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK2_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK2_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck3",
+			.of_match = of_match_ptr("buck3"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK3,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck12348_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK3_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK3_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK3_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK3_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK3_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK3_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+
+	}, {
+		.desc = {
+			.name = "buck4",
+			.of_match = of_match_ptr("buck4"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK4,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck12348_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK4_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK4_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK4_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK4_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK4_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK4_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck5",
+			.of_match = of_match_ptr("buck5"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK5,
+			.ops = &bd73800_buck5_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck5_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck5_volts),
+			.linear_range_selectors_bitfield =
+						bd73800_buck5_volt_range_sel,
+			.n_voltages = BD73800_NUM_BUCK5_VOLTS,
+			.enable_reg = BD73800_REG_BUCK5_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK5_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_BUCK5_VOLT,
+			.vsel_range_reg = BD73800_REG_BUCK5_MODE,
+			.vsel_range_mask = BD73800_BUCK5_RANGE_MASK,
+			.range_applied_by_vsel = true,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK5_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_DELAY,
+			.owner = THIS_MODULE,
+		},
+		.dvs = {
+			/*
+			 * We don't support setting the IDLE / SUSPEND voltages
+			 * for the BUCK 5 for now. Reason is that the pickable
+			 * range selector bit is common for all states (RUN,
+			 * SUSPEND and IDLE), and toggling it for one impacts
+			 * also others.
+			 * Furthermore, writing the BD73800 range selector does
+			 * not impact the RUN voltage until a new voltage value
+			 * is also written to the vsel register. Hence the
+			 * voltage change can be done without any 'intermediate
+			 * voltages', even when the range is changed when the
+			 * BUCK is enabled.
+			 * It, however, is not documented how the IDLE / SUSPEND
+			 * states work in this regard. I expect the full
+			 * combination of the range selector and vsel is taken
+			 * into account at the state change, no matter when they
+			 * have been written to.
+			 */
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND,
+			.run_reg = BD73800_REG_BUCK5_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+
+	}, {
+		.desc = {
+			.name = "buck6",
+			.of_match = of_match_ptr("buck6"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK6,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck67_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck67_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK6_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK6_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK6_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK6_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK6_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK6_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck7",
+			.of_match = of_match_ptr("buck7"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK7,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck67_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck67_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK7_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK7_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK7_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK7_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK7_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK7_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "buck8",
+			.of_match = of_match_ptr("buck8"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_BUCK8,
+			.ops = &bd73800_buck_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_buck12348_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_BUCK8_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_BUCK8_VOLT_RUN,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.ramp_delay_table = bd71828_ramp_delay,
+			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+			.ramp_reg = BD73800_REG_BUCK8_MODE,
+			.ramp_mask = BD73800_MASK_RAMP_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,
+			.run_reg = BD73800_REG_BUCK8_VOLT_RUN,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_reg = BD73800_REG_BUCK8_VOLT_IDLE,
+			.idle_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_reg = BD73800_REG_BUCK8_VOLT_SUSP,
+			.suspend_mask = BD73800_MASK_VOLT,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo1",
+			.of_match = of_match_ptr(LDO1_NODE_NAME),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_LDO1,
+			.ops = &bd73800_ldo_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_ldo13_low_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_ldo13_low_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_LDO1_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_LDO1_VOLT,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.owner = THIS_MODULE,
+			.of_parse_cb = buck_set_hw_dvs_levels,
+		},
+		.dvs = {
+			/*
+			 * LDOs support only single voltage for all states.
+			 * Voltage can be individually enabled for each state
+			 * though. Allow setting enable/disable config by
+			 * setting the <state>_on_mask for all supported states.
+			 */
+			.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+				     ROHM_DVS_LEVEL_SUSPEND,
+			.run_reg = BD73800_REG_LDO1_VOLT,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo2",
+			.of_match = of_match_ptr("ldo2"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_LDO2,
+			.ops = &bd73800_ldo_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_ldo24_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_ldo24_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_LDO2_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_LDO2_VOLT,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.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,
+			.run_reg = BD73800_REG_LDO2_VOLT,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo3",
+			.of_match = of_match_ptr(LDO3_NODE_NAME),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_LDO3,
+			.ops = &bd73800_ldo_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_ldo13_low_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_ldo13_low_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_LDO3_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_LDO3_VOLT,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.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,
+			.run_reg = BD73800_REG_LDO3_VOLT,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	}, {
+		.desc = {
+			.name = "ldo4",
+			.of_match = of_match_ptr("ldo4"),
+			.regulators_node = of_match_ptr("regulators"),
+			.id = BD73800_LDO4,
+			.ops = &bd73800_ldo_ops,
+			.type = REGULATOR_VOLTAGE,
+			.linear_ranges = bd73800_ldo24_volts,
+			.n_linear_ranges = ARRAY_SIZE(bd73800_ldo24_volts),
+			.n_voltages = BD73800_NUM_VOLTS,
+			.enable_reg = BD73800_REG_LDO4_ON,
+			.enable_mask = BD73800_MASK_RUN_EN,
+			.vsel_reg = BD73800_REG_LDO4_VOLT,
+			.vsel_mask = BD73800_MASK_VOLT,
+			.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,
+			.run_reg = BD73800_REG_LDO4_VOLT,
+			.run_mask = BD73800_MASK_VOLT,
+			.idle_on_mask = BD73800_MASK_IDLE_EN,
+			.suspend_on_mask = BD73800_MASK_SUSP_EN,
+		},
+	},
+};
+
 static int bd72720_buck10_ldon_head_mode(struct device *dev,
 					 struct device_node *npreg,
 					 struct regmap *regmap,
@@ -1619,6 +2111,52 @@ static int bd72720_dt_parse(struct device *dev,
 	return bd72720_buck10_ldon_head_mode(dev, nproot, regmap, buck10_desc);
 }
 
+static bool bd73800_use_ldo_high_range(struct device_node *nproot,
+				       const char *ldo_node)
+{
+	struct device_node *np __free(device_node) =
+		of_get_child_by_name(nproot, ldo_node);
+
+	if (!np)
+		return false;
+
+	return of_property_read_bool(np, "rohm,ldo-range-high");
+}
+
+static int bd73800_check_ldo_otp_options(struct device *dev,
+					 struct bd71828_regulator_data *d,
+					 unsigned int num_reg_data)
+{
+	struct device_node *nproot __free(device_node) =
+		of_get_child_by_name(dev->parent->of_node, "regulators");
+
+	/*
+	 * The code assumes regulator IDs to start from 0 and to match the
+	 * indexing of regulator data arrays. WARN if someone changes this.
+	 */
+	WARN_ON(d[BD73800_LDO1].desc.id != BD73800_LDO1);
+	WARN_ON(d[BD73800_LDO3].desc.id != BD73800_LDO3);
+
+	if (!nproot) {
+		dev_err(dev, "failed to find regulators node\n");
+		return -ENODEV;
+	}
+
+	if (bd73800_use_ldo_high_range(nproot, LDO1_NODE_NAME)) {
+		d[BD73800_LDO1].desc.linear_ranges = bd73800_ldo13_high_volts;
+		d[BD73800_LDO1].desc.n_linear_ranges =
+					ARRAY_SIZE(bd73800_ldo13_high_volts);
+	}
+
+	if (bd73800_use_ldo_high_range(nproot, LDO3_NODE_NAME)) {
+		d[BD73800_LDO3].desc.linear_ranges = bd73800_ldo13_high_volts;
+		d[BD73800_LDO3].desc.n_linear_ranges =
+					ARRAY_SIZE(bd73800_ldo13_high_volts);
+	}
+
+	return 0;
+}
+
 static int bd71828_probe(struct platform_device *pdev)
 {
 	int i, j, ret, num_regulators;
@@ -1656,6 +2194,23 @@ static int bd71828_probe(struct platform_device *pdev)
 		num_regulators = ARRAY_SIZE(bd71828_rdata);
 
 		break;
+
+	case ROHM_CHIP_TYPE_BD73800:
+	{
+		rdata = devm_kmemdup(&pdev->dev, bd73800_rdata,
+				     sizeof(bd73800_rdata), GFP_KERNEL);
+		if (!rdata)
+			return -ENOMEM;
+
+		num_regulators = ARRAY_SIZE(bd73800_rdata);
+
+		ret = bd73800_check_ldo_otp_options(&pdev->dev, rdata,
+						    num_regulators);
+		if (ret)
+			return ret;
+
+		break;
+	}
 	default:
 		return dev_err_probe(&pdev->dev, -EINVAL,
 				     "Unsupported device\n");
@@ -1692,6 +2247,7 @@ static int bd71828_probe(struct platform_device *pdev)
 static const struct platform_device_id bd71828_pmic_id[] = {
 	{ .name = "bd71828-pmic", .driver_data = ROHM_CHIP_TYPE_BD71828 },
 	{ .name = "bd72720-pmic", .driver_data = ROHM_CHIP_TYPE_BD72720 },
+	{ .name = "bd73800-pmic", .driver_data = ROHM_CHIP_TYPE_BD73800 },
 	{ }
 };
 MODULE_DEVICE_TABLE(platform, bd71828_pmic_id);
-- 
2.55.0
signature.asc (application/pgp-signature, 488 B)
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCgAdFiEEIx+f8wZb28fLKEhTeFA3/03aocUFAmpxvW8ACgkQeFA3/03a
ocX56Af8CLqbIVFMTub6EZA4fxIhqgnmbevKIqEwUwjtsuIKiiFKmzgSxfA9XySk
lfNcQE1CAON02Fn9YOMeOOTuxfO5YvPprWC609/YhYgKgipYmN38P6G8FnNfVcc/
zJbDx3lLIxyPYOU+eBKVEavVQNsEwAIh7Bk6Hab4UKlJfrYmFcBuMsv16GAYRIwz
y9/xlPJqIyxCGQ6mn6Jxjtf0KWWA7dxlVGy64gXSHWcDC5BSrVgGKEv+T93Z7Xki
+mXzfH8GXNIXAOXhI+JhioIRRl/DFxTAT9pBjEyhgvjaR+cmZx8LwbM8rnHQvZNC
e6BXQCAUbbT2vxWzL2/qnRyrHkvtNQ==
=Z6WA
-----END PGP SIGNATURE-----