regulator: bd71828: Support ROHM BD73800

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@gmail.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://patch.msgid.link/94a1cef828fb5f6ea1703167c819f321ee3bde77.1789538455.git.mazziesaccount@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
Matti Vaittinen 2026-09-16 09:10:00 +03:00 committed by Lee Jones
parent fcf132b701
commit e2be915076
2 changed files with 559 additions and 3 deletions

View File

@ -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

View File

@ -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);