1 /*
2 * Copyright (c) 2021 NXP
3 * Copyright (c) 2023 Martin Kiepfer <mrmarteng@teleschirm.org>
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT x_powers_axp192_regulator
8
9 #include <errno.h>
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/drivers/regulator.h>
14 #include <zephyr/sys/linear_range.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/dt-bindings/regulator/axp192.h>
17 #include <zephyr/logging/log.h>
18 #include <zephyr/logging/log_instance.h>
19 #include <zephyr/drivers/mfd/axp192.h>
20
21 LOG_MODULE_REGISTER(regulator_axp192, CONFIG_REGULATOR_LOG_LEVEL);
22
23 /* Output control registers */
24 #define AXP192_REG_EXTEN_DCDC2_CONTROL 0x10U
25 #define AXP192_REG_DCDC123_LDO23_CONTROL 0x12U
26 #define AXP192_REG_DCDC2_VOLTAGE 0x23U
27 #define AXP192_REG_DCDC2_SLOPE 0x25U
28 #define AXP192_REG_DCDC1_VOLTAGE 0x26U
29 #define AXP192_REG_DCDC3_VOLTAGE 0x27U
30 #define AXP192_REG_LDO23_VOLTAGE 0x28U
31 #define AXP192_REG_DCDC123_WORKMODE 0x80U
32 #define AXP192_REG_GPIO0_CONTROL 0x90U
33 #define AXP192_REG_LDOIO0_VOLTAGE 0x91U
34
35 struct regulator_axp192_desc {
36 const uint8_t enable_reg;
37 const uint8_t enable_mask;
38 const uint8_t enable_val;
39 const uint8_t vsel_reg;
40 const uint8_t vsel_mask;
41 const uint8_t vsel_bitpos;
42 const int32_t max_ua;
43 const uint8_t workmode_reg;
44 const uint8_t workmode_mask;
45 const uint8_t workmode_pwm_val;
46 const uint8_t num_ranges;
47 const struct linear_range *ranges;
48 };
49
50 struct regulator_axp192_data {
51 struct regulator_common_data data;
52 };
53
54 struct regulator_axp192_config {
55 struct regulator_common_config common;
56 const struct regulator_axp192_desc *desc;
57 const struct device *mfd;
58 const struct i2c_dt_spec i2c;
59
60 LOG_INSTANCE_PTR_DECLARE(log);
61 };
62
63 static const struct linear_range dcdc1_ranges[] = {
64 LINEAR_RANGE_INIT(700000U, 25000U, 0x00U, 0x7FU),
65 };
66
67 __maybe_unused static const struct regulator_axp192_desc dcdc1_desc = {
68 .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL,
69 .enable_mask = 0x01U,
70 .enable_val = 0x01U,
71 .vsel_reg = AXP192_REG_DCDC1_VOLTAGE,
72 .vsel_mask = 0x7FU,
73 .vsel_bitpos = 0U,
74 .max_ua = 1200000U,
75 .workmode_reg = AXP192_REG_DCDC123_WORKMODE,
76 .workmode_mask = 0x08U,
77 .workmode_pwm_val = 0x08U,
78 .ranges = dcdc1_ranges,
79 .num_ranges = ARRAY_SIZE(dcdc1_ranges),
80 };
81
82 static const struct linear_range dcdc2_ranges[] = {
83 LINEAR_RANGE_INIT(700000U, 25000U, 0x00U, 0x3FU),
84 };
85
86 __maybe_unused static const struct regulator_axp192_desc dcdc2_desc = {
87 .enable_reg = AXP192_REG_EXTEN_DCDC2_CONTROL,
88 .enable_mask = 0x01U,
89 .enable_val = 0x01U,
90 .vsel_reg = AXP192_REG_DCDC2_VOLTAGE,
91 .vsel_mask = 0x3FU,
92 .vsel_bitpos = 0U,
93 .max_ua = 1600000U,
94 .workmode_reg = AXP192_REG_DCDC123_WORKMODE,
95 .workmode_mask = 0x04U,
96 .workmode_pwm_val = 0x04U,
97 .ranges = dcdc2_ranges,
98 .num_ranges = ARRAY_SIZE(dcdc2_ranges),
99 };
100
101 static const struct linear_range dcdc3_ranges[] = {
102 LINEAR_RANGE_INIT(700000U, 25000U, 0x00U, 0x7FU),
103 };
104
105 __maybe_unused static const struct regulator_axp192_desc dcdc3_desc = {
106 .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL,
107 .enable_mask = 0x02U,
108 .enable_val = 0x02U,
109 .vsel_reg = AXP192_REG_DCDC3_VOLTAGE,
110 .vsel_mask = 0x7FU,
111 .vsel_bitpos = 0U,
112 .max_ua = 700000U,
113 .workmode_reg = AXP192_REG_DCDC123_WORKMODE,
114 .workmode_mask = 0x02U,
115 .workmode_pwm_val = 0x02U,
116 .ranges = dcdc3_ranges,
117 .num_ranges = ARRAY_SIZE(dcdc3_ranges),
118 };
119
120 static const struct linear_range ldoio0_ranges[] = {
121 LINEAR_RANGE_INIT(1800000u, 100000u, 0x00u, 0x0Fu),
122 };
123
124 __maybe_unused static const struct regulator_axp192_desc ldoio0_desc = {
125 .enable_reg = AXP192_REG_GPIO0_CONTROL,
126 .enable_mask = 0x07u,
127 .enable_val = 0x03u,
128 .vsel_reg = AXP192_REG_LDOIO0_VOLTAGE,
129 .vsel_mask = 0xF0u,
130 .vsel_bitpos = 4u,
131 .max_ua = 50000u,
132 .workmode_reg = 0u,
133 .workmode_mask = 0u,
134 .ranges = ldoio0_ranges,
135 .num_ranges = ARRAY_SIZE(ldoio0_ranges),
136 };
137
138 static const struct linear_range ldo2_ranges[] = {
139 LINEAR_RANGE_INIT(1800000U, 100000U, 0x00U, 0x0FU),
140 };
141
142 __maybe_unused static const struct regulator_axp192_desc ldo2_desc = {
143 .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL,
144 .enable_mask = 0x04U,
145 .enable_val = 0x04U,
146 .vsel_reg = AXP192_REG_LDO23_VOLTAGE,
147 .vsel_mask = 0xF0U,
148 .vsel_bitpos = 4U,
149 .max_ua = 200000U,
150 .workmode_reg = 0U,
151 .workmode_mask = 0U,
152 .ranges = ldo2_ranges,
153 .num_ranges = ARRAY_SIZE(ldo2_ranges),
154 };
155
156 static const struct linear_range ldo3_ranges[] = {
157 LINEAR_RANGE_INIT(1800000U, 100000U, 0x00U, 0x0FU),
158 };
159
160 __maybe_unused static const struct regulator_axp192_desc ldo3_desc = {
161 .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL,
162 .enable_mask = 0x08U,
163 .enable_val = 0x08U,
164 .vsel_reg = AXP192_REG_LDO23_VOLTAGE,
165 .vsel_mask = 0x0FU,
166 .vsel_bitpos = 0U,
167 .max_ua = 200000U,
168 .workmode_reg = 0U,
169 .workmode_mask = 0U,
170 .ranges = ldo3_ranges,
171 .num_ranges = ARRAY_SIZE(ldo3_ranges),
172 };
173
axp192_enable(const struct device * dev)174 static int axp192_enable(const struct device *dev)
175 {
176 const struct regulator_axp192_config *config = dev->config;
177 int ret;
178
179 LOG_INST_DBG(config->log, "Enabling regulator");
180 LOG_INST_DBG(config->log, "[0x%02x]=0x%02x mask=0x%02x", config->desc->enable_reg,
181 config->desc->enable_val, config->desc->enable_mask);
182
183 /* special case for LDOIO0, which is multiplexed with GPIO0 */
184 if (config->desc->enable_reg == AXP192_REG_GPIO0_CONTROL) {
185 ret = mfd_axp192_gpio_func_ctrl(config->mfd, dev, 0, AXP192_GPIO_FUNC_LDO);
186 } else {
187 ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->enable_reg,
188 config->desc->enable_mask, config->desc->enable_val);
189 }
190
191 if (ret != 0) {
192 LOG_INST_ERR(config->log, "Failed to enable regulator");
193 }
194
195 return ret;
196 }
197
axp192_disable(const struct device * dev)198 static int axp192_disable(const struct device *dev)
199 {
200 const struct regulator_axp192_config *config = dev->config;
201 int ret;
202
203 LOG_INST_DBG(config->log, "Disabling regulator");
204 LOG_INST_DBG(config->log, "[0x%02x]=0 mask=0x%x", config->desc->enable_reg,
205 config->desc->enable_mask);
206
207 /* special case for LDOIO0, which is multiplexed with GPIO0 */
208 if (config->desc->enable_reg == AXP192_REG_GPIO0_CONTROL) {
209 ret = mfd_axp192_gpio_func_ctrl(config->mfd, dev, 0, AXP192_GPIO_FUNC_OUTPUT_LOW);
210 } else {
211 ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->enable_reg,
212 config->desc->enable_mask, 0u);
213 }
214 if (ret != 0) {
215 LOG_INST_ERR(config->log, "Failed to disable regulator");
216 }
217
218 return ret;
219 }
220
axp192_count_voltages(const struct device * dev)221 static unsigned int axp192_count_voltages(const struct device *dev)
222 {
223 const struct regulator_axp192_config *config = dev->config;
224
225 return linear_range_group_values_count(config->desc->ranges, config->desc->num_ranges);
226 }
227
axp192_list_voltage(const struct device * dev,unsigned int idx,int32_t * volt_uv)228 static int axp192_list_voltage(const struct device *dev, unsigned int idx, int32_t *volt_uv)
229 {
230 const struct regulator_axp192_config *config = dev->config;
231
232 return linear_range_group_get_value(config->desc->ranges, config->desc->num_ranges, idx,
233 volt_uv);
234 }
235
axp192_set_voltage(const struct device * dev,int32_t min_uv,int32_t max_uv)236 static int axp192_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
237 {
238 const struct regulator_axp192_config *config = dev->config;
239 uint16_t idx;
240 int ret;
241
242 LOG_INST_DBG(config->log, "voltage = [min=%d, max=%d]", min_uv, max_uv);
243
244 /* set voltage */
245 ret = linear_range_group_get_win_index(config->desc->ranges, config->desc->num_ranges,
246 min_uv, max_uv, &idx);
247 if (ret != 0) {
248 LOG_INST_ERR(config->log, "No voltage range window could be detected");
249 return ret;
250 }
251
252 idx <<= config->desc->vsel_bitpos;
253
254 LOG_INST_DBG(config->log, "[0x%x]=0x%x mask=0x%x", config->desc->vsel_reg, idx,
255 config->desc->vsel_mask);
256 ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->vsel_reg, config->desc->vsel_mask,
257 (uint8_t)idx);
258 if (ret != 0) {
259 LOG_INST_ERR(config->log, "Failed to set regulator voltage");
260 }
261
262 return ret;
263 }
264
axp192_get_voltage(const struct device * dev,int32_t * volt_uv)265 static int axp192_get_voltage(const struct device *dev, int32_t *volt_uv)
266 {
267 const struct regulator_axp192_config *config = dev->config;
268 int ret;
269 uint8_t raw_reg;
270
271 /* read voltage */
272 ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->vsel_reg, &raw_reg);
273 if (ret != 0) {
274 return ret;
275 }
276
277 raw_reg = (raw_reg & config->desc->vsel_mask) >> config->desc->vsel_bitpos;
278
279 ret = linear_range_group_get_value(config->desc->ranges, config->desc->num_ranges, raw_reg,
280 volt_uv);
281
282 return ret;
283 }
284
axp192_set_mode(const struct device * dev,regulator_mode_t mode)285 static int axp192_set_mode(const struct device *dev, regulator_mode_t mode)
286 {
287 const struct regulator_axp192_config *config = dev->config;
288 int ret;
289
290 /* setting workmode is only possible for DCDC1-3 */
291 if ((mode == AXP192_DCDC_MODE_PWM) && (config->desc->workmode_reg != 0)) {
292
293 /* configure PWM mode */
294 LOG_INST_DBG(config->log, "PWM mode enabled");
295 ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->workmode_reg,
296 config->desc->workmode_mask,
297 config->desc->workmode_pwm_val);
298 if (ret != 0) {
299 return ret;
300 }
301 } else if (mode == AXP192_DCDC_MODE_AUTO) {
302
303 /* configure AUTO mode (default) */
304 if (config->desc->workmode_reg != 0) {
305 ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->workmode_reg,
306 config->desc->workmode_mask, 0u);
307 if (ret != 0) {
308 return ret;
309 }
310 } else {
311
312 /* AUTO is default mode for LDOs that cannot be configured */
313 return 0;
314 }
315 } else {
316 LOG_INST_ERR(config->log, "Setting DCDC workmode failed");
317 return -ENOTSUP;
318 }
319
320 return 0;
321 }
322
axp192_get_current_limit(const struct device * dev,int32_t * curr_ua)323 static int axp192_get_current_limit(const struct device *dev, int32_t *curr_ua)
324 {
325 const struct regulator_axp192_config *config = dev->config;
326
327 *curr_ua = config->desc->max_ua;
328
329 return 0;
330 }
331
332 static DEVICE_API(regulator, api) = {
333 .enable = axp192_enable,
334 .disable = axp192_disable,
335 .count_voltages = axp192_count_voltages,
336 .list_voltage = axp192_list_voltage,
337 .set_voltage = axp192_set_voltage,
338 .get_voltage = axp192_get_voltage,
339 .set_mode = axp192_set_mode,
340 .get_current_limit = axp192_get_current_limit,
341 };
342
regulator_axp192_init(const struct device * dev)343 static int regulator_axp192_init(const struct device *dev)
344 {
345 const struct regulator_axp192_config *config = dev->config;
346 uint8_t enabled_val;
347 bool is_enabled;
348 int ret = 0;
349
350 regulator_common_data_init(dev);
351
352 if (!device_is_ready(config->mfd)) {
353 LOG_INST_ERR(config->log, "Parent instance not ready!");
354 return -ENODEV;
355 }
356
357 /* read regulator state */
358 ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->enable_reg, &enabled_val);
359 if (ret != 0) {
360 LOG_INST_ERR(config->log, "Reading enable status failed!");
361 return ret;
362 }
363 is_enabled = ((enabled_val & config->desc->enable_mask) == config->desc->enable_val);
364 LOG_INST_DBG(config->log, "is_enabled: %d", is_enabled);
365
366 return regulator_common_init(dev, is_enabled);
367 }
368
369 #define REGULATOR_AXP192_DEFINE(node_id, id, name) \
370 static struct regulator_axp192_data data_##id; \
371 LOG_INSTANCE_REGISTER(name, node_id, CONFIG_REGULATOR_LOG_LEVEL); \
372 static const struct regulator_axp192_config config_##id = { \
373 .common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \
374 .desc = &name##_desc, \
375 .mfd = DEVICE_DT_GET(DT_GPARENT(node_id)), \
376 .i2c = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \
377 LOG_INSTANCE_PTR_INIT(log, name, node_id)}; \
378 DEVICE_DT_DEFINE(node_id, regulator_axp192_init, NULL, &data_##id, &config_##id, \
379 POST_KERNEL, CONFIG_REGULATOR_AXP192_INIT_PRIORITY, &api);
380
381 #define REGULATOR_AXP192_DEFINE_COND(inst, child) \
382 COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \
383 (REGULATOR_AXP192_DEFINE(DT_INST_CHILD(inst, child), child##inst, child)), ())
384
385 #define REGULATOR_AXP192_DEFINE_ALL(inst) \
386 REGULATOR_AXP192_DEFINE_COND(inst, dcdc1) \
387 REGULATOR_AXP192_DEFINE_COND(inst, dcdc2) \
388 REGULATOR_AXP192_DEFINE_COND(inst, dcdc3) \
389 REGULATOR_AXP192_DEFINE_COND(inst, ldoio0) \
390 REGULATOR_AXP192_DEFINE_COND(inst, ldo2) \
391 REGULATOR_AXP192_DEFINE_COND(inst, ldo3)
392
393 DT_INST_FOREACH_STATUS_OKAY(REGULATOR_AXP192_DEFINE_ALL)
394