Add a DB8500 regulator driver for the VAPE and VSMPS2 compatibility nodes. Back the regulator enable state with the corresponding power domains.
This is done for off-chip consumers: the corresponding voltage rails are routed out so they are used for powering different peripherals using these voltages as supplies. Assisted-by: Codex:gpt-5-5 Signed-off-by: Linus Walleij <[email protected]> --- arch/arm/boot/dts/st/ste-dbx5x0.dtsi | 2 + drivers/regulator/Kconfig | 11 ++ drivers/regulator/Makefile | 1 + drivers/regulator/db8500-regulator.c | 221 +++++++++++++++++++++++++++++++++++ 4 files changed, 235 insertions(+) diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi index a6fef302c994..fd6a075e4c93 100644 --- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi @@ -673,6 +673,7 @@ db8500-prcmu-regulators { // DB8500_REGULATOR_VAPE db8500_vape_reg: db8500_vape { regulator-always-on; + power-domains = <&pm_domains DOMAIN_VAPE>; }; // DB8500_REGULATOR_VARM @@ -693,6 +694,7 @@ db8500_vsmps1_reg: db8500_vsmps1 { // DB8500_REGULATOR_VSMPS2 db8500_vsmps2_reg: db8500_vsmps2 { + power-domains = <&pm_domains DOMAIN_VSMPS2>; }; // DB8500_REGULATOR_VSMPS3 diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index acc698c17bd2..8db63d8d3fa4 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -397,6 +397,17 @@ config REGULATOR_DA9210 converter 12A DC-DC Buck controlled through an I2C interface. +config REGULATOR_DB8500 + bool "ST-Ericsson DB8500 power domain regulators" + depends on MFD_DB8500_PRCMU && UX500_PM_DOMAIN && OF + default ARCH_U8500 + help + This driver supports the DB8500 VAPE and VSMPS2 regulators. + These supplies are represented by generic power domains in hardware, + but the same voltage rails are routed out of the chip and used to + supply external peripherals. + Enable this driver to bridge those regulator consumers to genpd. + config REGULATOR_DA9211 tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 96a02063b843..f4109549525a 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_REGULATOR_DA9063) += da9063-regulator.o obj-$(CONFIG_REGULATOR_DA9121) += da9121-regulator.o obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o obj-$(CONFIG_REGULATOR_DA9211) += da9211-regulator.o +obj-$(CONFIG_REGULATOR_DB8500) += db8500-regulator.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o diff --git a/drivers/regulator/db8500-regulator.c b/drivers/regulator/db8500-regulator.c new file mode 100644 index 000000000000..c5a9a1baaf8e --- /dev/null +++ b/drivers/regulator/db8500-regulator.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Linus Walleij <[email protected]> + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/slab.h> + +struct db8500_regulator_info { + struct regulator_desc desc; + struct regulator_init_data init_data; + struct device pd_dev; + bool enabled; +}; + +struct db8500_regulator_match { + const char *name; + const char *supply_name; + const char *constraint_name; + int fixed_uV; + bool always_on; +}; + +static const struct db8500_regulator_match db8500_regulator_matches[] = { + { + .name = "db8500_vape", + .supply_name = "db8500-vape", + .constraint_name = "db8500-vape", + .always_on = true, + }, { + .name = "db8500_vsmps2", + .supply_name = "db8500-vsmps2", + .constraint_name = "db8500-vsmps2", + .fixed_uV = 1800000, + }, +}; + +static int db8500_regulator_enable(struct regulator_dev *rdev) +{ + struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + ret = pm_runtime_resume_and_get(&info->pd_dev); + if (ret) + return ret; + + info->enabled = true; + return 0; +} + +static int db8500_regulator_disable(struct regulator_dev *rdev) +{ + struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + ret = pm_runtime_put_sync_suspend(&info->pd_dev); + if (ret) + return ret; + + info->enabled = false; + return 0; +} + +static int db8500_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + + return info->enabled; +} + +static int db8500_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + + if (!info->desc.fixed_uV) + return -EINVAL; + + return info->desc.fixed_uV; +} + +static const struct regulator_ops db8500_regulator_ops = { + .enable = db8500_regulator_enable, + .disable = db8500_regulator_disable, + .is_enabled = db8500_regulator_is_enabled, + .get_voltage = db8500_regulator_get_voltage, +}; + +static void db8500_regulator_release(struct device *dev) +{ +} + +static void db8500_regulator_cleanup(void *data) +{ + struct db8500_regulator_info *info = data; + + pm_runtime_disable(&info->pd_dev); + dev_pm_domain_detach(&info->pd_dev, true); + put_device(&info->pd_dev); +} + +static const struct db8500_regulator_match * +db8500_regulator_match(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(db8500_regulator_matches); i++) { + if (of_node_name_eq(np, db8500_regulator_matches[i].name)) + return &db8500_regulator_matches[i]; + } + + return NULL; +} + +static int db8500_regulator_register(struct platform_device *pdev, + struct device_node *np) +{ + const struct db8500_regulator_match *match; + struct regulator_config config = { }; + struct db8500_regulator_info *info; + struct of_phandle_args pd_args; + struct regulator_dev *rdev; + const char *cells = "#power-domain-cells"; + int ret; + + match = db8500_regulator_match(np); + if (!match) + return 0; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + device_initialize(&info->pd_dev); + info->pd_dev.parent = &pdev->dev; + info->pd_dev.of_node = np; + info->pd_dev.release = db8500_regulator_release; + ret = dev_set_name(&info->pd_dev, "%s-pd", match->name); + if (ret) + goto put_device; + + ret = of_parse_phandle_with_args(np, "power-domains", cells, 0, &pd_args); + if (ret) + goto put_device; + + ret = of_genpd_add_device(&pd_args, &info->pd_dev); + of_node_put(pd_args.np); + if (ret) + goto put_device; + + pm_runtime_enable(&info->pd_dev); + ret = devm_add_action_or_reset(&pdev->dev, db8500_regulator_cleanup, info); + if (ret) + return ret; + + info->init_data.constraints.name = match->constraint_name; + info->init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS; + info->init_data.constraints.always_on = match->always_on; + + info->desc.name = match->supply_name; + info->desc.of_match = match->name; + info->desc.ops = &db8500_regulator_ops; + info->desc.type = REGULATOR_VOLTAGE; + info->desc.owner = THIS_MODULE; + info->desc.fixed_uV = match->fixed_uV; + config.dev = &pdev->dev; + config.init_data = &info->init_data; + config.driver_data = info; + config.of_node = np; + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + return 0; + +put_device: + put_device(&info->pd_dev); + return ret; +} + +static int db8500_regulator_probe(struct platform_device *pdev) +{ + struct device_node *np; + int ret; + + for_each_available_child_of_node(pdev->dev.of_node, np) { + ret = db8500_regulator_register(pdev, np); + if (ret) { + of_node_put(np); + return ret; + } + } + + return 0; +} + +static const struct of_device_id db8500_regulator_match_table[] = { + { .compatible = "stericsson,db8500-prcmu-regulator" }, + { } +}; +MODULE_DEVICE_TABLE(of, db8500_regulator_match_table); + +static struct platform_driver db8500_regulator_driver = { + .driver = { + .name = "db8500-prcmu-regulators", + .of_match_table = db8500_regulator_match_table, + }, + .probe = db8500_regulator_probe, +}; +module_platform_driver(db8500_regulator_driver); + +MODULE_AUTHOR("Linus Walleij <[email protected]>"); +MODULE_DESCRIPTION("DB8500 power-domain regulator driver"); +MODULE_LICENSE("GPL"); -- 2.54.0
