drivers: regulator: add support for RaspberryPi Pico regulator.

Add support for rpi_pico regulator.

Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt
index 170fff4..c05e2dd 100644
--- a/drivers/regulator/CMakeLists.txt
+++ b/drivers/regulator/CMakeLists.txt
@@ -10,3 +10,4 @@
 zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM6001 regulator_npm6001.c)
 zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9420 regulator_pca9420.c)
 zephyr_library_sources_ifdef(CONFIG_REGULATOR_SHELL regulator_shell.c)
+zephyr_library_sources_ifdef(CONFIG_REGULATOR_RPI_PICO regulator_rpi_pico.c)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index e0329db..415fcfd 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -25,5 +25,6 @@
 source "drivers/regulator/Kconfig.npm1100"
 source "drivers/regulator/Kconfig.npm6001"
 source "drivers/regulator/Kconfig.pca9420"
+source "drivers/regulator/Kconfig.rpi_pico"
 
 endif # REGULATOR
diff --git a/drivers/regulator/Kconfig.rpi_pico b/drivers/regulator/Kconfig.rpi_pico
new file mode 100644
index 0000000..fe97a52
--- /dev/null
+++ b/drivers/regulator/Kconfig.rpi_pico
@@ -0,0 +1,19 @@
+# Copyright (c) 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
+# SPDX-License-Identifier: Apache-2.0
+
+config REGULATOR_RPI_PICO
+	bool "RaspberryPi Pico regulator driver"
+	default y
+	depends on DT_HAS_RASPBERRYPI_CORE_SUPPLY_REGULATOR_ENABLED
+	help
+	  Enable support for the RaspberryPi Pico regulator.
+
+if REGULATOR_RPI_PICO
+
+config REGULATOR_RPI_PICO_INIT_PRIORITY
+	int "RaspberryPi Pico regulator driver init priority"
+	default KERNEL_INIT_PRIORITY_DEVICE
+	help
+	  Init priority for the RaspberryPi Pico regulator driver.
+
+endif
diff --git a/drivers/regulator/regulator_rpi_pico.c b/drivers/regulator/regulator_rpi_pico.c
new file mode 100644
index 0000000..f2c0af1
--- /dev/null
+++ b/drivers/regulator/regulator_rpi_pico.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT raspberrypi_core_supply_regulator
+
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/regulator.h>
+#include <zephyr/dt-bindings/regulator/rpi_pico.h>
+#include <zephyr/sys/linear_range.h>
+#include <zephyr/toolchain.h>
+#include <hardware/regs/vreg_and_chip_reset.h>
+#include <hardware/structs/vreg_and_chip_reset.h>
+
+static const struct linear_range core_ranges[] = {
+	LINEAR_RANGE_INIT(800000u, 0u, 0u, 5u),
+	LINEAR_RANGE_INIT(850000u, 50000u, 6u, 15u),
+};
+
+static const size_t num_core_ranges = ARRAY_SIZE(core_ranges);
+
+struct regulator_rpi_pico_config {
+	struct regulator_common_config common;
+	vreg_and_chip_reset_hw_t * const reg;
+	const bool brown_out_detection;
+	const uint32_t brown_out_threshold;
+};
+
+struct regulator_rpi_pico_data {
+	struct regulator_common_data data;
+};
+
+/*
+ * APIs
+ */
+
+static unsigned int regulator_rpi_pico_count_voltages(const struct device *dev)
+{
+	return linear_range_group_values_count(core_ranges, num_core_ranges);
+}
+
+static int regulator_rpi_pico_list_voltage(const struct device *dev, unsigned int idx,
+					   int32_t *volt_uv)
+{
+	return linear_range_group_get_value(core_ranges, num_core_ranges, idx, volt_uv);
+}
+
+static int regulator_rpi_pico_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+	uint16_t idx;
+	int ret;
+
+	ret = linear_range_group_get_win_index(core_ranges, num_core_ranges, min_uv, max_uv, &idx);
+	if (ret < 0) {
+		return ret;
+	}
+
+	config->reg->vreg = ((config->reg->vreg & ~VREG_AND_CHIP_RESET_VREG_VSEL_BITS) |
+			     (idx << VREG_AND_CHIP_RESET_VREG_VSEL_LSB));
+
+	return 0;
+}
+
+static int regulator_rpi_pico_get_voltage(const struct device *dev, int32_t *volt_uv)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+
+	return linear_range_group_get_value(
+		core_ranges, num_core_ranges,
+		((config->reg->vreg & VREG_AND_CHIP_RESET_VREG_VSEL_BITS) >>
+		 VREG_AND_CHIP_RESET_VREG_VSEL_LSB),
+		volt_uv);
+}
+
+static int regulator_rpi_pico_enable(const struct device *dev)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+
+	config->reg->vreg |= BIT(VREG_AND_CHIP_RESET_VREG_EN_LSB);
+
+	return 0;
+}
+
+static int regulator_rpi_pico_disable(const struct device *dev)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+
+	config->reg->vreg &= ~BIT(VREG_AND_CHIP_RESET_VREG_EN_LSB);
+
+	return 0;
+}
+
+static int regulator_rpi_pico_set_mode(const struct device *dev, regulator_mode_t mode)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+
+	if (mode & REGULATOR_RPI_PICO_MODE_HI_Z) {
+		config->reg->vreg |= REGULATOR_RPI_PICO_MODE_HI_Z;
+	} else {
+		config->reg->vreg &= (~REGULATOR_RPI_PICO_MODE_HI_Z);
+	}
+
+	return 0;
+}
+
+static int regulator_rpi_pico_get_mode(const struct device *dev, regulator_mode_t *mode)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+
+	*mode = (config->reg->vreg & REGULATOR_RPI_PICO_MODE_HI_Z);
+
+	return 0;
+}
+
+static int regulator_rpi_pico_init(const struct device *dev)
+{
+	const struct regulator_rpi_pico_config *config = dev->config;
+
+	if (config->brown_out_detection) {
+		config->reg->bod =
+			(BIT(VREG_AND_CHIP_RESET_BOD_EN_LSB) |
+			 (config->brown_out_threshold << VREG_AND_CHIP_RESET_BOD_VSEL_LSB));
+	} else {
+		config->reg->bod &= ~BIT(VREG_AND_CHIP_RESET_BOD_EN_LSB);
+	}
+
+	regulator_common_data_init(dev);
+
+	return regulator_common_init(dev, true);
+}
+
+static const struct regulator_driver_api api = {
+	.enable = regulator_rpi_pico_enable,
+	.disable = regulator_rpi_pico_disable,
+	.count_voltages = regulator_rpi_pico_count_voltages,
+	.list_voltage = regulator_rpi_pico_list_voltage,
+	.set_voltage = regulator_rpi_pico_set_voltage,
+	.get_voltage = regulator_rpi_pico_get_voltage,
+	.set_mode = regulator_rpi_pico_set_mode,
+	.get_mode = regulator_rpi_pico_get_mode,
+};
+
+#define REGULATOR_RPI_PICO_DEFINE_ALL(inst)                                                        \
+	static struct regulator_rpi_pico_data data_##inst;                                         \
+                                                                                                   \
+	static const struct regulator_rpi_pico_config config_##inst = {                            \
+		.common = REGULATOR_DT_COMMON_CONFIG_INIT(inst),                                   \
+		.reg = (vreg_and_chip_reset_hw_t * const)DT_INST_REG_ADDR(inst),                   \
+		.brown_out_detection = DT_INST_PROP(inst, raspberrypi_brown_out_detection),        \
+		.brown_out_threshold = DT_INST_ENUM_IDX(inst, raspberrypi_brown_out_threshold),    \
+	};                                                                                         \
+                                                                                                   \
+	DEVICE_DT_INST_DEFINE(inst, regulator_rpi_pico_init, NULL, &data_##inst, &config_##inst,   \
+			      POST_KERNEL, CONFIG_REGULATOR_RPI_PICO_INIT_PRIORITY, &api);
+
+DT_INST_FOREACH_STATUS_OKAY(REGULATOR_RPI_PICO_DEFINE_ALL)
diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi
index a5a6fe8..5910411 100644
--- a/dts/arm/rpi_pico/rp2040.dtsi
+++ b/dts/arm/rpi_pico/rp2040.dtsi
@@ -7,6 +7,7 @@
 #include <arm/armv6-m.dtsi>
 #include <zephyr/dt-bindings/gpio/gpio.h>
 #include <zephyr/dt-bindings/i2c/i2c.h>
