Add support for the regulators found in the SpacemiT P1 PMIC. This
PMIC provides six buck converters and 12 LDO regulators.
The PMIC is implemented as a multi-function device. These regulators
are probed based on this driver being named in a MFD cell in the P1
PMIC driver.
Signed-off-by: Alex Elder <elder@riscstar.com>
---
drivers/regulator/Kconfig | 9 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/spacemit-p1.c | 154 ++++++++++++++++++++++++++++++++
3 files changed, 164 insertions(+)
create mode 100644 drivers/regulator/spacemit-p1.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6d8988387da45..7bb7b8fad24f2 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1384,6 +1384,15 @@ config REGULATOR_SLG51000
The SLG51000 is seven compact and customizable low dropout
regulators.
+config REGULATOR_SPACEMIT_P1
+ tristate "SpacemiT P1 regulators"
+ depends on ARCH_SPACEMIT || COMPILE_TEST
+ default ARCH_SPACEMIT
+ help
+ Enable support for regulators implemented by the SpacemiT P1
+ power controller. The P1 implements 6 high-efficiency buck
+ converters and 12 programmable LDO regulators.
+
config REGULATOR_STM32_BOOSTER
tristate "STMicroelectronics STM32 BOOSTER"
depends on ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index c0bc7a0f4e670..c58aecadd466e 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -161,6 +161,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o
+obj-$(CONFIG_REGULATOR_SPACEMIT_P1) += spacemit-p1.o
obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
diff --git a/drivers/regulator/spacemit-p1.c b/drivers/regulator/spacemit-p1.c
new file mode 100644
index 0000000000000..35c7b4a36e3ee
--- /dev/null
+++ b/drivers/regulator/spacemit-p1.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for regulators found in the SpacemiT P1 PMIC
+ *
+ * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
+ * Derived from code from SpacemiT.
+ * Copyright (c) 2023, SPACEMIT Co., Ltd
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/linear_range.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+
+enum p1_regulator_id {
+ P1_BUCK1,
+ P1_BUCK2,
+ P1_BUCK3,
+ P1_BUCK4,
+ P1_BUCK5,
+ P1_BUCK6,
+
+ P1_ALDO1,
+ P1_ALDO2,
+ P1_ALDO3,
+ P1_ALDO4,
+
+ P1_DLDO1,
+ P1_DLDO2,
+ P1_DLDO3,
+ P1_DLDO4,
+ P1_DLDO5,
+ P1_DLDO6,
+ P1_DLDO7,
+};
+
+static const struct regulator_ops p1_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+/* Selector value 255 can be used to disable the buck converter on sleep */
+static const struct linear_range p1_buck_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 170, 5000),
+ REGULATOR_LINEAR_RANGE(1375000, 171, 254, 25000),
+};
+
+/* Selector value 0 can be used for suspend */
+static const struct linear_range p1_ldo_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 11, 127, 25000),
+};
+
+/* These define the voltage selector field for buck and LDO regulators */
+#define BUCK_MASK GENMASK(7, 0)
+#define LDO_MASK GENMASK(6, 0)
+
+#define P1_ID(_TYPE, _n) P1_ ## _TYPE ## _n
+#define P1_ENABLE_REG(_off, _n) ((_off) + 3 * ((_n) - 1))
+
+#define P1_REG_DESC(_TYPE, _type, _n, _s, _off, _mask, _nv, _ranges) \
+ { \
+ .name = #_type #_n, \
+ .supply_name = _s, \
+ .of_match = of_match_ptr(#_type #_n), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .id = P1_ID(_TYPE, _n), \
+ .n_voltages = _nv, \
+ .ops = &p1_regulator_ops, \
+ .owner = THIS_MODULE, \
+ .linear_ranges = _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(_ranges), \
+ .vsel_reg = P1_ENABLE_REG(_off, _n) + 1, \
+ .vsel_mask = _mask, \
+ .enable_reg = P1_ENABLE_REG(_off, _n), \
+ .enable_mask = BIT(0), \
+ }
+
+#define P1_BUCK_DESC(_n) \
+ P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges)
+
+#define P1_ALDO_DESC(_n) \
+ P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges)
+
+#define P1_DLDO_DESC(_n) \
+ P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges)
+
+static const struct regulator_desc p1_regulator_desc[] = {
+ P1_BUCK_DESC(1),
+ P1_BUCK_DESC(2),
+ P1_BUCK_DESC(3),
+ P1_BUCK_DESC(4),
+ P1_BUCK_DESC(5),
+ P1_BUCK_DESC(6),
+
+ P1_ALDO_DESC(1),
+ P1_ALDO_DESC(2),
+ P1_ALDO_DESC(3),
+ P1_ALDO_DESC(4),
+
+ P1_DLDO_DESC(1),
+ P1_DLDO_DESC(2),
+ P1_DLDO_DESC(3),
+ P1_DLDO_DESC(4),
+ P1_DLDO_DESC(5),
+ P1_DLDO_DESC(6),
+ P1_DLDO_DESC(7),
+};
+
+static int p1_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_config config = { };
+ struct device *dev = &pdev->dev;
+ u32 i;
+
+ /*
+ * The parent device (PMIC) owns the regmap. Since we don't
+ * provide one in the config structure, that one will be used.
+ */
+ config.dev = dev->parent;
+
+ for (i = 0; i < ARRAY_SIZE(p1_regulator_desc); i++) {
+ const struct regulator_desc *desc = &p1_regulator_desc[i];
+ struct regulator_dev *rdev;
+
+ rdev = devm_regulator_register(dev, desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "error registering regulator %s\n",
+ desc->name);
+ }
+
+ return 0;
+}
+
+static struct platform_driver p1_regulator_driver = {
+ .probe = p1_regulator_probe,
+ .driver = {
+ .name = "spacemit-p1-regulator",
+ },
+};
+
+module_platform_driver(p1_regulator_driver);
+
+MODULE_DESCRIPTION("SpacemiT P1 regulator driver");
+MODULE_LICENSE("GPL");
--
2.45.2
On 6/14/25 05:01, Alex Elder wrote: > <snip> > > diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig > index 6d8988387da45..7bb7b8fad24f2 100644 > --- a/drivers/regulator/Kconfig > +++ b/drivers/regulator/Kconfig > @@ -1384,6 +1384,15 @@ config REGULATOR_SLG51000 > The SLG51000 is seven compact and customizable low dropout > regulators. > > +config REGULATOR_SPACEMIT_P1 > + tristate "SpacemiT P1 regulators" > + depends on ARCH_SPACEMIT || COMPILE_TEST > + default ARCH_SPACEMIT > + help > + Enable support for regulators implemented by the SpacemiT P1 > + power controller. The P1 implements 6 high-efficiency buck > + converters and 12 programmable LDO regulators. Needs module name in help text, as is the case with spacemit-pmic. > + > config REGULATOR_STM32_BOOSTER > tristate "STMicroelectronics STM32 BOOSTER" > depends on ARCH_STM32 || COMPILE_TEST > > <snip> > > +static struct platform_driver p1_regulator_driver = { > + .probe = p1_regulator_probe, > + .driver = { > + .name = "spacemit-p1-regulator", > + }, > +}; > + > +module_platform_driver(p1_regulator_driver); > + > +MODULE_DESCRIPTION("SpacemiT P1 regulator driver"); > +MODULE_LICENSE("GPL"); If this driver is compiled as a module, it needs to be found by modalias so the driver auto-loads after spacemit-pmic registers the regulator device, so you need: +MODULE_ALIAS("platform:spacemit-p1-regulator"); Also, consider extracting the name to a macro: #define DRV_NAME "spacemit-p1-regulator" Also, consider naming this consistently: "spacemit-p1", or "spacemit-p1-regulator"? Regards, Vivian "dramforever" Wang
On 6/19/25 1:15 AM, Vivian Wang wrote: > On 6/14/25 05:01, Alex Elder wrote: >> <snip> >> >> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig >> index 6d8988387da45..7bb7b8fad24f2 100644 >> --- a/drivers/regulator/Kconfig >> +++ b/drivers/regulator/Kconfig >> @@ -1384,6 +1384,15 @@ config REGULATOR_SLG51000 >> The SLG51000 is seven compact and customizable low dropout >> regulators. >> >> +config REGULATOR_SPACEMIT_P1 >> + tristate "SpacemiT P1 regulators" >> + depends on ARCH_SPACEMIT || COMPILE_TEST >> + default ARCH_SPACEMIT >> + help >> + Enable support for regulators implemented by the SpacemiT P1 >> + power controller. The P1 implements 6 high-efficiency buck >> + converters and 12 programmable LDO regulators. > Needs module name in help text, as is the case with spacemit-pmic. I will add this text. >> + >> config REGULATOR_STM32_BOOSTER >> tristate "STMicroelectronics STM32 BOOSTER" >> depends on ARCH_STM32 || COMPILE_TEST >> >> <snip> >> >> +static struct platform_driver p1_regulator_driver = { >> + .probe = p1_regulator_probe, >> + .driver = { >> + .name = "spacemit-p1-regulator", >> + }, >> +}; >> + >> +module_platform_driver(p1_regulator_driver); >> + >> +MODULE_DESCRIPTION("SpacemiT P1 regulator driver"); >> +MODULE_LICENSE("GPL"); > > If this driver is compiled as a module, it needs to be found by modalias > so the driver auto-loads after spacemit-pmic registers the regulator > device, so you need: > > +MODULE_ALIAS("platform:spacemit-p1-regulator"); > > Also, consider extracting the name to a macro: > > #define DRV_NAME "spacemit-p1-regulator" I will implement both of these suggestions (and will do so in the PMIC driver as well). > Also, consider naming this consistently: "spacemit-p1", or > "spacemit-p1-regulator"? Let me see if I understand your comment, by explaining the naming I used. The PMIC driver could support a different PMIC. Its OF match table specifies a compatible string with matching data, and the data describes attributes of the P1 PMIC. So that driver uses MOD_NAME "spacemit-pmic". This driver describes specifically the regulators found in the P1 PMIC, so it uses "spacemit-p1-regulator" as its MOD_NAME. You might still be right; but does this change what you are suggesting? Thanks. -Alex > > Regards, > Vivian "dramforever" Wang >
On 6/19/25 21:23, Alex Elder wrote: > On 6/19/25 1:15 AM, Vivian Wang wrote: >> Also, consider naming this consistently: "spacemit-p1", or >> "spacemit-p1-regulator"? > > Let me see if I understand your comment, by explaining the > naming I used. > > The PMIC driver could support a different PMIC. Its OF > match table specifies a compatible string with matching > data, and the data describes attributes of the P1 PMIC. > So that driver uses MOD_NAME "spacemit-pmic". > > This driver describes specifically the regulators found > in the P1 PMIC, so it uses "spacemit-p1-regulator" as > its MOD_NAME. > > You might still be right; but does this change what you > are suggesting? Oh sorry it was simpler than that. It's just I've noted that this regulator module file is called "spacemit-p1": > +obj-$(CONFIG_REGULATOR_SPACEMIT_P1) += spacemit-p1.o ... but the MOD_NAME is "spacemit-p1-regulator", and I was wondering if it made sense to rename the module to also "spacemit-p1-regulator". In addition to consistency, modules are free to have all sorts of names in Linux, but the names have to be unique, so if this is only the regulator driver part, the name should reflect that. Vivian "dramforever" Wang
On Fri, Jun 13, 2025 at 04:01:46PM -0500, Alex Elder wrote: > Add support for the regulators found in the SpacemiT P1 PMIC. This > PMIC provides six buck converters and 12 LDO regulators. Reviewed-by: Mark Brown <broonie@kernel.org>
© 2016 - 2025 Red Hat, Inc.