[PATCH 5/8] regulator: bd71828: Support ROHM BD73800
From: Matti Vaittinen
Date: Wed Jul 01 2026 - 08:55:47 EST
From: Matti Vaittinen <mazziesaccount@xxxxxxxxx>
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 <mazziesaccount@xxxxxxxxx>
---
drivers/regulator/Kconfig | 4 +-
drivers/regulator/bd71828-regulator.c | 555 +++++++++++++++++++++++++-
2 files changed, 556 insertions(+), 3 deletions(-)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a54a549196fe..0e5a3994f49d 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 bd61caa8284a..89738953f8b5 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/mod_devicetable.h>
#include <linux/of.h>
@@ -32,6 +32,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.
@@ -173,6 +180,54 @@ 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),
+};
+/*
+ * iBUCK5 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 };
/*
@@ -226,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,
@@ -1566,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_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,
@@ -1620,6 +2111,50 @@ static int bd72720_dt_parse(struct device *dev,
return bd72720_buck10_ldon_head_mode(dev, nproot, regmap, buck10_desc);
}
+static int bd73800_check_ldo_otp_options(struct device *dev,
+ struct bd71828_regulator_data *d,
+ unsigned int num_reg_data)
+{
+ bool ldo1_use_high_range = false, ldo3_use_high_range = false;
+ struct device_node *nproot = dev->parent->of_node;
+ struct device_node *np;
+
+ /*
+ * 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);
+
+ nproot = of_get_child_by_name(nproot, "regulators");
+ if (!nproot) {
+ dev_err(dev, "failed to find regulators node\n");
+ return -ENODEV;
+ }
+ for_each_child_of_node(nproot, np) {
+ if (of_node_name_eq(np, LDO1_NODE_NAME))
+ ldo1_use_high_range = of_property_read_bool(np,
+ "rohm,ldo-range-high");
+ if (of_node_name_eq(np, LDO3_NODE_NAME))
+ ldo3_use_high_range = of_property_read_bool(np,
+ "rohm,ldo-range-high");
+ }
+ of_node_put(nproot);
+
+ if (ldo1_use_high_range) {
+ d[BD73800_LDO1].desc.linear_ranges = bd73800_ldo13_high_volts;
+ d[BD73800_LDO1].desc.n_linear_ranges =
+ ARRAY_SIZE(bd73800_ldo13_high_volts);
+ }
+ if (ldo3_use_high_range) {
+ 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;
@@ -1657,6 +2192,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");
@@ -1693,6 +2245,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.54.0
Attachment:
signature.asc
Description: PGP signature