1 /*
2 * Copyright (c) 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT raspberrypi_core_supply_regulator
7
8 #include <zephyr/devicetree.h>
9 #include <zephyr/drivers/regulator.h>
10 #include <zephyr/dt-bindings/regulator/rpi_pico.h>
11 #include <zephyr/sys/linear_range.h>
12 #include <zephyr/toolchain.h>
13 #include <hardware/regs/vreg_and_chip_reset.h>
14 #include <hardware/structs/vreg_and_chip_reset.h>
15
16 static const struct linear_range core_ranges[] = {
17 LINEAR_RANGE_INIT(800000u, 0u, 0u, 5u),
18 LINEAR_RANGE_INIT(850000u, 50000u, 6u, 15u),
19 };
20
21 static const size_t num_core_ranges = ARRAY_SIZE(core_ranges);
22
23 struct regulator_rpi_pico_config {
24 struct regulator_common_config common;
25 vreg_and_chip_reset_hw_t * const reg;
26 const bool brown_out_detection;
27 const uint32_t brown_out_threshold;
28 };
29
30 struct regulator_rpi_pico_data {
31 struct regulator_common_data data;
32 };
33
34 /*
35 * APIs
36 */
37
regulator_rpi_pico_count_voltages(const struct device * dev)38 static unsigned int regulator_rpi_pico_count_voltages(const struct device *dev)
39 {
40 return linear_range_group_values_count(core_ranges, num_core_ranges);
41 }
42
regulator_rpi_pico_list_voltage(const struct device * dev,unsigned int idx,int32_t * volt_uv)43 static int regulator_rpi_pico_list_voltage(const struct device *dev, unsigned int idx,
44 int32_t *volt_uv)
45 {
46 return linear_range_group_get_value(core_ranges, num_core_ranges, idx, volt_uv);
47 }
48
regulator_rpi_pico_set_voltage(const struct device * dev,int32_t min_uv,int32_t max_uv)49 static int regulator_rpi_pico_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
50 {
51 const struct regulator_rpi_pico_config *config = dev->config;
52 uint16_t idx;
53 int ret;
54
55 ret = linear_range_group_get_win_index(core_ranges, num_core_ranges, min_uv, max_uv, &idx);
56 if (ret < 0) {
57 return ret;
58 }
59
60 config->reg->vreg = ((config->reg->vreg & ~VREG_AND_CHIP_RESET_VREG_VSEL_BITS) |
61 (idx << VREG_AND_CHIP_RESET_VREG_VSEL_LSB));
62
63 return 0;
64 }
65
regulator_rpi_pico_get_voltage(const struct device * dev,int32_t * volt_uv)66 static int regulator_rpi_pico_get_voltage(const struct device *dev, int32_t *volt_uv)
67 {
68 const struct regulator_rpi_pico_config *config = dev->config;
69
70 return linear_range_group_get_value(
71 core_ranges, num_core_ranges,
72 ((config->reg->vreg & VREG_AND_CHIP_RESET_VREG_VSEL_BITS) >>
73 VREG_AND_CHIP_RESET_VREG_VSEL_LSB),
74 volt_uv);
75 }
76
regulator_rpi_pico_enable(const struct device * dev)77 static int regulator_rpi_pico_enable(const struct device *dev)
78 {
79 const struct regulator_rpi_pico_config *config = dev->config;
80
81 config->reg->vreg |= BIT(VREG_AND_CHIP_RESET_VREG_EN_LSB);
82
83 return 0;
84 }
85
regulator_rpi_pico_disable(const struct device * dev)86 static int regulator_rpi_pico_disable(const struct device *dev)
87 {
88 const struct regulator_rpi_pico_config *config = dev->config;
89
90 config->reg->vreg &= ~BIT(VREG_AND_CHIP_RESET_VREG_EN_LSB);
91
92 return 0;
93 }
94
regulator_rpi_pico_set_mode(const struct device * dev,regulator_mode_t mode)95 static int regulator_rpi_pico_set_mode(const struct device *dev, regulator_mode_t mode)
96 {
97 const struct regulator_rpi_pico_config *config = dev->config;
98
99 if (mode & REGULATOR_RPI_PICO_MODE_HI_Z) {
100 config->reg->vreg |= REGULATOR_RPI_PICO_MODE_HI_Z;
101 } else {
102 config->reg->vreg &= (~REGULATOR_RPI_PICO_MODE_HI_Z);
103 }
104
105 return 0;
106 }
107
regulator_rpi_pico_get_mode(const struct device * dev,regulator_mode_t * mode)108 static int regulator_rpi_pico_get_mode(const struct device *dev, regulator_mode_t *mode)
109 {
110 const struct regulator_rpi_pico_config *config = dev->config;
111
112 *mode = (config->reg->vreg & REGULATOR_RPI_PICO_MODE_HI_Z);
113
114 return 0;
115 }
116
regulator_rpi_pico_init(const struct device * dev)117 static int regulator_rpi_pico_init(const struct device *dev)
118 {
119 const struct regulator_rpi_pico_config *config = dev->config;
120
121 if (config->brown_out_detection) {
122 config->reg->bod =
123 (BIT(VREG_AND_CHIP_RESET_BOD_EN_LSB) |
124 (config->brown_out_threshold << VREG_AND_CHIP_RESET_BOD_VSEL_LSB));
125 } else {
126 config->reg->bod &= ~BIT(VREG_AND_CHIP_RESET_BOD_EN_LSB);
127 }
128
129 regulator_common_data_init(dev);
130
131 return regulator_common_init(dev, true);
132 }
133
134 static const struct regulator_driver_api api = {
135 .enable = regulator_rpi_pico_enable,
136 .disable = regulator_rpi_pico_disable,
137 .count_voltages = regulator_rpi_pico_count_voltages,
138 .list_voltage = regulator_rpi_pico_list_voltage,
139 .set_voltage = regulator_rpi_pico_set_voltage,
140 .get_voltage = regulator_rpi_pico_get_voltage,
141 .set_mode = regulator_rpi_pico_set_mode,
142 .get_mode = regulator_rpi_pico_get_mode,
143 };
144
145 #define REGULATOR_RPI_PICO_DEFINE_ALL(inst) \
146 static struct regulator_rpi_pico_data data_##inst; \
147 \
148 static const struct regulator_rpi_pico_config config_##inst = { \
149 .common = REGULATOR_DT_COMMON_CONFIG_INIT(inst), \
150 .reg = (vreg_and_chip_reset_hw_t * const)DT_INST_REG_ADDR(inst), \
151 .brown_out_detection = DT_INST_PROP(inst, raspberrypi_brown_out_detection), \
152 .brown_out_threshold = DT_INST_ENUM_IDX(inst, raspberrypi_brown_out_threshold), \
153 }; \
154 \
155 DEVICE_DT_INST_DEFINE(inst, regulator_rpi_pico_init, NULL, &data_##inst, &config_##inst, \
156 POST_KERNEL, CONFIG_REGULATOR_RPI_PICO_INIT_PRIORITY, &api);
157
158 DT_INST_FOREACH_STATUS_OKAY(REGULATOR_RPI_PICO_DEFINE_ALL)
159