summaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig39
-rw-r--r--drivers/regulator/Makefile5
-rw-r--r--drivers/regulator/anatop-regulator.c29
-rw-r--r--drivers/regulator/bcm2835.c35
-rw-r--r--drivers/regulator/core.c634
-rw-r--r--drivers/regulator/fixed.c72
-rw-r--r--drivers/regulator/helpers.c28
-rw-r--r--drivers/regulator/of_regulator.c150
-rw-r--r--drivers/regulator/pfuze.c42
-rw-r--r--drivers/regulator/rk808-regulator.c963
-rw-r--r--drivers/regulator/scmi-regulator.c394
-rw-r--r--drivers/regulator/stm32-pwr.c220
-rw-r--r--drivers/regulator/stm32-vrefbuf.c219
-rw-r--r--drivers/regulator/stpmic1_regulator.c34
14 files changed, 2453 insertions, 411 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 28bd69a2a5..17e217f0bb 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
menuconfig REGULATOR
bool "voltage regulator support"
@@ -19,7 +20,23 @@ config REGULATOR_BCM283X
config REGULATOR_PFUZE
bool "Freescale PFUZE100/200/3000 regulator driver"
depends on I2C
- depends on ARCH_IMX6
+ depends on ARCH_IMX || COMPILE_TEST
+
+config REGULATOR_STM32_PWR
+ bool "STMicroelectronics STM32 PWR"
+ depends on ARCH_STM32MP
+ help
+ This driver supports internal regulators (1V1, 1V8, 3V3) in the
+ STMicroelectronics STM32 chips.
+
+config REGULATOR_STM32_VREFBUF
+ tristate "STMicroelectronics STM32 VREFBUF"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ This driver supports STMicroelectronics STM32 VREFBUF (voltage
+ reference buffer) which can be used as voltage reference for
+ internal ADCs, DACs and also for external components through
+ dedicated Vref+ pin.
config REGULATOR_STPMIC1
tristate "STMicroelectronics STPMIC1 PMIC Regulators"
@@ -38,4 +55,24 @@ config REGULATOR_ANATOP
regulators. It is recommended that this option be
enabled on i.MX6 platform.
+
+config REGULATOR_ARM_SCMI
+ tristate "SCMI based regulator driver"
+ depends on ARM_SCMI_PROTOCOL && OFDEVICE
+ help
+ This adds the regulator driver support for ARM platforms using SCMI
+ protocol for device voltage management.
+ This driver uses SCMI Message Protocol driver to interact with the
+ firmware providing the device Voltage functionality.
+
+config REGULATOR_RK808
+ tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power regulators"
+ depends on MFD_RK808
+ help
+ Select this option to enable the power regulator of ROCKCHIP
+ PMIC RK805,RK809&RK817,RK808 and RK818.
+ This driver supports the control of different power rails of device
+ through regulator interface. The device supports multiple DCDC/LDO
+ outputs which can be controlled by i2c communication.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index e27e155cf6..95e42719d1 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_REGULATOR) += core.o helpers.o
obj-$(CONFIG_OFDEVICE) += of_regulator.o
obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
@@ -5,3 +6,7 @@ obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
+obj-$(CONFIG_REGULATOR_ARM_SCMI) += scmi-regulator.o
+obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 7ec9446a0a..4b4c174304 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -1,27 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
#include <common.h>
#include <init.h>
#include <mfd/syscon.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <regulator.h>
struct anatop_regulator {
@@ -48,9 +33,9 @@ static struct regulator_ops anatop_rops = {
.list_voltage = regulator_list_voltage_linear,
};
-static int anatop_regulator_probe(struct device_d *dev)
+static int anatop_regulator_probe(struct device *dev)
{
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev->of_node;
struct device_node *anatop_np;
struct regulator_desc *rdesc;
struct regulator_dev *rdev;
@@ -67,6 +52,7 @@ static int anatop_regulator_probe(struct device_d *dev)
rdev->desc = rdesc;
rdev->regmap = syscon_node_to_regmap(anatop_np);
+ rdev->dev = dev;
if (IS_ERR(rdev->regmap))
return PTR_ERR(rdev->regmap);
@@ -145,15 +131,16 @@ static int anatop_regulator_probe(struct device_d *dev)
}
}
- return of_regulator_register(rdev, dev->device_node);
+ return of_regulator_register(rdev, dev->of_node);
}
static const struct of_device_id of_anatop_regulator_match_tbl[] = {
{ .compatible = "fsl,anatop-regulator", },
{ /* end */ }
};
+MODULE_DEVICE_TABLE(of, of_anatop_regulator_match_tbl);
-static struct driver_d anatop_regulator_driver = {
+static struct driver anatop_regulator_driver = {
.name = "anatop_regulator",
.probe = anatop_regulator_probe,
.of_compatible = DRV_OF_COMPAT(of_anatop_regulator_match_tbl),
diff --git a/drivers/regulator/bcm2835.c b/drivers/regulator/bcm2835.c
index ea7cf7fe1e..fa9fc47207 100644
--- a/drivers/regulator/bcm2835.c
+++ b/drivers/regulator/bcm2835.c
@@ -1,20 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* bcm2835 regulator support
*
* Copyright (c) 2015 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * GPLv2 Only
*/
#include <common.h>
#include <malloc.h>
#include <init.h>
#include <regulator.h>
-#include <mach/mbox.h>
+#include <mach/bcm283x/mbox.h>
#define REG_DEV(_id, _name) \
{ \
- .id = _id, \
+ .id = _id, \
.devname = _name,\
}
@@ -22,7 +21,6 @@ static struct regulator_bcm2835 {
int id;
char *devname;
- struct device_d *dev;
struct regulator_dev rdev;
struct regulator_desc rdesc;
} regs[] = {
@@ -43,8 +41,9 @@ struct msg_set_power_state {
u32 end_tag;
};
-static int regulator_bcm2835_set(struct regulator_bcm2835 *rb, int state)
+static int regulator_bcm2835_set(struct regulator_dev *rdev, int state)
{
+ struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev);
BCM2835_MBOX_STACK_ALIGN(struct msg_set_power_state, msg_pwr);
int ret;
@@ -59,8 +58,8 @@ static int regulator_bcm2835_set(struct regulator_bcm2835 *rb, int state)
ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
&msg_pwr->hdr);
if (ret) {
- dev_err(rb->dev ,"bcm2835: Could not set module %u power state\n",
- rb->id);
+ dev_err(rdev->dev, "bcm2835: Could not set module %u power state\n",
+ rb->id);
return ret;
}
@@ -69,16 +68,12 @@ static int regulator_bcm2835_set(struct regulator_bcm2835 *rb, int state)
static int regulator_bcm2835_enable(struct regulator_dev *rdev)
{
- struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev);
-
- return regulator_bcm2835_set(rb, BCM2835_MBOX_SET_POWER_STATE_REQ_ON);
+ return regulator_bcm2835_set(rdev, BCM2835_MBOX_SET_POWER_STATE_REQ_ON);
}
static int regulator_bcm2835_disable(struct regulator_dev *rdev)
{
- struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev);
-
- return regulator_bcm2835_set(rb, BCM2835_MBOX_SET_POWER_STATE_REQ_OFF);
+ return regulator_bcm2835_set(rdev, BCM2835_MBOX_SET_POWER_STATE_REQ_OFF);
}
struct msg_get_power_state {
@@ -101,8 +96,8 @@ static int regulator_bcm2835_is_enabled(struct regulator_dev *rdev)
ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
&msg_pwr->hdr);
if (ret) {
- dev_err(rb->dev ,"bcm2835: Could not get module %u power state\n",
- rb->id);
+ dev_err(rdev->dev, "bcm2835: Could not get module %u power state\n",
+ rb->id);
return ret;
}
@@ -115,7 +110,7 @@ const static struct regulator_ops bcm2835_ops = {
.is_enabled = regulator_bcm2835_is_enabled,
};
-static int regulator_bcm2835_probe(struct device_d *dev)
+static int regulator_bcm2835_probe(struct device *dev)
{
struct regulator_bcm2835 *rb;
int ret, i;
@@ -125,9 +120,9 @@ static int regulator_bcm2835_probe(struct device_d *dev)
rb->rdesc.ops = &bcm2835_ops;
rb->rdev.desc = &rb->rdesc;
- rb->dev = dev;
+ rb->rdev.dev = dev;
- ret = dev_regulator_register(&rb->rdev, rb->devname, NULL);
+ ret = dev_regulator_register(&rb->rdev, rb->devname);
if (ret)
return ret;
}
@@ -135,7 +130,7 @@ static int regulator_bcm2835_probe(struct device_d *dev)
return 0;
}
-static struct driver_d regulator_bcm2835_driver = {
+static struct driver regulator_bcm2835_driver = {
.name = "regulator-bcm2835",
.probe = regulator_bcm2835_probe,
};
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 4ca035ae94..bbba3b0b57 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1,104 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* barebox regulator support
*
* Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <regulator.h>
#include <of.h>
#include <malloc.h>
#include <linux/err.h>
+#include <deep-probe.h>
static LIST_HEAD(regulator_list);
-struct regulator_internal {
- struct list_head list;
- struct device_node *node;
- struct regulator_dev *rdev;
- int enable_count;
- int enable_time_us;
- int min_uv;
- int max_uv;
- char *name;
- const char *supply;
- struct list_head consumer_list;
-};
-
struct regulator {
- struct regulator_internal *ri;
+ struct regulator_dev *rdev;
+ struct regulator_dev *rdev_consumer;
struct list_head list;
- struct device_d *dev;
+ struct device *dev;
};
+const char *rdev_get_name(struct regulator_dev *rdev)
+{
+ if (rdev->name)
+ return rdev->name;
+
+ return "";
+}
+
static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
int max_uV)
{
if (rdev->desc->ops->list_voltage == regulator_list_voltage_linear)
return regulator_map_voltage_linear(rdev, min_uV, max_uV);
- return -ENOSYS;
+ if (rdev->desc->ops->list_voltage == regulator_list_voltage_linear_range)
+ return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
+
+ return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
-static int regulator_enable_internal(struct regulator_internal *ri)
+static int regulator_enable_rdev(struct regulator_dev *rdev)
{
int ret;
- if (ri->enable_count) {
- ri->enable_count++;
+ if (rdev->enable_count) {
+ rdev->enable_count++;
return 0;
}
- if (!ri->rdev->desc->ops->enable)
+ if (!rdev->desc->ops->enable)
return -ENOSYS;
- ret = ri->rdev->desc->ops->enable(ri->rdev);
+ /* turn on parent regulator */
+ ret = regulator_enable(rdev->supply);
if (ret)
return ret;
- if (ri->enable_time_us)
- udelay(ri->enable_time_us);
+ ret = rdev->desc->ops->enable(rdev);
+ if (ret) {
+ regulator_disable(rdev->supply);
+ return ret;
+ }
+
+ if (rdev->enable_time_us)
+ udelay(rdev->enable_time_us);
- ri->enable_count++;
+ rdev->enable_count++;
return 0;
}
-static int regulator_disable_internal(struct regulator_internal *ri)
+static int regulator_disable_rdev(struct regulator_dev *rdev)
{
int ret;
- if (!ri->enable_count)
+ if (!rdev->enable_count)
return -EINVAL;
- if (!ri->rdev->desc->ops->disable)
+ if (rdev->enable_count > 1) {
+ rdev->enable_count--;
+ return 0;
+ }
+
+ /* Crisis averted, be loud about the unbalanced regulator use */
+ if (WARN_ON(rdev->always_on))
+ return -EPERM;
+
+ if (!rdev->desc->ops->disable)
return -ENOSYS;
- ret = ri->rdev->desc->ops->disable(ri->rdev);
+ ret = rdev->desc->ops->disable(rdev);
if (ret)
return ret;
- ri->enable_count--;
+ rdev->enable_count--;
- return 0;
+ return regulator_disable(rdev->supply);
}
-static int regulator_set_voltage_internal(struct regulator_internal *ri,
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
- struct regulator_dev *rdev = ri->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
unsigned int selector;
int best_val = 0;
@@ -122,89 +125,233 @@ static int regulator_set_voltage_internal(struct regulator_internal *ri,
return -ENOSYS;
}
-static struct regulator_internal * __regulator_register(struct regulator_dev *rd, const char *name)
+static int regulator_get_voltage_rdev(struct regulator_dev *rdev)
{
- struct regulator_internal *ri;
- int ret;
+ int sel, ret;
+
+ if (rdev->desc->ops->get_voltage_sel) {
+ sel = rdev->desc->ops->get_voltage_sel(rdev);
+ if (sel < 0)
+ return sel;
+ ret = rdev->desc->ops->list_voltage(rdev, sel);
+ } else if (rdev->desc->ops->get_voltage) {
+ ret = rdev->desc->ops->get_voltage(rdev);
+ } else if (rdev->desc->ops->list_voltage) {
+ ret = rdev->desc->ops->list_voltage(rdev, 0);
+ } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
+ ret = rdev->desc->fixed_uV;
+ } else if (rdev->min_uv && rdev->min_uv == rdev->max_uv) {
+ ret = rdev->min_uv;
+ } else if (rdev->supply) {
+ ret = regulator_get_voltage(rdev->supply);
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int regulator_resolve_supply(struct regulator_dev *rdev)
+{
+ struct regulator *supply;
+ const char *supply_name;
+
+ if (!rdev || rdev->supply)
+ return 0;
+
+ supply_name = rdev->desc->supply_name;
+ if (!supply_name)
+ return 0;
+
+ rdev_dbg(rdev, "resolving %s\n", supply_name);
+
+ supply = regulator_get(rdev->dev, supply_name);
+ if (IS_ERR(supply)) {
+ if (deep_probe_is_supported())
+ return PTR_ERR(supply);
+
+ /* For historic reasons, some regulator consumers don't handle
+ * -EPROBE_DEFER (e.g. vmmc-supply). If we now start propagating
+ * parent EPROBE_DEFER, previously requested vmmc-supply with
+ * always-on parent that worked before will end up not being
+ * requested breaking MMC use. So for non-deep probe systems,
+ * just make best effort to resolve, but don't fail the get if
+ * we couldn't. If you want to get rid of this warning, consider
+ * migrating your platform to have deep probe support.
+ */
+ rdev_warn(rdev, "Failed to get '%s' regulator (ignored).\n",
+ supply_name);
+ return 0;
+ }
+
+ if (supply)
+ supply->rdev_consumer = rdev;
+
+ rdev->supply = supply;
+
+ return 0;
+}
+
+static int regulator_init_voltage(struct regulator_dev *rdev)
+{
+ int target_min, target_max, current_uV, ret;
+
+ if (!rdev->min_uv || !rdev->max_uv)
+ return 0;
+
+ current_uV = regulator_get_voltage_rdev(rdev);
+ if (current_uV < 0) {
+ /* This regulator can't be read and must be initialized */
+ rdev_info(rdev, "Setting %d-%duV\n", rdev->min_uv, rdev->max_uv);
+ regulator_set_voltage_rdev(rdev, rdev->min_uv, rdev->max_uv);
+ current_uV = regulator_get_voltage_rdev(rdev);
+ }
+
+ if (current_uV < 0) {
+ if (current_uV != -EPROBE_DEFER)
+ rdev_err(rdev,
+ "failed to get the current voltage: %pe\n",
+ ERR_PTR(current_uV));
+ return current_uV;
+ }
+
+ /*
+ * If we're below the minimum voltage move up to the
+ * minimum voltage, if we're above the maximum voltage
+ * then move down to the maximum.
+ */
+ target_min = current_uV;
+ target_max = current_uV;
+
+ if (current_uV < rdev->min_uv) {
+ target_min = rdev->min_uv;
+ target_max = rdev->min_uv;
+ }
+
+ if (current_uV > rdev->max_uv) {
+ target_min = rdev->max_uv;
+ target_max = rdev->max_uv;
+ }
+
+ if (target_min != current_uV || target_max != current_uV) {
+ rdev_info(rdev, "Bringing %duV into %d-%duV\n",
+ current_uV, target_min, target_max);
+ ret = regulator_set_voltage_rdev(rdev, target_min, target_max);
+ if (ret < 0) {
+ rdev_err(rdev,
+ "failed to apply %d-%duV constraint: %pe\n",
+ target_min, target_max, ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ return 0;
+}
- ri = xzalloc(sizeof(*ri));
- ri->rdev = rd;
+static int __regulator_register(struct regulator_dev *rdev, const char *name)
+{
+ int ret;
- INIT_LIST_HEAD(&ri->consumer_list);
+ INIT_LIST_HEAD(&rdev->consumer_list);
- list_add_tail(&ri->list, &regulator_list);
+ list_add_tail(&rdev->list, &regulator_list);
if (name)
- ri->name = xstrdup(name);
+ rdev->name = xstrdup(name);
- if (rd->boot_on) {
- ret = regulator_enable_internal(ri);
+ ret = regulator_init_voltage(rdev);
+ if (ret)
+ goto err;
+
+ if (rdev->boot_on || rdev->always_on) {
+ ret = regulator_resolve_supply(rdev);
+ if (ret < 0)
+ goto err;
+
+ ret = regulator_enable_rdev(rdev);
if (ret && ret != -ENOSYS)
goto err;
}
- return ri;
+ return 0;
err:
- list_del(&ri->list);
- free(ri->name);
- free(ri);
+ list_del(&rdev->list);
+ free((char *)rdev->name);
- return ERR_PTR(ret);
+ return ret;
}
#ifdef CONFIG_OFDEVICE
/*
* of_regulator_register - register a regulator corresponding to a device_node
- * @rd: the regulator device providing the ops
+ * rdev: the regulator device providing the ops
* @node: the device_node this regulator corresponds to
*
* Return: 0 for success or a negative error code
*/
-int of_regulator_register(struct regulator_dev *rd, struct device_node *node)
+int of_regulator_register(struct regulator_dev *rdev, struct device_node *node)
{
- struct regulator_internal *ri;
const char *name;
+ int ret;
+
+ if (!rdev || !node)
+ return -EINVAL;
- rd->boot_on = of_property_read_bool(node, "regulator-boot-on");
+ rdev->boot_on = of_property_read_bool(node, "regulator-boot-on");
+ rdev->always_on = of_property_read_bool(node, "regulator-always-on");
name = of_get_property(node, "regulator-name", NULL);
+ if (!name)
+ name = node->name;
- ri = __regulator_register(rd, name);
- ri->node = node;
+ rdev->node = node;
+ node->dev = rdev->dev;
+
+ if (rdev->desc->off_on_delay)
+ rdev->enable_time_us = rdev->desc->off_on_delay;
+
+ if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)
+ rdev->min_uv = rdev->max_uv = rdev->desc->fixed_uV;
of_property_read_u32(node, "regulator-enable-ramp-delay",
- &ri->enable_time_us);
+ &rdev->enable_time_us);
of_property_read_u32(node, "regulator-min-microvolt",
- &ri->min_uv);
+ &rdev->min_uv);
of_property_read_u32(node, "regulator-max-microvolt",
- &ri->max_uv);
+ &rdev->max_uv);
+
+ ret = __regulator_register(rdev, name);
+ if (ret)
+ return ret;
return 0;
}
-static struct regulator_internal *of_regulator_get(struct device_d *dev, const char *supply)
+static struct regulator_dev *of_regulator_get(struct device *dev,
+ const char *supply)
{
char *propname;
- struct regulator_internal *ri;
- struct device_node *node;
-
- propname = basprintf("%s-supply", supply);
+ struct regulator_dev *rdev;
+ struct device_node *node, *node_parent;
+ int ret;
/*
* If the device does have a device node return the dummy regulator.
*/
- if (!dev->device_node)
+ if (!dev->of_node)
return NULL;
+ propname = basprintf("%s-supply", supply);
+
/*
* If the device node does not contain a supply property, this device doesn't
* need a regulator. Return the dummy regulator in this case.
*/
- if (!of_get_property(dev->device_node, propname, NULL)) {
+ if (!of_get_property(dev->of_node, propname, NULL)) {
dev_dbg(dev, "No %s-supply node found, using dummy regulator\n",
supply);
- ri = NULL;
+ rdev = NULL;
goto out;
}
@@ -212,17 +359,38 @@ static struct regulator_internal *of_regulator_get(struct device_d *dev, const c
* The device node specifies a supply, so it's mandatory. Return an error when
* something goes wrong below.
*/
- node = of_parse_phandle(dev->device_node, propname, 0);
+ node = of_parse_phandle(dev->of_node, propname, 0);
if (!node) {
dev_dbg(dev, "No %s node found\n", propname);
- ri = ERR_PTR(-EINVAL);
+ rdev = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ ret = of_device_ensure_probed(node);
+ if (ret) {
+ /*
+ * If "barebox,allow-dummy-supply" property is set for regulator
+ * provider allow use of dummy regulator (NULL is returned).
+ * Check regulator node and its parent if this setting is set
+ * PMIC wide.
+ */
+ node_parent = of_get_parent(node);
+ if (of_get_property(node, "barebox,allow-dummy-supply", NULL) ||
+ of_get_property(node_parent, "barebox,allow-dummy-supply", NULL)) {
+ dev_dbg(dev, "Allow use of dummy regulator for " \
+ "%s-supply\n", supply);
+ rdev = NULL;
+ goto out;
+ }
+
+ rdev = ERR_PTR(ret);
goto out;
}
- list_for_each_entry(ri, &regulator_list, list) {
- if (ri->node == node) {
- dev_dbg(dev, "Using %s regulator from %s\n",
- propname, node->full_name);
+ list_for_each_entry(rdev, &regulator_list, list) {
+ if (rdev->node == node) {
+ dev_dbg(dev, "Using %s regulator from %pOF\n",
+ propname, node);
goto out;
}
}
@@ -232,52 +400,54 @@ static struct regulator_internal *of_regulator_get(struct device_d *dev, const c
* added in future initcalls, so, instead of reporting a
* complete failure report probe deferral
*/
- ri = ERR_PTR(-EPROBE_DEFER);
+ rdev = ERR_PTR(-EPROBE_DEFER);
out:
free(propname);
- return ri;
+ return rdev;
}
#else
-static struct regulator_internal *of_regulator_get(struct device_d *dev, const char *supply)
+static struct regulator_dev *of_regulator_get(struct device *dev,
+ const char *supply)
{
return NULL;
}
#endif
-int dev_regulator_register(struct regulator_dev *rd, const char * name, const char* supply)
+int dev_regulator_register(struct regulator_dev *rdev, const char *name)
{
- struct regulator_internal *ri;
-
- ri = __regulator_register(rd, name);
+ int ret;
- ri->supply = supply;
+ ret = __regulator_register(rdev, name);
+ if (ret)
+ return ret;
return 0;
}
-static struct regulator_internal *dev_regulator_get(struct device_d *dev, const char *supply)
+static struct regulator_dev *dev_regulator_get(struct device *dev,
+ const char *supply)
{
- struct regulator_internal *ri;
- struct regulator_internal *ret = NULL;
+ struct regulator_dev *rdev;
+ struct regulator_dev *ret = NULL;
int match, best = 0;
const char *dev_id = dev ? dev_name(dev) : NULL;
- list_for_each_entry(ri, &regulator_list, list) {
+ list_for_each_entry(rdev, &regulator_list, list) {
match = 0;
- if (ri->name) {
- if (!dev_id || strcmp(ri->name, dev_id))
+ if (rdev->name) {
+ if (!dev_id || strcmp(rdev->name, dev_id))
continue;
match += 2;
}
- if (ri->supply) {
- if (!supply || strcmp(ri->supply, supply))
+ if (rdev->desc->supply_name) {
+ if (!supply || strcmp(rdev->desc->supply_name, supply))
continue;
match += 1;
}
if (match > best) {
- ret = ri;
+ ret = rdev;
if (match != 3)
best = match;
else
@@ -298,31 +468,73 @@ static struct regulator_internal *dev_regulator_get(struct device_d *dev, const
*
* Return: a regulator object or an error pointer
*/
-struct regulator *regulator_get(struct device_d *dev, const char *supply)
+struct regulator *regulator_get(struct device *dev, const char *supply)
{
- struct regulator_internal *ri = NULL;
+ struct regulator_dev *rdev = NULL;
struct regulator *r;
+ int ret;
- if (dev->device_node) {
- ri = of_regulator_get(dev, supply);
- if (IS_ERR(ri))
- return ERR_CAST(ri);
+ if (dev->of_node && supply) {
+ rdev = of_regulator_get(dev, supply);
+ if (IS_ERR(rdev))
+ return ERR_CAST(rdev);
}
- if (!ri) {
- ri = dev_regulator_get(dev, supply);
- if (IS_ERR(ri))
- return ERR_CAST(ri);
+ if (!rdev) {
+ rdev = dev_regulator_get(dev, supply);
+ if (IS_ERR(rdev))
+ return ERR_CAST(rdev);
}
- if (!ri)
+ if (!rdev)
return NULL;
+ ret = regulator_resolve_supply(rdev);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
r = xzalloc(sizeof(*r));
- r->ri = ri;
+ r->rdev = rdev;
r->dev = dev;
- list_add_tail(&r->list, &ri->consumer_list);
+ list_add_tail(&r->list, &rdev->consumer_list);
+
+ return r;
+}
+
+void regulator_put(struct regulator *r)
+{
+ if (IS_ERR_OR_NULL(r))
+ return;
+ list_del(&r->list);
+ free(r);
+}
+
+static struct regulator_dev *regulator_by_name(const char *name)
+{
+ struct regulator_dev *rdev;
+
+ list_for_each_entry(rdev, &regulator_list, list) {
+ if (rdev->name && !strcmp(rdev->name, name))
+ return rdev;
+ }
+
+ return NULL;
+}
+
+struct regulator *regulator_get_name(const char *name)
+{
+ struct regulator_dev *rdev;
+ struct regulator *r;
+
+ rdev = regulator_by_name(name);
+ if (!rdev)
+ return ERR_PTR(-ENODEV);
+
+ r = xzalloc(sizeof(*r));
+ r->rdev = rdev;
+
+ list_add_tail(&r->list, &rdev->consumer_list);
return r;
}
@@ -341,7 +553,7 @@ int regulator_enable(struct regulator *r)
if (!r)
return 0;
- return regulator_enable_internal(r->ri);
+ return regulator_enable_rdev(r->rdev);
}
/*
@@ -358,7 +570,7 @@ int regulator_disable(struct regulator *r)
if (!r)
return 0;
- return regulator_disable_internal(r->ri);
+ return regulator_disable_rdev(r->rdev);
}
int regulator_set_voltage(struct regulator *r, int min_uV, int max_uV)
@@ -366,31 +578,199 @@ int regulator_set_voltage(struct regulator *r, int min_uV, int max_uV)
if (!r)
return 0;
- return regulator_set_voltage_internal(r->ri, min_uV, max_uV);
+ return regulator_set_voltage_rdev(r->rdev, min_uV, max_uV);
+}
+
+/**
+ * regulator_bulk_get - get multiple regulator consumers
+ *
+ * @dev: Device to supply
+ * @num_consumers: Number of consumers to register
+ * @consumers: Configuration of consumers; clients are stored here.
+ *
+ * @return 0 on success, an errno on failure.
+ *
+ * This helper function allows drivers to get several regulator
+ * consumers in one operation. If any of the regulators cannot be
+ * acquired then any regulators that were allocated will be freed
+ * before returning to the caller.
+ */
+int regulator_bulk_get(struct device *dev, int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < num_consumers; i++)
+ consumers[i].consumer = NULL;
+
+ for (i = 0; i < num_consumers; i++) {
+ consumers[i].consumer = regulator_get(dev,
+ consumers[i].supply);
+ if (IS_ERR(consumers[i].consumer)) {
+ ret = PTR_ERR(consumers[i].consumer);
+ consumers[i].consumer = NULL;
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get supply '%s': %d\n",
+ consumers[i].supply, ret);
+ else
+ dev_dbg(dev, "Failed to get supply '%s', deferring\n",
+ consumers[i].supply);
+
+ return ret;
}
+EXPORT_SYMBOL_GPL(regulator_bulk_get);
-static void regulator_print_one(struct regulator_internal *ri)
+/**
+ * regulator_bulk_enable - enable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers: Consumer data; clients are stored here.
+ * @return 0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to enable multiple regulator
+ * clients in a single API call. If any consumers cannot be enabled
+ * then any others that were enabled will be disabled again prior to
+ * return.
+ */
+int regulator_bulk_enable(int num_consumers,
+ struct regulator_bulk_data *consumers)
{
+ int ret;
+ int i;
+
+ for (i = 0; i < num_consumers; i++) {
+ ret = regulator_enable(consumers[i].consumer);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0)
+ regulator_disable(consumers[i].consumer);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_enable);
+
+/**
+ * regulator_bulk_disable - disable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers: Consumer data; clients are stored here.
+ * @return 0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to disable multiple regulator
+ * clients in a single API call. If any consumers cannot be disabled
+ * then any others that were disabled will be enabled again prior to
+ * return.
+ */
+int regulator_bulk_disable(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int i;
+ int ret, r;
+
+ for (i = num_consumers - 1; i >= 0; --i) {
+ ret = regulator_disable(consumers[i].consumer);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
+ for (++i; i < num_consumers; ++i) {
+ r = regulator_enable(consumers[i].consumer);
+ if (r != 0)
+ pr_err("Failed to re-enable %s: %d\n",
+ consumers[i].supply, r);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_disable);
+
+/**
+ * regulator_bulk_free - free multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers: Consumer data; clients are stored here.
+ *
+ * This convenience API allows consumers to free multiple regulator
+ * clients in a single API call.
+ */
+void regulator_bulk_free(int num_consumers,
+ struct regulator_bulk_data *consumers)
+{
+ int i;
+
+ for (i = 0; i < num_consumers; i++)
+ consumers[i].consumer = NULL;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_free);
+
+int regulator_get_voltage(struct regulator *regulator)
+{
+ if (!regulator)
+ return -EINVAL;
+
+ return regulator_get_voltage_rdev(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage);
+
+static int regulator_name_indent(unsigned flags)
+{
+ return 30 + (flags & REGULATOR_PRINT_DEVS ? 50 : 0);
+}
+
+static void regulator_print_one(struct regulator_dev *rdev, int level, unsigned flags)
+{
+ const char *name = rdev->name;
struct regulator *r;
+ char buf[256];
+
+ if (!rdev)
+ return;
- printf("%-20s %6d %10d %10d\n", ri->name, ri->enable_count, ri->min_uv, ri->max_uv);
+ if (flags & REGULATOR_PRINT_DEVS) {
+ snprintf(buf, sizeof(buf), "%s %s", dev_name(rdev->dev), rdev->name);
+ name = buf;
+ }
- if (!list_empty(&ri->consumer_list)) {
- printf(" consumers:\n");
+ printf("%*s%-*s %6d %10d %10d\n", level * 3, "",
+ regulator_name_indent(flags) - level * 3,
+ name, rdev->enable_count, rdev->min_uv, rdev->max_uv);
- list_for_each_entry(r, &ri->consumer_list, list)
- printf(" %s\n", dev_name(r->dev));
+ list_for_each_entry(r, &rdev->consumer_list, list) {
+ if (r->rdev_consumer)
+ regulator_print_one(r->rdev_consumer, level + 1, flags);
+ else
+ printf("%*s%s\n", (level + 1) * 3, "", r->dev ? dev_name(r->dev) : "none");
}
}
/*
* regulators_print - print informations about all regulators
*/
-void regulators_print(void)
+void regulators_print(unsigned flags)
{
- struct regulator_internal *ri;
+ struct regulator_dev *rdev;
- printf("%-20s %6s %10s %10s\n", "name", "enable", "min_uv", "max_uv");
- list_for_each_entry(ri, &regulator_list, list)
- regulator_print_one(ri);
+ printf("%-*s %6s %10s %10s\n", regulator_name_indent(flags),
+ "name", "enable", "min_uv", "max_uv");
+ list_for_each_entry(rdev, &regulator_list, list) {
+ if (!rdev->supply)
+ regulator_print_one(rdev, 0, flags);
+ }
}
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index cb5d785817..0edb5ceb10 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -1,33 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* fixed regulator support
*
* Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <malloc.h>
#include <init.h>
#include <regulator.h>
#include <of.h>
-#include <of_gpio.h>
-#include <gpio.h>
+#include <linux/gpio/consumer.h>
struct regulator_fixed {
- int gpio;
- int active_low;
- int always_on;
+ struct gpio_desc *gpio;
struct regulator_dev rdev;
struct regulator_desc rdesc;
};
@@ -36,23 +21,14 @@ static int regulator_fixed_enable(struct regulator_dev *rdev)
{
struct regulator_fixed *fix = container_of(rdev, struct regulator_fixed, rdev);
- if (!gpio_is_valid(fix->gpio))
- return 0;
-
- return gpio_direction_output(fix->gpio, !fix->active_low);
+ return gpiod_direction_output(fix->gpio, true);
}
static int regulator_fixed_disable(struct regulator_dev *rdev)
{
struct regulator_fixed *fix = container_of(rdev, struct regulator_fixed, rdev);
- if (fix->always_on)
- return 0;
-
- if (!gpio_is_valid(fix->gpio))
- return 0;
-
- return gpio_direction_output(fix->gpio, fix->active_low);
+ return gpiod_direction_output(fix->gpio, false);
}
const static struct regulator_ops fixed_ops = {
@@ -60,40 +36,37 @@ const static struct regulator_ops fixed_ops = {
.disable = regulator_fixed_disable,
};
-static int regulator_fixed_probe(struct device_d *dev)
+static int regulator_fixed_probe(struct device *dev)
{
+ struct device_node *np = dev->of_node;
struct regulator_fixed *fix;
- enum of_gpio_flags gpioflags;
+ u32 delay;
int ret;
- if (!dev->device_node)
+ if (!dev->of_node)
return -EINVAL;
fix = xzalloc(sizeof(*fix));
- fix->gpio = -EINVAL;
-
- if (of_get_property(dev->device_node, "gpio", NULL)) {
- fix->gpio = of_get_named_gpio_flags(dev->device_node, "gpio", 0, &gpioflags);
- if (fix->gpio < 0) {
- ret = fix->gpio;
- goto err;
- }
- if (gpioflags & OF_GPIO_ACTIVE_LOW)
- fix->active_low = 1;
+ fix->gpio = gpiod_get_optional(dev, NULL, GPIOD_ASIS);
+ if (IS_ERR(fix->gpio)) {
+ ret = PTR_ERR(fix->gpio);
+ goto err;
}
fix->rdesc.ops = &fixed_ops;
fix->rdev.desc = &fix->rdesc;
+ fix->rdev.dev = dev;
- if (of_find_property(dev->device_node, "regulator-always-on", NULL)) {
- fix->always_on = 1;
- regulator_fixed_enable(&fix->rdev);
- }
+ if (!of_property_read_u32(np, "off-on-delay-us", &delay))
+ fix->rdesc.off_on_delay = delay;
+
+ if (of_find_property(np, "vin-supply", NULL))
+ fix->rdesc.supply_name = "vin";
- ret = of_regulator_register(&fix->rdev, dev->device_node);
+ ret = of_regulator_register(&fix->rdev, np);
if (ret)
- return ret;
+ goto err;
return 0;
err:
@@ -106,8 +79,9 @@ static struct of_device_id regulator_fixed_of_ids[] = {
{ .compatible = "regulator-fixed", },
{ }
};
+MODULE_DEVICE_TABLE(of, regulator_fixed_of_ids);
-static struct driver_d regulator_fixed_driver = {
+static struct driver regulator_fixed_driver = {
.name = "regulator-fixed",
.probe = regulator_fixed_probe,
.of_compatible = DRV_OF_COMPAT(regulator_fixed_of_ids),
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index c4877cecf7..80102e2c10 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -1,5 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <regulator.h>
/**
@@ -369,4 +370,29 @@ int regulator_map_voltage_iterate(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
+/**
+ * regulator_list_voltage_table - List voltages with table based mapping
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with table based mapping between voltages and
+ * selectors can set volt_table in the regulator descriptor
+ * and then use this function as their list_voltage() operation.
+ */
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ if (!rdev->desc->volt_table) {
+ BUG_ON(!rdev->desc->volt_table);
+ return -EINVAL;
+ }
+ if (selector >= rdev->desc->n_voltages)
+ return -EINVAL;
+ if (selector < rdev->desc->linear_min_sel)
+ return 0;
+
+ return rdev->desc->volt_table[selector];
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 3e8caa8710..10f75a4f1c 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -9,145 +9,6 @@
#include <common.h>
#include <of.h>
#include <linux/regulator/of_regulator.h>
-#include <linux/regulator/machine.h>
-
-static int of_get_regulation_constraints(struct device_d *dev,
- struct device_node *np,
- struct regulator_init_data **init_data,
- const struct regulator_desc *desc)
-{
- struct regulation_constraints *constraints = &(*init_data)->constraints;
- int ret;
- u32 pval;
-
- constraints->name = of_get_property(np, "regulator-name", NULL);
-
- if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
- constraints->min_uV = pval;
-
- if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
- constraints->max_uV = pval;
-
- /* Voltage change possible? */
- if (constraints->min_uV != constraints->max_uV)
- constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
-
- /* Do we have a voltage range, if so try to apply it? */
- if (constraints->min_uV && constraints->max_uV)
- constraints->apply_uV = true;
-
- if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
- constraints->uV_offset = pval;
- if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
- constraints->min_uA = pval;
- if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
- constraints->max_uA = pval;
-
- if (!of_property_read_u32(np, "regulator-input-current-limit-microamp",
- &pval))
- constraints->ilim_uA = pval;
-
- /* Current change possible? */
- if (constraints->min_uA != constraints->max_uA)
- constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
-
- constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
- constraints->always_on = of_property_read_bool(np, "regulator-always-on");
- if (!constraints->always_on) /* status change should be possible. */
- constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
-
- constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
-
- if (of_property_read_bool(np, "regulator-allow-bypass"))
- constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
-
- if (of_property_read_bool(np, "regulator-allow-set-load"))
- constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
-
- ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
- if (!ret) {
- if (pval)
- constraints->ramp_delay = pval;
- else
- constraints->ramp_disable = true;
- }
-
- ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
- if (!ret)
- constraints->settling_time = pval;
-
- ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval);
- if (!ret)
- constraints->settling_time_up = pval;
- if (constraints->settling_time_up && constraints->settling_time) {
- pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
- np);
- constraints->settling_time_up = 0;
- }
-
- ret = of_property_read_u32(np, "regulator-settling-time-down-us",
- &pval);
- if (!ret)
- constraints->settling_time_down = pval;
- if (constraints->settling_time_down && constraints->settling_time) {
- pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
- np);
- constraints->settling_time_down = 0;
- }
-
- ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
- if (!ret)
- constraints->enable_time = pval;
-
- constraints->soft_start = of_property_read_bool(np,
- "regulator-soft-start");
- ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
- if (!ret) {
- constraints->active_discharge =
- (pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
- REGULATOR_ACTIVE_DISCHARGE_DISABLE;
- }
-
- if (!of_property_read_u32(np, "regulator-system-load", &pval))
- constraints->system_load = pval;
-
- if (!of_property_read_u32(np, "regulator-max-step-microvolt",
- &pval))
- constraints->max_uV_step = pval;
-
- constraints->over_current_protection = of_property_read_bool(np,
- "regulator-over-current-protection");
-
- return 0;
-}
-
-/**
- * of_get_regulator_init_data - extract regulator_init_data structure info
- * @dev: device requesting for regulator_init_data
- * @node: regulator device node
- * @desc: regulator description
- *
- * Populates regulator_init_data structure by extracting data from device
- * tree node, returns a pointer to the populated structure or NULL if memory
- * alloc fails.
- */
-struct regulator_init_data *of_get_regulator_init_data(struct device_d *dev,
- struct device_node *node,
- const struct regulator_desc *desc)
-{
- struct regulator_init_data *init_data;
-
- if (!node)
- return NULL;
-
- init_data = xzalloc(sizeof(*init_data));
-
- if (of_get_regulation_constraints(dev, node, &init_data, desc))
- return NULL;
-
- return init_data;
-}
-EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
struct devm_of_regulator_matches {
struct of_regulator_match *matches;
@@ -172,7 +33,7 @@ struct devm_of_regulator_matches {
*
* Returns the number of matches found or a negative error code on failure.
*/
-int of_regulator_match(struct device_d *dev, struct device_node *node,
+int of_regulator_match(struct device *dev, struct device_node *node,
struct of_regulator_match *matches,
unsigned int num_matches)
{
@@ -192,7 +53,6 @@ int of_regulator_match(struct device_d *dev, struct device_node *node,
for (i = 0; i < num_matches; i++) {
struct of_regulator_match *match = &matches[i];
- match->init_data = NULL;
match->of_node = NULL;
}
@@ -210,14 +70,6 @@ int of_regulator_match(struct device_d *dev, struct device_node *node,
if (strcmp(match->name, name))
continue;
- match->init_data = of_get_regulator_init_data(dev, child,
- match->desc);
- if (!match->init_data) {
- dev_err(dev,
- "failed to parse DT for regulator %pOFn\n",
- child);
- return -EINVAL;
- }
match->of_node = child;
count++;
break;
diff --git a/drivers/regulator/pfuze.c b/drivers/regulator/pfuze.c
index 1950ffb04c..3e8890b10c 100644
--- a/drivers/regulator/pfuze.c
+++ b/drivers/regulator/pfuze.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2017 Sascha Hauer, Pengutronix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -21,18 +10,15 @@
#include <errno.h>
#include <malloc.h>
#include <of.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <mfd/pfuze.h>
#include <i2c/i2c.h>
#include <poweroff.h>
-#include <mach/imx6.h>
#define DRIVERNAME "pfuze"
-#define MC13XXX_NUMREGS 0x3f
-
#define PFUZE100_SW1ABMODE 0x23
#define PFUZE100_SW1CMODE 0x31
#define PFUZE100_SW2MODE 0x38
@@ -54,7 +40,7 @@
#define PFUZE100_VGENxSTBY BIT(5)
struct pfuze {
- struct device_d *dev;
+ struct device *dev;
struct regmap *map;
struct i2c_client *client;
int revision;
@@ -144,8 +130,6 @@ static void pfuze_power_off_prepare(struct poweroff_handler *handler)
regmap_write_bits(pfuze_dev->map, PFUZE100_VGEN6VOL,
PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
PFUZE100_VGENxSTBY);
-
- imx6_pm_stby_poweroff();
}
static struct regmap_bus regmap_pfuze_i2c_bus = {
@@ -159,7 +143,7 @@ static const struct regmap_config pfuze_regmap_i2c_config = {
.max_register = 127,
};
-static int __init pfuze_probe(struct device_d *dev)
+static int __init pfuze_probe(struct device *dev)
{
int ret;
@@ -180,7 +164,7 @@ static int __init pfuze_probe(struct device_d *dev)
if (pfuze_init_callback)
pfuze_init_callback(pfuze_dev->map);
- if (of_property_read_bool(dev->device_node,
+ if (of_property_read_bool(dev->of_node,
"fsl,pmic-stby-poweroff"))
return poweroff_handler_register_fn(pfuze_power_off_prepare);
@@ -202,23 +186,13 @@ static __maybe_unused struct of_device_id pfuze_dt_ids[] = {
{ .compatible = "fsl,pfuze3001" },
{ }
};
+MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
-static struct driver_d pfuze_i2c_driver = {
+static struct driver pfuze_i2c_driver = {
.name = "pfuze-i2c",
.probe = pfuze_probe,
.id_table = pfuze_ids,
.of_compatible = DRV_OF_COMPAT(pfuze_dt_ids),
};
-static int __init pfuze_init(void)
-{
- int ret;
-
- ret = i2c_driver_register(&pfuze_i2c_driver);
- if (ret)
- return ret;
-
- return 0;
-
-}
-late_initcall(pfuze_init);
+device_i2c_driver(pfuze_i2c_driver);
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
new file mode 100644
index 0000000000..adb0262314
--- /dev/null
+++ b/drivers/regulator/rk808-regulator.c
@@ -0,0 +1,963 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Regulator driver for Rockchip RK808
+ *
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ * Author: Zhang Qing <zhangqing@rock-chips.com>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <gpio.h>
+#include <init.h>
+#include <i2c/i2c.h>
+#include <of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/of_regulator.h>
+#include <regulator.h>
+#include <linux/mfd/rk808.h>
+
+/* Field Definitions */
+#define RK808_BUCK_VSEL_MASK 0x3f
+#define RK808_BUCK4_VSEL_MASK 0xf
+#define RK808_LDO_VSEL_MASK 0x1f
+
+#define RK809_BUCK5_VSEL_MASK 0x7
+
+#define RK817_LDO_VSEL_MASK 0x7f
+#define RK817_BOOST_VSEL_MASK 0x7
+#define RK817_BUCK_VSEL_MASK 0x7f
+
+#define RK818_BUCK_VSEL_MASK 0x3f
+#define RK818_BUCK4_VSEL_MASK 0x1f
+#define RK818_LDO_VSEL_MASK 0x1f
+#define RK818_LDO3_ON_VSEL_MASK 0xf
+#define RK818_BOOST_ON_VSEL_MASK 0xe0
+
+#define ENABLE_MASK(id) (BIT(id) | BIT(4 + (id)))
+#define DISABLE_VAL(id) (BIT(4 + (id)))
+
+#define RK817_BOOST_DESC(_supply_name, _min, _max, _step, _vreg,\
+ _vmask, _ereg, _emask, _enval, _disval, _etime) \
+ {{ \
+ .supply_name = (_supply_name), \
+ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
+ .min_uV = (_min) * 1000, \
+ .uV_step = (_step) * 1000, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .enable_val = (_enval), \
+ .disable_val = (_disval), \
+ .off_on_delay = (_etime), \
+ .ops = &rk817_boost_ops, \
+ }}
+
+#define RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _enval, _disval, _etime, _ops) \
+ {{ \
+ .supply_name = (_supply_name), \
+ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
+ .min_uV = (_min) * 1000, \
+ .uV_step = (_step) * 1000, \
+ .vsel_reg = (_vreg), \
+ .vsel_mask = (_vmask), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .enable_val = (_enval), \
+ .disable_val = (_disval), \
+ .off_on_delay = (_etime), \
+ .ops = _ops, \
+ }}
+
+#define RK805_DESC(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _etime) \
+ RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops)
+
+#define RK8XX_DESC(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _etime) \
+ RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops)
+
+#define RK817_DESC(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _disval, _etime) \
+ RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _emask, _disval, _etime, &rk817_reg_ops)
+
+#define RKXX_DESC_SWITCH_COM(_supply_name,_ereg, _emask, \
+ _enval, _disval, _ops) \
+ {{ \
+ .supply_name = (_supply_name), \
+ .enable_reg = (_ereg), \
+ .enable_mask = (_emask), \
+ .enable_val = (_enval), \
+ .disable_val = (_disval), \
+ .ops = _ops \
+ }}
+
+#define RK817_DESC_SWITCH(_supply_name, _ereg, _emask, \
+ _disval) \
+ RKXX_DESC_SWITCH_COM(_supply_name, _ereg, _emask, \
+ _emask, _disval, &rk817_switch_ops)
+
+#define RK8XX_DESC_SWITCH(_supply_name, _ereg, _emask) \
+ RKXX_DESC_SWITCH_COM(_supply_name, _ereg, _emask, \
+ 0, 0, &rk808_switch_ops)
+
+static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000),
+ REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
+};
+
+#define RK809_BUCK5_SEL_CNT (8)
+
+static const struct regulator_linear_range rk809_buck5_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1500000, 0, 0, 0),
+ REGULATOR_LINEAR_RANGE(1800000, 1, 3, 200000),
+ REGULATOR_LINEAR_RANGE(2800000, 4, 5, 200000),
+ REGULATOR_LINEAR_RANGE(3300000, 6, 7, 300000),
+};
+
+#define RK817_BUCK1_MIN0 500000
+#define RK817_BUCK1_MAX0 1500000
+
+#define RK817_BUCK1_MIN1 1600000
+#define RK817_BUCK1_MAX1 2400000
+
+#define RK817_BUCK3_MAX1 3400000
+
+#define RK817_BUCK1_STP0 12500
+#define RK817_BUCK1_STP1 100000
+
+#define RK817_BUCK1_SEL0 ((RK817_BUCK1_MAX0 - RK817_BUCK1_MIN0) /\
+ RK817_BUCK1_STP0)
+#define RK817_BUCK1_SEL1 ((RK817_BUCK1_MAX1 - RK817_BUCK1_MIN1) /\
+ RK817_BUCK1_STP1)
+
+#define RK817_BUCK3_SEL1 ((RK817_BUCK3_MAX1 - RK817_BUCK1_MIN1) /\
+ RK817_BUCK1_STP1)
+
+#define RK817_BUCK1_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK1_SEL1 + 1)
+#define RK817_BUCK3_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK3_SEL1 + 1)
+
+static const struct regulator_linear_range rk817_buck1_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN0, 0,
+ RK817_BUCK1_SEL0, RK817_BUCK1_STP0),
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1,
+ RK817_BUCK1_SEL_CNT, RK817_BUCK1_STP1),
+};
+
+static const struct regulator_linear_range rk817_buck3_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN0, 0,
+ RK817_BUCK1_SEL0, RK817_BUCK1_STP0),
+ REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1,
+ RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1),
+};
+
+struct rk_regulator_cfg {
+ struct regulator_desc desc;
+ struct regulator_dev rdev;
+};
+
+static int rk8xx_is_enabled_wmsk_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ /* add write mask bit */
+ val |= (rdev->desc->enable_mask & 0xf0);
+ val &= rdev->desc->enable_mask;
+
+ if (rdev->desc->enable_is_inverted) {
+ if (rdev->desc->enable_val)
+ return val != rdev->desc->enable_val;
+ return (val == 0);
+ }
+ if (rdev->desc->enable_val)
+ return val == rdev->desc->enable_val;
+ return val != 0;
+}
+
+static struct regulator_ops rk808_buck1_2_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops rk808_reg_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops rk808_reg_ops_ranges = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops rk808_switch_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_linear_range rk805_buck_1_2_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(712500, 0, 59, 12500),
+ REGULATOR_LINEAR_RANGE(1800000, 60, 62, 200000),
+ REGULATOR_LINEAR_RANGE(2300000, 63, 63, 0),
+};
+
+static const struct regulator_ops rk809_buck5_ops_range = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+};
+
+static const struct regulator_ops rk817_reg_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+};
+
+static const struct regulator_ops rk817_boost_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+};
+
+static const struct regulator_ops rk817_buck_ops_range = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+};
+
+static const struct regulator_ops rk817_switch_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = rk8xx_is_enabled_wmsk_regmap,
+};
+
+static struct rk_regulator_cfg rk805_reg[] = {
+ {{
+ /* .name = "DCDC_REG1", */
+ .supply_name = "vcc1",
+ .ops = &rk808_reg_ops_ranges,
+ .n_voltages = 64,
+ .linear_ranges = rk805_buck_1_2_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges),
+ .vsel_reg = RK805_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK805_DCDC_EN_REG,
+ .enable_mask = BIT(0),
+ }}, {{
+ /* .name = "DCDC_REG2", */
+ .supply_name = "vcc2",
+ .ops = &rk808_reg_ops_ranges,
+ .n_voltages = 64,
+ .linear_ranges = rk805_buck_1_2_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges),
+ .vsel_reg = RK805_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK805_DCDC_EN_REG,
+ .enable_mask = BIT(1),
+ }}, {{
+ /* .name = "DCDC_REG3", */
+ .supply_name = "vcc3",
+ .ops = &rk808_switch_ops,
+ .n_voltages = 1,
+ .enable_reg = RK805_DCDC_EN_REG,
+ .enable_mask = BIT(2),
+ }},
+
+ RK805_DESC(/* "DCDC_REG4", */ "vcc4", 800, 3400, 100,
+ RK805_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK,
+ RK805_DCDC_EN_REG, BIT(3), 0),
+
+ RK805_DESC(/* "LDO_REG1", */ "vcc5", 800, 3400, 100,
+ RK805_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG,
+ BIT(0), 400),
+ RK805_DESC(/* "LDO_REG2", */ "vcc5", 800, 3400, 100,
+ RK805_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG,
+ BIT(1), 400),
+ RK805_DESC(/* "LDO_REG3", */ "vcc6", 800, 3400, 100,
+ RK805_LDO3_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG,
+ BIT(2), 400),
+};
+static_assert(ARRAY_SIZE(rk805_reg) == RK805_NUM_REGULATORS);
+
+static struct rk_regulator_cfg rk808_reg[] = {
+ {{
+ /* .name = "DCDC_REG1", */
+ .supply_name = "vcc1",
+ .ops = &rk808_buck1_2_ops,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK808_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK_VSEL_MASK,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(0),
+ }}, {{
+ /* .name = "DCDC_REG2", */
+ .supply_name = "vcc2",
+ .ops = &rk808_buck1_2_ops,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK808_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK_VSEL_MASK,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(1),
+ }}, {{
+ /* .name = "DCDC_REG3", */
+ .supply_name = "vcc3",
+ .ops = &rk808_switch_ops,
+ .n_voltages = 1,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(2),
+ }}, {{
+ /* .name = "DCDC_REG4", */
+ .supply_name = "vcc4",
+ .ops = &rk808_reg_ops,
+ .min_uV = 1800000,
+ .uV_step = 100000,
+ .n_voltages = 16,
+ .vsel_reg = RK808_BUCK4_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK4_VSEL_MASK,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(3),
+ }}, {{
+ /* .name = "LDO_REG1", */
+ .supply_name = "vcc6",
+ .ops = &rk808_reg_ops,
+ .min_uV = 1800000,
+ .uV_step = 100000,
+ .n_voltages = 17,
+ .vsel_reg = RK808_LDO1_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(0),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG2", */
+ .supply_name = "vcc6",
+ .ops = &rk808_reg_ops,
+ .min_uV = 1800000,
+ .uV_step = 100000,
+ .n_voltages = 17,
+ .vsel_reg = RK808_LDO2_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(1),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG3", */
+ .supply_name = "vcc7",
+ .ops = &rk808_reg_ops_ranges,
+ .n_voltages = 16,
+ .linear_ranges = rk808_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
+ .vsel_reg = RK808_LDO3_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK4_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(2),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG4", */
+ .supply_name = "vcc9",
+ .ops = &rk808_reg_ops,
+ .min_uV = 1800000,
+ .uV_step = 100000,
+ .n_voltages = 17,
+ .vsel_reg = RK808_LDO4_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(3),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG5", */
+ .supply_name = "vcc9",
+ .ops = &rk808_reg_ops,
+ .min_uV = 1800000,
+ .uV_step = 100000,
+ .n_voltages = 17,
+ .vsel_reg = RK808_LDO5_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(4),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG6", */
+ .supply_name = "vcc10",
+ .ops = &rk808_reg_ops,
+ .min_uV = 800000,
+ .uV_step = 100000,
+ .n_voltages = 18,
+ .vsel_reg = RK808_LDO6_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(5),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG7", */
+ .supply_name = "vcc7",
+ .ops = &rk808_reg_ops,
+ .min_uV = 800000,
+ .uV_step = 100000,
+ .n_voltages = 18,
+ .vsel_reg = RK808_LDO7_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(6),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "LDO_REG8", */
+ .supply_name = "vcc11",
+ .ops = &rk808_reg_ops,
+ .min_uV = 1800000,
+ .uV_step = 100000,
+ .n_voltages = 17,
+ .vsel_reg = RK808_LDO8_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(7),
+ .off_on_delay = 400,
+ }}, {{
+ /* .name = "SWITCH_REG1", */
+ .supply_name = "vcc8",
+ .ops = &rk808_switch_ops,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(5),
+ }}, {{
+ /* .name = "SWITCH_REG2", */
+ .supply_name = "vcc12",
+ .ops = &rk808_switch_ops,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(6),
+ }},
+};
+static_assert(ARRAY_SIZE(rk808_reg) == RK808_NUM_REGULATORS);
+
+static struct rk_regulator_cfg rk809_reg[] = {
+ {{
+ /* .name = "DCDC_REG1", */
+ .supply_name = "vcc1",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC1),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+ }}, {{
+ /* .name = "DCDC_REG2", */
+ .supply_name = "vcc2",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC2),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+ }}, {{
+ /* .name = "DCDC_REG3", */
+ .supply_name = "vcc3",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK3_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC3),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+ }}, {{
+ /* .name = "DCDC_REG4", */
+ .supply_name = "vcc4",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK3_SEL_CNT + 1,
+ .linear_ranges = rk817_buck3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck3_voltage_ranges),
+ .vsel_reg = RK817_BUCK4_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC4),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+ }},
+ RK817_DESC(/* "LDO_REG1", */ "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(/* "LDO_REG2", */ "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(/* "LDO_REG3", */ "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(/* "LDO_REG4", */ "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(/* "LDO_REG5", */ "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(/* "LDO_REG6", */ "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(/* "LDO_REG7", */ "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(/* "LDO_REG8", */ "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(/* "LDO_REG9", */ "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(3), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ {{
+ /* .name = "DCDC_REG5", */
+ .supply_name = "vcc9",
+ .ops = &rk809_buck5_ops_range,
+ .n_voltages = RK809_BUCK5_SEL_CNT,
+ .linear_ranges = rk809_buck5_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk809_buck5_voltage_ranges),
+ .vsel_reg = RK809_BUCK5_CONFIG(0),
+ .vsel_mask = RK809_BUCK5_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(3),
+ .enable_mask = ENABLE_MASK(1),
+ .enable_val = ENABLE_MASK(1),
+ .disable_val = DISABLE_VAL(1),
+ }},
+ RK817_DESC_SWITCH(/* "SWITCH_REG1", */ "vcc9",
+ RK817_POWER_EN_REG(3), ENABLE_MASK(2), DISABLE_VAL(2)),
+ RK817_DESC_SWITCH(/* "SWITCH_REG2", */ "vcc8",
+ RK817_POWER_EN_REG(3), ENABLE_MASK(3), DISABLE_VAL(3)),
+};
+static_assert(ARRAY_SIZE(rk809_reg) == RK809_NUM_REGULATORS);
+
+static struct rk_regulator_cfg rk817_reg[] = {
+ {{
+ /* .name = "DCDC_REG1", */
+ .supply_name = "vcc1",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC1),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC1),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC1),
+ }}, {{
+ /* .name = "DCDC_REG2", */
+ .supply_name = "vcc2",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC2),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC2),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC2),
+ }}, {{
+ /* .name = "DCDC_REG3", */
+ .supply_name = "vcc3",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK1_SEL_CNT + 1,
+ .linear_ranges = rk817_buck1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges),
+ .vsel_reg = RK817_BUCK3_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC3),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC3),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC3),
+ }}, {{
+ /* .name = "DCDC_REG4", */
+ .supply_name = "vcc4",
+ .ops = &rk817_buck_ops_range,
+ .n_voltages = RK817_BUCK3_SEL_CNT + 1,
+ .linear_ranges = rk817_buck3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk817_buck3_voltage_ranges),
+ .vsel_reg = RK817_BUCK4_ON_VSEL_REG,
+ .vsel_mask = RK817_BUCK_VSEL_MASK,
+ .enable_reg = RK817_POWER_EN_REG(0),
+ .enable_mask = ENABLE_MASK(RK817_ID_DCDC4),
+ .enable_val = ENABLE_MASK(RK817_ID_DCDC4),
+ .disable_val = DISABLE_VAL(RK817_ID_DCDC4),
+ }},
+ RK817_DESC(/* "LDO_REG1", */ "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(/* "LDO_REG2", */ "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(/* "LDO_REG3", */ "vcc5", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(/* "LDO_REG4", */ "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(1), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(/* "LDO_REG5", */ "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_DESC(/* "LDO_REG6", */ "vcc6", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC(/* "LDO_REG7", */ "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(2),
+ DISABLE_VAL(2), 400),
+ RK817_DESC(/* "LDO_REG8", */ "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(2), ENABLE_MASK(3),
+ DISABLE_VAL(3), 400),
+ RK817_DESC(/* "LDO_REG9", */ "vcc7", 600, 3400, 25,
+ RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK,
+ RK817_POWER_EN_REG(3), ENABLE_MASK(0),
+ DISABLE_VAL(0), 400),
+ RK817_BOOST_DESC(/* "BOOST", */ "vcc8", 4700, 5400, 100,
+ RK817_BOOST_OTG_CFG, RK817_BOOST_VSEL_MASK,
+ RK817_POWER_EN_REG(3), ENABLE_MASK(1), ENABLE_MASK(1),
+ DISABLE_VAL(1), 400),
+ RK817_DESC_SWITCH(/* "OTG_SWITCH", */ "vcc9",
+ RK817_POWER_EN_REG(3), ENABLE_MASK(2), DISABLE_VAL(2)),
+};
+static_assert(ARRAY_SIZE(rk817_reg) == RK817_NUM_REGULATORS);
+
+static struct rk_regulator_cfg rk818_reg[] = {
+ {{
+ /* .name = "DCDC_REG1", */
+ .supply_name = "vcc1",
+ .ops = &rk808_reg_ops,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK818_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(0),
+ }}, {{
+ /* .name = "DCDC_REG2", */
+ .supply_name = "vcc2",
+ .ops = &rk808_reg_ops,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK818_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(1),
+ }}, {{
+ /* .name = "DCDC_REG3", */
+ .supply_name = "vcc3",
+ .ops = &rk808_switch_ops,
+ .n_voltages = 1,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(2),
+ }},
+ RK8XX_DESC(/* "DCDC_REG4", */ "vcc4", 1800, 3600, 100,
+ RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(3), 0),
+ RK8XX_DESC(/* "DCDC_BOOST", */ "boost", 4700, 5400, 100,
+ RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(4), 0),
+ RK8XX_DESC(/* "LDO_REG1", */ "vcc6", 1800, 3400, 100,
+ RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(0), 400),
+ RK8XX_DESC(/* "LDO_REG2", */ "vcc6", 1800, 3400, 100,
+ RK818_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(1), 400),
+ {{
+ /* .name = "LDO_REG3", */
+ .supply_name = "vcc7",
+ .ops = &rk808_reg_ops_ranges,
+ .n_voltages = 16,
+ .linear_ranges = rk808_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
+ .vsel_reg = RK818_LDO3_ON_VSEL_REG,
+ .vsel_mask = RK818_LDO3_ON_VSEL_MASK,
+ .enable_reg = RK818_LDO_EN_REG,
+ .enable_mask = BIT(2),
+ .off_on_delay = 400,
+ }},
+ RK8XX_DESC(/* "LDO_REG4", */ "vcc8", 1800, 3400, 100,
+ RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(3), 400),
+ RK8XX_DESC(/* "LDO_REG5", */ "vcc7", 1800, 3400, 100,
+ RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(4), 400),
+ RK8XX_DESC(/* "LDO_REG6", */ "vcc8", 800, 2500, 100,
+ RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(5), 400),
+ RK8XX_DESC(/* "LDO_REG7", */ "vcc7", 800, 2500, 100,
+ RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(6), 400),
+ RK8XX_DESC(/* "LDO_REG8", */ "vcc8", 1800, 3400, 100,
+ RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(7), 400),
+ RK8XX_DESC(/* "LDO_REG9", */ "vcc9", 1800, 3400, 100,
+ RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(5), 400),
+ RK8XX_DESC_SWITCH(/* "SWITCH_REG", */ "vcc9",
+ RK818_DCDC_EN_REG, BIT(6)),
+ RK8XX_DESC_SWITCH(/* "HDMI_SWITCH", */ "h_5v",
+ RK818_H5V_EN_REG, BIT(0)),
+ RK8XX_DESC_SWITCH(/* "OTG_SWITCH", */ "usb",
+ RK818_DCDC_EN_REG, BIT(7)),
+};
+static_assert(ARRAY_SIZE(rk818_reg) == RK818_NUM_REGULATORS);
+
+static int rk808_regulator_register(struct rk808 *rk808, int id,
+ struct of_regulator_match *match,
+ struct rk_regulator_cfg *cfg)
+{
+ struct device *dev = &rk808->i2c->dev;
+ int ret;
+
+ if (!match->of_node) {
+ dev_dbg(dev, "Skip missing DTB regulator %s", match->name);
+ return 0;
+ }
+
+ cfg->rdev.desc = &cfg->desc;
+ cfg->rdev.dev = dev;
+ cfg->rdev.regmap = rk808->regmap;
+
+ ret = of_regulator_register(&cfg->rdev, match->of_node);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register %s regulator\n",
+ match->name);
+
+ dev_dbg(dev, "registered %s\n", match->name);
+
+ return 0;
+}
+
+#define MATCH(variant, _name, _id) [RK##variant##_ID_##_id] = \
+ { .name = #_name, .desc = &rk##variant##_reg[RK##variant##_ID_##_id].desc }
+
+static struct of_regulator_match rk805_reg_matches[] = {
+ MATCH(805, DCDC_REG1, DCDC1),
+ MATCH(805, DCDC_REG2, DCDC2),
+ MATCH(805, DCDC_REG3, DCDC3),
+ MATCH(805, DCDC_REG4, DCDC4),
+ MATCH(805, LDO_REG1, LDO1),
+ MATCH(805, LDO_REG2, LDO2),
+ MATCH(805, LDO_REG3, LDO3),
+};
+static_assert(ARRAY_SIZE(rk805_reg_matches) == RK805_NUM_REGULATORS);
+
+static struct of_regulator_match rk808_reg_matches[] = {
+ MATCH(808, DCDC_REG1, DCDC1),
+ MATCH(808, DCDC_REG2, DCDC2),
+ MATCH(808, DCDC_REG3, DCDC3),
+ MATCH(808, DCDC_REG4, DCDC4),
+ MATCH(808, LDO_REG1, LDO1),
+ MATCH(808, LDO_REG2, LDO2),
+ MATCH(808, LDO_REG3, LDO3),
+ MATCH(808, LDO_REG4, LDO4),
+ MATCH(808, LDO_REG5, LDO5),
+ MATCH(808, LDO_REG6, LDO6),
+ MATCH(808, LDO_REG7, LDO7),
+ MATCH(808, LDO_REG8, LDO8),
+ MATCH(808, SWITCH_REG1, SWITCH1),
+ MATCH(808, SWITCH_REG2, SWITCH2),
+};
+static_assert(ARRAY_SIZE(rk808_reg_matches) == RK808_NUM_REGULATORS);
+
+static struct of_regulator_match rk809_reg_matches[] = {
+ MATCH(809, DCDC_REG1, DCDC1),
+ MATCH(809, DCDC_REG2, DCDC2),
+ MATCH(809, DCDC_REG3, DCDC3),
+ MATCH(809, DCDC_REG4, DCDC4),
+ MATCH(809, LDO_REG1, LDO1),
+ MATCH(809, LDO_REG2, LDO2),
+ MATCH(809, LDO_REG3, LDO3),
+ MATCH(809, LDO_REG4, LDO4),
+ MATCH(809, LDO_REG5, LDO5),
+ MATCH(809, LDO_REG6, LDO6),
+ MATCH(809, LDO_REG7, LDO7),
+ MATCH(809, LDO_REG8, LDO8),
+ MATCH(809, LDO_REG9, LDO9),
+ MATCH(809, DCDC_REG5, DCDC5),
+ MATCH(809, SWITCH_REG1, SW1),
+ MATCH(809, SWITCH_REG2, SW2),
+};
+static_assert(ARRAY_SIZE(rk809_reg_matches) == RK809_NUM_REGULATORS);
+
+static struct of_regulator_match rk817_reg_matches[] = {
+ MATCH(817, DCDC_REG1, DCDC1),
+ MATCH(817, DCDC_REG2, DCDC2),
+ MATCH(817, DCDC_REG3, DCDC3),
+ MATCH(817, DCDC_REG4, DCDC4),
+ MATCH(817, LDO_REG1, LDO1),
+ MATCH(817, LDO_REG2, LDO2),
+ MATCH(817, LDO_REG3, LDO3),
+ MATCH(817, LDO_REG4, LDO4),
+ MATCH(817, LDO_REG5, LDO5),
+ MATCH(817, LDO_REG6, LDO6),
+ MATCH(817, LDO_REG7, LDO7),
+ MATCH(817, LDO_REG8, LDO8),
+ MATCH(817, LDO_REG9, LDO9),
+ MATCH(817, BOOST, BOOST),
+ MATCH(817, OTG_SWITCH, BOOST_OTG_SW),
+};
+static_assert(ARRAY_SIZE(rk817_reg_matches) == RK817_NUM_REGULATORS);
+
+static struct of_regulator_match rk818_reg_matches[] = {
+ MATCH(818, DCDC_REG1, DCDC1),
+ MATCH(818, DCDC_REG2, DCDC2),
+ MATCH(818, DCDC_REG3, DCDC3),
+ MATCH(818, DCDC_REG4, DCDC4),
+ MATCH(818, DCDC_BOOST, BOOST),
+ MATCH(818, LDO_REG1, LDO1),
+ MATCH(818, LDO_REG2, LDO2),
+ MATCH(818, LDO_REG3, LDO3),
+ MATCH(818, LDO_REG4, LDO4),
+ MATCH(818, LDO_REG5, LDO5),
+ MATCH(818, LDO_REG6, LDO6),
+ MATCH(818, LDO_REG7, LDO7),
+ MATCH(818, LDO_REG8, LDO8),
+ MATCH(818, LDO_REG9, LDO9),
+ MATCH(818, SWITCH_REG, SWITCH),
+ MATCH(818, HDMI_SWITCH, HDMI_SWITCH),
+ MATCH(818, OTG_SWITCH, OTG_SWITCH),
+};
+static_assert(ARRAY_SIZE(rk818_reg_matches) == RK818_NUM_REGULATORS);
+
+static int rk808_regulator_dt_parse(struct device *dev,
+ struct of_regulator_match *matches,
+ int nregulators)
+{
+ struct device_node *np = dev->of_node;
+
+ np = of_get_child_by_name(np, "regulators");
+ if (!np)
+ return -ENOENT;
+
+ return of_regulator_match(dev, np, matches, nregulators);
+}
+
+static int rk808_regulator_probe(struct device *dev)
+{
+ struct rk808 *rk808 = dev->parent->priv;
+ struct rk_regulator_cfg *regulators;
+ struct of_regulator_match *matches;
+ int ret, i, nregulators;
+
+ switch (rk808->variant) {
+ case RK805_ID:
+ regulators = rk805_reg;
+ matches = rk805_reg_matches;
+ nregulators = RK805_NUM_REGULATORS;
+ break;
+ case RK808_ID:
+ regulators = rk808_reg;
+ matches = rk808_reg_matches;
+ nregulators = RK809_NUM_REGULATORS;
+ break;
+ case RK809_ID:
+ regulators = rk809_reg;
+ matches = rk809_reg_matches;
+ nregulators = RK809_NUM_REGULATORS;
+ break;
+ case RK817_ID:
+ regulators = rk817_reg;
+ matches = rk817_reg_matches;
+ nregulators = RK817_NUM_REGULATORS;
+ break;
+ case RK818_ID:
+ regulators = rk818_reg;
+ matches = rk818_reg_matches;
+ nregulators = RK818_NUM_REGULATORS;
+ break;
+ default:
+ dev_err(dev, "unsupported RK8XX ID %lu\n", rk808->variant);
+ return -EINVAL;
+ }
+
+ ret = rk808_regulator_dt_parse(&rk808->i2c->dev, matches, nregulators);
+ if (ret < 0)
+ return ret;
+
+ /* Instantiate the regulators */
+ for (i = 0; i < nregulators; i++) {
+ ret = rk808_regulator_register(rk808, i, &matches[i],
+ &regulators[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct driver rk808_regulator_driver = {
+ .name = "rk808-regulator",
+ .probe = rk808_regulator_probe,
+};
+device_platform_driver(rk808_regulator_driver);
+
+MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
+MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rk808-regulator");
diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
new file mode 100644
index 0000000000..6f22fa6420
--- /dev/null
+++ b/drivers/regulator/scmi-regulator.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// System Control and Management Interface (SCMI) based regulator driver
+//
+// Copyright (C) 2020-2021 ARM Ltd.
+//
+// Implements a regulator driver on top of the SCMI Voltage Protocol.
+//
+// The ARM SCMI Protocol aims in general to hide as much as possible all the
+// underlying operational details while providing an abstracted interface for
+// its users to operate upon: as a consequence the resulting operational
+// capabilities and configurability of this regulator device are much more
+// limited than the ones usually available on a standard physical regulator.
+//
+// The supported SCMI regulator ops are restricted to the bare minimum:
+//
+// - 'status_ops': enable/disable/is_enabled
+// - 'voltage_ops': get_voltage_sel/set_voltage_sel
+// list_voltage/map_voltage
+//
+// Each SCMI regulator instance is associated, through the means of a proper DT
+// entry description, to a specific SCMI Voltage Domain.
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <common.h>
+#include <of.h>
+#include <regulator.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/scmi_protocol.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+static const struct scmi_voltage_proto_ops *voltage_ops;
+
+struct scmi_reg_desc {
+ struct regulator_desc desc;
+ const char *name;
+ const char *supply_name;
+};
+
+struct scmi_regulator {
+ u32 id;
+ struct scmi_device *sdev;
+ struct scmi_protocol_handle *ph;
+ struct regulator_dev rdev;
+ struct device_node *of_node;
+ struct scmi_reg_desc sdesc;
+};
+
+struct scmi_regulator_info {
+ int num_doms;
+ struct scmi_regulator **sregv;
+};
+
+static inline struct scmi_regulator *to_scmi_regulator(struct regulator_dev *rdev)
+{
+ return container_of(rdev, struct scmi_regulator, rdev);
+}
+
+static int scmi_reg_enable(struct regulator_dev *rdev)
+{
+ struct scmi_regulator *sreg = to_scmi_regulator(rdev);
+
+ return voltage_ops->config_set(sreg->ph, sreg->id,
+ SCMI_VOLTAGE_ARCH_STATE_ON);
+}
+
+static int scmi_reg_disable(struct regulator_dev *rdev)
+{
+ struct scmi_regulator *sreg = to_scmi_regulator(rdev);
+
+ return voltage_ops->config_set(sreg->ph, sreg->id,
+ SCMI_VOLTAGE_ARCH_STATE_OFF);
+}
+
+static int scmi_reg_is_enabled(struct regulator_dev *rdev)
+{
+ int ret;
+ u32 config;
+ struct scmi_regulator *sreg = to_scmi_regulator(rdev);
+ struct scmi_reg_desc *sdesc = &sreg->sdesc;
+
+ ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);
+ if (ret) {
+ dev_err(&sreg->sdev->dev,
+ "Error %d reading regulator %s status.\n",
+ ret, sdesc->name);
+ return ret;
+ }
+
+ return config & SCMI_VOLTAGE_ARCH_STATE_ON;
+}
+
+static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev)
+{
+ int ret;
+ s32 volt_uV;
+ struct scmi_regulator *sreg = to_scmi_regulator(rdev);
+
+ ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);
+ if (ret)
+ return ret;
+
+ return sreg->sdesc.desc.ops->map_voltage(rdev, volt_uV, volt_uV);
+}
+
+static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ s32 volt_uV;
+ struct scmi_regulator *sreg = to_scmi_regulator(rdev);
+
+ volt_uV = sreg->sdesc.desc.ops->list_voltage(rdev, selector);
+ if (volt_uV <= 0)
+ return -EINVAL;
+
+ return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);
+}
+
+static const struct regulator_ops scmi_reg_fixed_ops = {
+ .enable = scmi_reg_enable,
+ .disable = scmi_reg_disable,
+ .is_enabled = scmi_reg_is_enabled,
+};
+
+static const struct regulator_ops scmi_reg_linear_ops = {
+ .enable = scmi_reg_enable,
+ .disable = scmi_reg_disable,
+ .is_enabled = scmi_reg_is_enabled,
+ .get_voltage_sel = scmi_reg_get_voltage_sel,
+ .set_voltage_sel = scmi_reg_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+};
+
+static const struct regulator_ops scmi_reg_discrete_ops = {
+ .enable = scmi_reg_enable,
+ .disable = scmi_reg_disable,
+ .is_enabled = scmi_reg_is_enabled,
+ .get_voltage_sel = scmi_reg_get_voltage_sel,
+ .set_voltage_sel = scmi_reg_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+};
+
+static int
+scmi_config_linear_regulator_mappings(struct scmi_regulator *sreg,
+ const struct scmi_voltage_info *vinfo)
+{
+ struct regulator_desc *desc = &sreg->sdesc.desc;
+ s32 delta_uV;
+
+ /*
+ * Note that SCMI voltage domains describable by linear ranges
+ * (segments) {low, high, step} are guaranteed to come in one single
+ * triplet by the SCMI Voltage Domain protocol support itself.
+ */
+
+ delta_uV = (vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH] -
+ vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW]);
+
+ /* Rule out buggy negative-intervals answers from fw */
+ if (delta_uV < 0) {
+ dev_err(&sreg->sdev->dev,
+ "Invalid volt-range %d-%duV for domain %d\n",
+ vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW],
+ vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH],
+ sreg->id);
+ return -EINVAL;
+ }
+
+ if (!delta_uV) {
+ /* Just one fixed voltage exposed by SCMI */
+ desc->fixed_uV =
+ vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
+ desc->n_voltages = 1;
+ desc->ops = &scmi_reg_fixed_ops;
+ } else {
+ /* One simple linear mapping. */
+ desc->min_uV =
+ vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
+ desc->uV_step =
+ vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_STEP];
+ desc->linear_min_sel = 0;
+ desc->n_voltages = (delta_uV / desc->uV_step) + 1;
+ desc->ops = &scmi_reg_linear_ops;
+ }
+
+ return 0;
+}
+
+static int
+scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg,
+ const struct scmi_voltage_info *vinfo)
+{
+ struct regulator_desc *desc = &sreg->sdesc.desc;
+
+ /* Discrete non linear levels are mapped to volt_table */
+ desc->n_voltages = vinfo->num_levels;
+
+ if (desc->n_voltages > 1) {
+ desc->volt_table = (const unsigned int *)vinfo->levels_uv;
+ desc->ops = &scmi_reg_discrete_ops;
+ } else {
+ desc->fixed_uV = vinfo->levels_uv[0];
+ desc->ops = &scmi_reg_fixed_ops;
+ }
+
+ return 0;
+}
+
+static int scmi_regulator_common_init(struct scmi_regulator *sreg)
+{
+ int ret;
+ struct device *dev = &sreg->sdev->dev;
+ const struct scmi_voltage_info *vinfo;
+ struct scmi_reg_desc *sdesc = &sreg->sdesc;
+
+ vinfo = voltage_ops->info_get(sreg->ph, sreg->id);
+ if (!vinfo) {
+ dev_warn(dev, "Failure to get voltage domain %d\n",
+ sreg->id);
+ return -ENODEV;
+ }
+
+ /*
+ * Regulator framework does not fully support negative voltages
+ * so we discard any voltage domain reported as supporting negative
+ * voltages: as a consequence each levels_uv entry is guaranteed to
+ * be non-negative from here on.
+ */
+ if (vinfo->negative_volts_allowed) {
+ dev_warn(dev, "Negative voltages NOT supported...skip %pOF\n",
+ sreg->of_node);
+ return -EOPNOTSUPP;
+ }
+
+ sdesc->name = basprintf("%s", vinfo->name);
+ if (!sdesc->name)
+ return -ENOMEM;
+
+ if (vinfo->segmented)
+ ret = scmi_config_linear_regulator_mappings(sreg, vinfo);
+ else
+ ret = scmi_config_discrete_regulator_mappings(sreg, vinfo);
+
+ return ret;
+}
+
+static int process_scmi_regulator_of_node(struct scmi_device *sdev,
+ struct scmi_protocol_handle *ph,
+ struct device_node *np,
+ struct scmi_regulator_info *rinfo)
+{
+ u32 dom, ret;
+
+ ret = of_property_read_u32(np, "reg", &dom);
+ if (ret)
+ return ret;
+
+ if (dom >= rinfo->num_doms)
+ return -ENODEV;
+
+ if (rinfo->sregv[dom]) {
+ dev_err(&sdev->dev,
+ "SCMI Voltage Domain %d already in use. Skipping: %pOF\n",
+ dom, np);
+ return -EINVAL;
+ }
+
+ rinfo->sregv[dom] = kzalloc(sizeof(struct scmi_regulator), GFP_KERNEL);
+ if (!rinfo->sregv[dom])
+ return -ENOMEM;
+
+ rinfo->sregv[dom]->id = dom;
+ rinfo->sregv[dom]->sdev = sdev;
+ rinfo->sregv[dom]->ph = ph;
+
+ /* get hold of good nodes */
+ rinfo->sregv[dom]->of_node = np;
+
+ dev_dbg(&sdev->dev,
+ "Found SCMI Regulator entry -- OF node [%d] -> %pOF\n",
+ dom, np);
+
+ return 0;
+}
+
+static int scmi_regulator_probe(struct scmi_device *sdev)
+{
+ int d, ret, num_doms;
+ struct device_node *np, *child;
+ const struct scmi_handle *handle = sdev->handle;
+ struct scmi_regulator_info *rinfo;
+ struct scmi_protocol_handle *ph;
+ struct scmi_reg_desc *sdesc;
+
+ if (!handle)
+ return -ENODEV;
+
+ voltage_ops = handle->dev_protocol_get(sdev, SCMI_PROTOCOL_VOLTAGE, &ph);
+ if (IS_ERR(voltage_ops))
+ return PTR_ERR(voltage_ops);
+
+ num_doms = voltage_ops->num_domains_get(ph);
+ if (num_doms <= 0) {
+ if (!num_doms) {
+ dev_err(&sdev->dev,
+ "number of voltage domains invalid\n");
+ num_doms = -EINVAL;
+ } else {
+ dev_err(&sdev->dev,
+ "failed to get voltage domains - err:%d\n",
+ num_doms);
+ }
+
+ return num_doms;
+ }
+
+ rinfo = kzalloc(sizeof(*rinfo), GFP_KERNEL);
+ if (!rinfo)
+ return -ENOMEM;
+
+ /* Allocate pointers array for all possible domains */
+ rinfo->sregv = kcalloc(num_doms, sizeof(void *), GFP_KERNEL);
+ if (!rinfo->sregv)
+ return -ENOMEM;
+
+ rinfo->num_doms = num_doms;
+
+ /*
+ * Start collecting into rinfo->sregv possibly good SCMI Regulators as
+ * described by a well-formed DT entry and associated with an existing
+ * plausible SCMI Voltage Domain number, all belonging to this SCMI
+ * platform instance node (handle->dev->of_node).
+ */
+ np = of_find_node_by_name(handle->dev->of_node, "regulators");
+ for_each_child_of_node(np, child) {
+ ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
+ /* abort on any mem issue */
+ if (ret == -ENOMEM)
+ return ret;
+ }
+
+ /*
+ * Register a regulator for each valid regulator-DT-entry that we
+ * can successfully reach via SCMI and has a valid associated voltage
+ * domain.
+ */
+ for (d = 0; d < num_doms; d++) {
+ struct scmi_regulator *sreg = rinfo->sregv[d];
+
+ /* Skip empty slots */
+ if (!sreg)
+ continue;
+
+ sdesc = &sreg->sdesc;
+
+ ret = scmi_regulator_common_init(sreg);
+ /* Skip invalid voltage domains */
+ if (ret)
+ continue;
+
+ sreg->rdev.desc = &sdesc->desc;
+ sreg->rdev.dev = &sdev->dev;
+
+ ret = of_regulator_register(&sreg->rdev, sreg->of_node);
+ if (ret)
+ continue;
+
+ dev_dbg(&sdev->dev,
+ "Regulator %s registered for domain [%d]\n",
+ sreg->sdesc.name, sreg->id);
+ }
+
+ return 0;
+}
+
+static const struct scmi_device_id scmi_regulator_id_table[] = {
+ { SCMI_PROTOCOL_VOLTAGE, "regulator" },
+ { },
+};
+
+static struct scmi_driver scmi_drv = {
+ .name = "scmi-regulator",
+ .probe = scmi_regulator_probe,
+ .id_table = scmi_regulator_id_table,
+};
+core_scmi_driver(scmi_drv);
+
+MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c
new file mode 100644
index 0000000000..ca03529b7f
--- /dev/null
+++ b/drivers/regulator/stm32-pwr.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) STMicroelectronics 2019
+// Authors: Gabriel Fernandez <gabriel.fernandez@st.com>
+// Pascal Paillet <p.paillet@st.com>.
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/iopoll.h>
+#include <of.h>
+#include <regulator.h>
+
+/*
+ * Registers description
+ */
+#define REG_PWR_CR3 0x0C
+
+#define USB_3_3_EN BIT(24)
+#define USB_3_3_RDY BIT(26)
+#define REG_1_8_EN BIT(28)
+#define REG_1_8_RDY BIT(29)
+#define REG_1_1_EN BIT(30)
+#define REG_1_1_RDY BIT(31)
+
+/* list of supported regulators */
+enum {
+ PWR_REG11,
+ PWR_REG18,
+ PWR_USB33,
+ STM32PWR_REG_NUM_REGS
+};
+
+struct stm32_pwr_desc {
+ struct regulator_desc desc;
+ const char *name;
+ const char *supply_name;
+};
+
+static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = {
+ [PWR_REG11] = REG_1_1_RDY,
+ [PWR_REG18] = REG_1_8_RDY,
+ [PWR_USB33] = USB_3_3_RDY,
+};
+
+struct stm32_pwr_reg {
+ void __iomem *base;
+ u32 ready_mask;
+ struct regulator_dev rdev;
+ struct regulator *supply;
+};
+
+static inline struct stm32_pwr_reg *to_pwr_reg(struct regulator_dev *rdev)
+{
+ return container_of(rdev, struct stm32_pwr_reg, rdev);
+}
+
+static inline struct stm32_pwr_desc *to_desc(struct regulator_dev *rdev)
+{
+ return container_of(rdev->desc, struct stm32_pwr_desc, desc);
+}
+
+static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+
+ return (val & priv->ready_mask);
+}
+
+static int stm32_pwr_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+
+ return (val & rdev->desc->enable_mask);
+}
+
+static int stm32_pwr_reg_enable(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ struct stm32_pwr_desc *desc = to_desc(rdev);
+ int ret;
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+ val |= rdev->desc->enable_mask;
+ writel(val, priv->base + REG_PWR_CR3);
+
+ /* use an arbitrary timeout of 20ms */
+ ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val,
+ 20 * USEC_PER_MSEC);
+ if (ret)
+ dev_err(rdev->dev, "%s: regulator enable timed out!\n",
+ desc->name);
+
+ return ret;
+}
+
+static int stm32_pwr_reg_disable(struct regulator_dev *rdev)
+{
+ struct stm32_pwr_reg *priv = to_pwr_reg(rdev);
+ struct stm32_pwr_desc *desc = to_desc(rdev);
+ int ret;
+ u32 val;
+
+ val = readl(priv->base + REG_PWR_CR3);
+ val &= ~rdev->desc->enable_mask;
+ writel(val, priv->base + REG_PWR_CR3);
+
+ /* use an arbitrary timeout of 20ms */
+ ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val,
+ 20 * USEC_PER_MSEC);
+ if (ret)
+ dev_err(rdev->dev, "%s: regulator disable timed out!\n",
+ desc->name);
+
+ return ret;
+}
+
+static const struct regulator_ops stm32_pwr_reg_ops = {
+ .enable = stm32_pwr_reg_enable,
+ .disable = stm32_pwr_reg_disable,
+ .is_enabled = stm32_pwr_reg_is_enabled,
+};
+
+#define PWR_REG(_id, _name, _volt, _en, _supply) \
+ [_id] = { { \
+ .n_voltages = 1, \
+ .ops = &stm32_pwr_reg_ops, \
+ .min_uV = _volt, \
+ .enable_mask = _en, \
+ }, .name = _name, .supply_name = _supply, }
+
+static const struct stm32_pwr_desc stm32_pwr_desc[] = {
+ PWR_REG(PWR_REG11, "reg11", 1100000, REG_1_1_EN, "vdd"),
+ PWR_REG(PWR_REG18, "reg18", 1800000, REG_1_8_EN, "vdd"),
+ PWR_REG(PWR_USB33, "usb33", 3300000, USB_3_3_EN, "vdd_3v3_usbfs"),
+};
+
+static int stm32_pwr_regulator_probe(struct device *dev)
+{
+ struct stm32_pwr_reg *priv;
+ struct device_node *child;
+ struct resource *iores;
+ int i, ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ for_each_child_of_node(dev->of_node, child) {
+ const struct stm32_pwr_desc *desc = NULL;
+
+ for (i = 0; i < STM32PWR_REG_NUM_REGS; i++) {
+ const char *name;
+
+ name = of_get_property(child, "regulator-name", NULL);
+ if (name && strcmp(stm32_pwr_desc[i].name, name)) {
+ desc = &stm32_pwr_desc[i];
+ break;
+ }
+ }
+
+ if (!desc) {
+ dev_warn(dev, "Skipping unknown child node %s\n",
+ child->name);
+ continue;
+ }
+
+ priv = xzalloc(sizeof(*priv));
+ priv->base = IOMEM(iores->start);
+ priv->ready_mask = ready_mask_table[i];
+
+ priv->rdev.desc = &desc->desc;
+ priv->rdev.dev = dev;
+
+ priv->supply = regulator_get(dev, desc->supply_name);
+ if (IS_ERR(priv->supply)) {
+ ret = PTR_ERR(priv->supply);
+ goto release_region;
+ }
+
+ ret = of_regulator_register(&priv->rdev, child);
+ if (ret) {
+ dev_err(dev, "%s: Failed to register regulator: %d\n",
+ desc->name, ret);
+ goto release_region;
+ }
+
+ regulator_enable(priv->supply);
+ }
+
+ return 0;
+
+release_region:
+ release_region(iores);
+
+ return ret;
+}
+
+static const struct of_device_id stm32_pwr_of_match[] = {
+ { .compatible = "st,stm32mp1,pwr-reg", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_pwr_of_match);
+
+static struct driver stm32_pwr_driver = {
+ .probe = stm32_pwr_regulator_probe,
+ .name = "stm32-pwr-regulator",
+ .of_compatible = stm32_pwr_of_match,
+};
+device_platform_driver(stm32_pwr_driver);
+
+MODULE_DESCRIPTION("STM32MP1 PWR voltage regulator driver");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 0000000000..18cf53e735
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ */
+
+#include <common.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <of.h>
+#include <io.h>
+#include <regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR 0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS GENMASK(6, 4)
+#define STM32_VRR BIT(3)
+#define STM32_HIZ BIT(1)
+#define STM32_ENVR BIT(0)
+
+#define STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS 10
+
+struct stm32_vrefbuf {
+ void __iomem *base;
+ struct clk *clk;
+ struct device *dev;
+ struct regulator_dev rdev;
+};
+
+struct stm32_vrefbuf_desc {
+ struct regulator_desc desc;
+ const char *supply_name;
+};
+
+static inline struct stm32_vrefbuf *to_stm32_vrefbuf(struct regulator_dev *rdev)
+{
+ return container_of(rdev, struct stm32_vrefbuf, rdev);
+}
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+ /* Matches resp. VRS = 000b, 001b, 010b, 011b */
+ 2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+ struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev);
+ u32 val;
+ int ret;
+
+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+ val = (val & ~STM32_HIZ) | STM32_ENVR;
+ writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+ /*
+ * Vrefbuf startup time depends on external capacitor: wait here for
+ * VRR to be set. That means output has reached expected value.
+ * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+ * arbitrary timeout.
+ */
+ ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+ val & STM32_VRR, 10000);
+ if (ret) {
+ dev_err(priv->dev, "stm32 vrefbuf timed out!\n");
+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+ val = (val & ~STM32_ENVR) | STM32_HIZ;
+ writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+ }
+
+ return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+ struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev);
+ u32 val;
+
+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+ val &= ~STM32_ENVR;
+ writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+ return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+ struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev);
+ int ret;
+
+ ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+
+ return ret;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned sel)
+{
+ struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev);
+ u32 val;
+
+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+ val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+ writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+ return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct stm32_vrefbuf *priv = to_stm32_vrefbuf(rdev);
+ u32 val;
+ int ret;
+
+ val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+ ret = FIELD_GET(STM32_VRS, val);
+
+ return ret;
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+ .enable = stm32_vrefbuf_enable,
+ .disable = stm32_vrefbuf_disable,
+ .is_enabled = stm32_vrefbuf_is_enabled,
+ .get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+ .set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_table,
+};
+
+static const struct stm32_vrefbuf_desc stm32_vrefbuf_regu = {
+ .desc = {
+ .volt_table = stm32_vrefbuf_voltages,
+ .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+ .ops = &stm32_vrefbuf_volt_ops,
+ .off_on_delay = 1000,
+ },
+ .supply_name = "vdda",
+};
+
+static int stm32_vrefbuf_probe(struct device *dev)
+{
+ struct stm32_vrefbuf *priv;
+ struct regulator_dev *rdev;
+ struct regulator *supply;
+ int ret;
+
+ supply = regulator_get(dev, stm32_vrefbuf_regu.supply_name);
+ if (IS_ERR(supply))
+ return PTR_ERR(supply);
+
+ priv = xzalloc(sizeof(*priv));
+ priv->dev = dev;
+
+ priv->base = dev_request_mem_region(dev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->clk = clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ ret = clk_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "clk enable failed with error %d\n", ret);
+ return ret;
+ }
+
+ rdev = &priv->rdev;
+
+ rdev->dev = dev;
+ rdev->desc = &stm32_vrefbuf_regu.desc;
+
+ ret = of_regulator_register(rdev, dev->of_node);
+ if (ret) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "register failed with error %d\n", ret);
+ goto err_clk_dis;
+ }
+
+ regulator_enable(supply);
+
+ dev->priv = priv;
+
+ return 0;
+
+err_clk_dis:
+ clk_disable(priv->clk);
+
+ return ret;
+}
+
+static void stm32_vrefbuf_remove(struct device *dev)
+{
+ struct stm32_vrefbuf *priv = dev->priv;
+
+ clk_disable(priv->clk);
+};
+
+static const struct of_device_id __maybe_unused stm32_vrefbuf_of_match[] = {
+ { .compatible = "st,stm32-vrefbuf", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct driver stm32_vrefbuf_driver = {
+ .probe = stm32_vrefbuf_probe,
+ .name = "stm32-vrefbuf",
+ .remove = stm32_vrefbuf_remove,
+ .of_compatible = stm32_vrefbuf_of_match,
+};
+device_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c
index aaaba092c1..3ed351b580 100644
--- a/drivers/regulator/stpmic1_regulator.c
+++ b/drivers/regulator/stpmic1_regulator.c
@@ -1,11 +1,11 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) STMicroelectronics 2018
// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
#include <common.h>
#include <init.h>
#include <of_device.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <regulator.h>
#include <linux/mfd/stpmic1.h>
@@ -21,7 +21,6 @@
* @icc_mask: icc register mask
*/
struct stpmic1_regulator_cfg {
- struct device_d *dev;
struct regulator_dev rdev;
struct regulator_desc desc;
u8 mask_reset_reg;
@@ -127,6 +126,7 @@ static const struct regulator_ops stpmic1_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
@@ -136,6 +136,7 @@ static const struct regulator_ops stpmic1_ldo3_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
@@ -151,6 +152,7 @@ static const struct regulator_ops stpmic1_buck_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
@@ -183,6 +185,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = LDO_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_LDO3(ids, base) { \
@@ -196,6 +199,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = LDO_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_LDO4(ids, base) { \
@@ -206,6 +210,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = LDO_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_BUCK(ids, base) { \
@@ -219,6 +224,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = BUCK_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_VREF_DDR(ids, base) { \
@@ -229,6 +235,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = BUCK_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_BOOST(ids, base) { \
@@ -239,6 +246,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = BOOST_ENABLED, \
.enable_val = BOOST_ENABLED, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_VBUS_OTG(ids, base) { \
@@ -249,6 +257,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = USBSW_OTG_SWITCH_ENABLED, \
.enable_val = USBSW_OTG_SWITCH_ENABLED, \
.disable_val = 0, \
+ .supply_name = #base, \
}
#define REG_SW_OUT(ids, base) { \
@@ -259,6 +268,7 @@ static const struct regulator_ops stpmic1_switch_regul_ops = {
.enable_mask = SWIN_SWOUT_ENABLED, \
.enable_val = SWIN_SWOUT_ENABLED, \
.disable_val = 0, \
+ .supply_name = #base, \
}
static struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = {
@@ -377,14 +387,19 @@ static struct of_regulator_match stpmic1_matches[] = {
MATCH(pwr_sw2, SW_OUT),
};
-static int stpmic1_regulator_register(struct device_d *dev, int id,
+static int stpmic1_regulator_register(struct device *dev, int id,
struct of_regulator_match *match,
struct stpmic1_regulator_cfg *cfg)
{
int ret;
- cfg->dev = dev;
+ if (!match->of_node) {
+ dev_dbg(dev, "Skip missing DTB regulator %s", match->name);
+ return 0;
+ }
+
cfg->rdev.desc = &cfg->desc;
+ cfg->rdev.dev = dev;
cfg->rdev.regmap = dev_get_regmap(dev->parent, NULL);
if (IS_ERR(cfg->rdev.regmap))
return PTR_ERR(cfg->rdev.regmap);
@@ -400,11 +415,11 @@ static int stpmic1_regulator_register(struct device_d *dev, int id,
return 0;
}
-static int stpmic1_regulator_probe(struct device_d *dev)
+static int stpmic1_regulator_probe(struct device *dev)
{
int i, ret;
- ret = of_regulator_match(dev, dev->device_node, stpmic1_matches,
+ ret = of_regulator_match(dev, dev->of_node, stpmic1_matches,
ARRAY_SIZE(stpmic1_matches));
if (ret < 0) {
dev_err(dev, "Error in PMIC regulator device tree node");
@@ -427,10 +442,11 @@ static __maybe_unused const struct of_device_id stpmic1_regulator_of_match[] = {
{ .compatible = "st,stpmic1-regulators" },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, stpmic1_regulator_of_match);
-static struct driver_d stpmic1_regulator_driver = {
+static struct driver stpmic1_regulator_driver = {
.name = "stpmic1-regulator",
.probe = stpmic1_regulator_probe,
.of_compatible = DRV_OF_COMPAT(stpmic1_regulator_of_match),
};
-device_platform_driver(stpmic1_regulator_driver);
+coredevice_platform_driver(stpmic1_regulator_driver);