1 /*
2 * Copyright 2023-2024 NXP
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT nxp_vref
7
8 #include <errno.h>
9
10 #include <zephyr/drivers/regulator.h>
11 #include <zephyr/dt-bindings/regulator/nxp_vref.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys/linear_range.h>
14 #include <zephyr/sys/util.h>
15
16 #include <fsl_device_registers.h>
17
18 static const struct linear_range utrim_range = LINEAR_RANGE_INIT(1000000, 100000U, 0x0U, 0xBU);
19
20 struct regulator_nxp_vref_data {
21 struct regulator_common_data common;
22 };
23
24 struct regulator_nxp_vref_config {
25 struct regulator_common_config common;
26 VREF_Type *base;
27 uint16_t buf_start_delay;
28 uint16_t bg_start_time;
29 bool current_compensation_en;
30 };
31
regulator_nxp_vref_enable(const struct device * dev)32 static int regulator_nxp_vref_enable(const struct device *dev)
33 {
34 const struct regulator_nxp_vref_config *config = dev->config;
35 VREF_Type *const base = config->base;
36
37 volatile uint32_t *const csr = &base->CSR;
38
39 *csr |= VREF_CSR_LPBGEN_MASK | VREF_CSR_LPBG_BUF_EN_MASK;
40 /* Wait for bandgap startup */
41 k_busy_wait(config->bg_start_time);
42
43 /* Enable high accuracy bandgap */
44 *csr |= VREF_CSR_HCBGEN_MASK;
45
46 /* Monitor until stable */
47 while (!(*csr & VREF_CSR_VREFST_MASK)) {
48 ;
49 }
50
51 /* Enable output buffer */
52 *csr |= VREF_CSR_BUF21EN_MASK;
53
54 return 0;
55 }
56
regulator_nxp_vref_disable(const struct device * dev)57 static int regulator_nxp_vref_disable(const struct device *dev)
58 {
59 const struct regulator_nxp_vref_config *config = dev->config;
60 VREF_Type *const base = config->base;
61
62 /*
63 * Disable HC Bandgap, LP Bandgap, and Buf21
64 * to achieve "Off" mode of VREF
65 */
66 base->CSR &= ~(VREF_CSR_BUF21EN_MASK | VREF_CSR_HCBGEN_MASK | VREF_CSR_LPBGEN_MASK);
67
68 return 0;
69 }
70
regulator_nxp_vref_set_mode(const struct device * dev,regulator_mode_t mode)71 static int regulator_nxp_vref_set_mode(const struct device *dev, regulator_mode_t mode)
72 {
73 const struct regulator_nxp_vref_config *config = dev->config;
74 VREF_Type *const base = config->base;
75 uint32_t csr = base->CSR;
76
77 if (mode == NXP_VREF_MODE_STANDBY) {
78 csr &= ~VREF_CSR_REGEN_MASK &
79 ~VREF_CSR_CHOPEN_MASK &
80 ~VREF_CSR_HI_PWR_LV_MASK &
81 ~VREF_CSR_BUF21EN_MASK;
82 } else if (mode == NXP_VREF_MODE_LOW_POWER) {
83 csr &= ~VREF_CSR_REGEN_MASK &
84 ~VREF_CSR_CHOPEN_MASK &
85 ~VREF_CSR_HI_PWR_LV_MASK;
86 csr |= VREF_CSR_BUF21EN_MASK;
87 } else if (mode == NXP_VREF_MODE_HIGH_POWER) {
88 csr &= ~VREF_CSR_REGEN_MASK &
89 ~VREF_CSR_CHOPEN_MASK;
90 csr |= VREF_CSR_HI_PWR_LV_MASK &
91 VREF_CSR_BUF21EN_MASK;
92 } else if (mode == NXP_VREF_MODE_INTERNAL_REGULATOR) {
93 csr |= VREF_CSR_REGEN_MASK &
94 VREF_CSR_CHOPEN_MASK &
95 VREF_CSR_HI_PWR_LV_MASK &
96 VREF_CSR_BUF21EN_MASK;
97 } else {
98 return -EINVAL;
99 }
100
101 base->CSR = csr;
102
103 k_busy_wait(config->buf_start_delay);
104
105 return 0;
106 }
107
regulator_nxp_vref_get_mode(const struct device * dev,regulator_mode_t * mode)108 static int regulator_nxp_vref_get_mode(const struct device *dev, regulator_mode_t *mode)
109 {
110 const struct regulator_nxp_vref_config *config = dev->config;
111 VREF_Type *const base = config->base;
112 uint32_t csr = base->CSR;
113
114 /* Check bits to determine mode */
115 if (csr & VREF_CSR_REGEN_MASK) {
116 *mode = NXP_VREF_MODE_INTERNAL_REGULATOR;
117 } else if (csr & VREF_CSR_HI_PWR_LV_MASK) {
118 *mode = NXP_VREF_MODE_HIGH_POWER;
119 } else if (csr & VREF_CSR_BUF21EN_MASK) {
120 *mode = NXP_VREF_MODE_LOW_POWER;
121 } else {
122 *mode = NXP_VREF_MODE_STANDBY;
123 }
124
125 return 0;
126 }
127
regulator_nxp_vref_count_voltages(const struct device * dev)128 static inline unsigned int regulator_nxp_vref_count_voltages(const struct device *dev)
129 {
130 return linear_range_values_count(&utrim_range);
131 }
132
regulator_nxp_vref_list_voltage(const struct device * dev,unsigned int idx,int32_t * volt_uv)133 static int regulator_nxp_vref_list_voltage(const struct device *dev,
134 unsigned int idx, int32_t *volt_uv)
135 {
136 return linear_range_get_value(&utrim_range, idx, volt_uv);
137 }
138
regulator_nxp_vref_set_voltage(const struct device * dev,int32_t min_uv,int32_t max_uv)139 static int regulator_nxp_vref_set_voltage(const struct device *dev,
140 int32_t min_uv, int32_t max_uv)
141 {
142 const struct regulator_nxp_vref_config *config = dev->config;
143 VREF_Type *const base = config->base;
144 uint16_t idx;
145 int ret;
146
147 ret = linear_range_get_win_index(&utrim_range, min_uv, max_uv, &idx);
148 if (ret < 0) {
149 return ret;
150 }
151
152 base->UTRIM &= ~VREF_UTRIM_TRIM2V1_MASK;
153 base->UTRIM |= VREF_UTRIM_TRIM2V1_MASK & idx;
154
155 return 0;
156 }
157
regulator_nxp_vref_get_voltage(const struct device * dev,int32_t * volt_uv)158 static int regulator_nxp_vref_get_voltage(const struct device *dev,
159 int32_t *volt_uv)
160 {
161 const struct regulator_nxp_vref_config *config = dev->config;
162 VREF_Type *const base = config->base;
163 uint16_t idx;
164 int ret;
165
166 /* Linear range index is the register value */
167 idx = (base->UTRIM & VREF_UTRIM_TRIM2V1_MASK) >> VREF_UTRIM_TRIM2V1_SHIFT;
168
169 ret = linear_range_get_value(&utrim_range, idx, volt_uv);
170
171 return ret;
172 }
173
174 static DEVICE_API(regulator, api) = {
175 .enable = regulator_nxp_vref_enable,
176 .disable = regulator_nxp_vref_disable,
177 .set_mode = regulator_nxp_vref_set_mode,
178 .get_mode = regulator_nxp_vref_get_mode,
179 .set_voltage = regulator_nxp_vref_set_voltage,
180 .get_voltage = regulator_nxp_vref_get_voltage,
181 .list_voltage = regulator_nxp_vref_list_voltage,
182 .count_voltages = regulator_nxp_vref_count_voltages,
183 };
184
regulator_nxp_vref_init(const struct device * dev)185 static int regulator_nxp_vref_init(const struct device *dev)
186 {
187 const struct regulator_nxp_vref_config *config = dev->config;
188 VREF_Type *const base = config->base;
189 int ret;
190
191 regulator_common_data_init(dev);
192
193 ret = regulator_nxp_vref_disable(dev);
194 if (ret < 0) {
195 return ret;
196 }
197
198 if (config->current_compensation_en) {
199 base->CSR |= VREF_CSR_ICOMPEN_MASK;
200 }
201
202 /* Workaround some chips not resetting the value correctly on reset */
203 base->UTRIM = 0;
204
205 return regulator_common_init(dev, false);
206 }
207
208 #define REGULATOR_NXP_VREF_DEFINE(inst) \
209 static struct regulator_nxp_vref_data data_##inst; \
210 \
211 static const struct regulator_nxp_vref_config config_##inst = { \
212 .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \
213 .base = (VREF_Type *) DT_INST_REG_ADDR(inst), \
214 .buf_start_delay = DT_INST_PROP(inst, \
215 nxp_buffer_startup_delay_us), \
216 .bg_start_time = DT_INST_PROP(inst, \
217 nxp_bandgap_startup_time_us), \
218 .current_compensation_en = DT_INST_PROP(inst, \
219 nxp_current_compensation_en), \
220 }; \
221 \
222 DEVICE_DT_INST_DEFINE(inst, regulator_nxp_vref_init, NULL, &data_##inst,\
223 &config_##inst, POST_KERNEL, \
224 CONFIG_REGULATOR_NXP_VREF_INIT_PRIORITY, &api); \
225
226 DT_INST_FOREACH_STATUS_OKAY(REGULATOR_NXP_VREF_DEFINE)
227