+#include <zephyr/dt-bindings/regulator/rpi_pico.h>
 #include <mem.h>
 
 #include "rpi_pico_common.dtsi"
@@ -184,6 +185,14 @@
 			status = "disabled";
 			#pwm-cells = <3>;
 		};
+
+		vreg: vreg@40064000 {
+			compatible = "raspberrypi,core-supply-regulator";
+			reg = <0x40064000 1>;
+			status = "okay";
+			raspberrypi,brown-out-detection;
+			raspberrypi,brown-out-threshold = <860000>;
+		};
 	};
 
 	pinctrl: pin-controller {
diff --git a/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml b/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml
new file mode 100644
index 0000000..2034ccd
--- /dev/null
+++ b/dts/bindings/regulator/raspberrypi,core-supply-regulator.yaml
@@ -0,0 +1,48 @@
+# Copyright (c), 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
+# SPDX -License-Identifier: Apache-2.0
+
+description: |
+  RaspberryPi Pico core supply regurator
+
+compatible: "raspberrypi,core-supply-regulator"
+
+include:
+  - name: base.yaml
+  - name: regulator.yaml
+    property-allowlist:
+      - regulator-always-on
+      - regulator-boot-on
+      - regulator-min-microvolt
+      - regulator-max-microvolt
+      - regulator-allowed-modes
+      - regulator-initial-mode
+
+properties:
+  raspberrypi,brown-out-detection:
+    type: boolean
+    description:
+      Enable brown-out detection
+
+  raspberrypi,brown-out-threshold:
+    type: int
+    default: 860000
+    enum:
+      - 473000
+      - 516000
+      - 559000
+      - 602000
+      - 645000
+      - 688000
+      - 731000
+      - 774000
+      - 817000
+      - 860000
+      - 903000
+      - 946000
+      - 989000
+      - 1032000
+      - 1075000
+      - 1118000
+    description: |
+      Reset if the core voltage drops below this threshold for a particular time
+      (determined by the 'brown-out detection assertion delay').
diff --git a/include/zephyr/dt-bindings/regulator/rpi_pico.h b/include/zephyr/dt-bindings/regulator/rpi_pico.h
new file mode 100644
index 0000000..55f2421
--- /dev/null
+++ b/include/zephyr/dt-bindings/regulator/rpi_pico.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_RPI_PICO_H_
+#define ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_RPI_PICO_H_
+
+#define REGULATOR_RPI_PICO_MODE_NORMAL 0x0
+#define REGULATOR_RPI_PICO_MODE_HI_Z 0x2
+
+#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_RPI_PICO_H_ */