1 /*
2 * Copyright (c) 2023 Martin Kiepfer <mrmarteng@teleschirm.org>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT x_powers_axp192
7
8 #include <errno.h>
9 #include <stdbool.h>
10
11 #include <zephyr/drivers/mfd/axp192.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/logging/log.h>
15
16 LOG_MODULE_REGISTER(mfd_axp192, CONFIG_MFD_LOG_LEVEL);
17
18 /* Chip ID value */
19 #define AXP192_CHIP_ID 0x03U
20
21 /* Registers definitions */
22 #define AXP192_REG_CHIP_ID 0x03U
23
24 /* AXP192 GPIO register addresses */
25 #define AXP192_GPIO0_REG_FUNC 0x90U
26 #define AXP192_GPIO1_REG_FUNC 0x92U
27 #define AXP192_GPIO2_REG_FUNC 0x93U
28 #define AXP192_GPIO34_REG_FUNC 0x95U
29 #define AXP192_GPIO012_REG_PINVAL 0x94U
30 #define AXP192_GPIO34_REG_PINVAL 0x96U
31 #define AXP192_GPIO012_REG_PULLDOWN 0x97U
32
33 /* GPIO function control parameters */
34 #define AXP192_GPIO012_FUNC_VAL_OUTPUT_OD 0x00U
35 #define AXP192_GPIO012_FUNC_VAL_INPUT 0x01U
36 #define AXP192_GPIO012_FUNC_VAL_LDO 0x02U /* only applicable for GPIO0 */
37 #define AXP192_GPIO012_FUNC_VAL_ADC 0x04U
38 #define AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW 0x05U
39 #define AXP192_GPIO012_FUNC_VAL_FLOAT 0x06U
40 #define AXP192_GPIO012_FUNC_MASK \
41 (AXP192_GPIO012_FUNC_VAL_OUTPUT_OD | AXP192_GPIO012_FUNC_VAL_INPUT | \
42 AXP192_GPIO012_FUNC_VAL_LDO | AXP192_GPIO012_FUNC_VAL_ADC | \
43 AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW | AXP192_GPIO012_FUNC_VAL_FLOAT)
44
45 #define AXP192_GPIO34_FUNC_ENA 0x80U
46 #define AXP192_GPIO3_FUNC_VAL_CHARGE_CTL 0x00U
47 #define AXP192_GPIO3_FUNC_VAL_OUTPUT_OD 0x01U
48 #define AXP192_GPIO3_FUNC_VAL_INPUT 0x02U
49 #define AXP192_GPIO3_FUNC_MASK \
50 (AXP192_GPIO34_FUNC_ENA | AXP192_GPIO3_FUNC_VAL_CHARGE_CTL | \
51 AXP192_GPIO3_FUNC_VAL_OUTPUT_OD | AXP192_GPIO3_FUNC_VAL_INPUT)
52
53 #define AXP192_GPIO4_FUNC_VAL_CHARGE_CTL 0x00U
54 #define AXP192_GPIO4_FUNC_VAL_OUTPUT_OD 0x04U
55 #define AXP192_GPIO4_FUNC_VAL_INPUT 0x08U
56 #define AXP192_GPIO4_FUNC_VAL_ADC 0x0CU
57 #define AXP192_GPIO4_FUNC_MASK \
58 (AXP192_GPIO34_FUNC_ENA | AXP192_GPIO4_FUNC_VAL_CHARGE_CTL | \
59 AXP192_GPIO4_FUNC_VAL_OUTPUT_OD | AXP192_GPIO4_FUNC_VAL_INPUT)
60
61 /* Pull-Down enable parameters */
62 #define AXP192_GPIO0_PULLDOWN_ENABLE 0x01U
63 #define AXP192_GPIO1_PULLDOWN_ENABLE 0x02U
64 #define AXP192_GPIO2_PULLDOWN_ENABLE 0x04U
65
66 /* GPIO Value parameters */
67 #define AXP192_GPIO0_INPUT_VAL 0x10U
68 #define AXP192_GPIO1_INPUT_VAL 0x20U
69 #define AXP192_GPIO2_INPUT_VAL 0x40U
70 #define AXP192_GPIO012_INTPUT_SHIFT 4U
71 #define AXP192_GPIO012_INTPUT_MASK \
72 (AXP192_GPIO0_INPUT_VAL | AXP192_GPIO1_INPUT_VAL | AXP192_GPIO2_INPUT_VAL)
73 #define AXP192_GPIO3_INPUT_VAL 0x10U
74 #define AXP192_GPIO4_INPUT_VAL 0x20U
75 #define AXP192_GPIO34_INTPUT_SHIFT 4U
76 #define AXP192_GPIO34_INTPUT_MASK (AXP192_GPIO3_INPUT_VAL | AXP192_GPIO4_INPUT_VAL)
77
78 #define AXP192_GPIO0_OUTPUT_VAL 0x01U
79 #define AXP192_GPIO1_OUTPUT_VAL 0x02U
80 #define AXP192_GPIO2_OUTPUT_VAL 0x04U
81 #define AXP192_GPIO012_OUTPUT_MASK \
82 (AXP192_GPIO0_OUTPUT_VAL | AXP192_GPIO1_OUTPUT_VAL | AXP192_GPIO2_OUTPUT_VAL)
83 #define AXP192_GPIO3_OUTPUT_VAL 0x01U
84 #define AXP192_GPIO4_OUTPUT_VAL 0x02U
85 #define AXP192_GPIO34_OUTPUT_MASK (AXP192_GPIO3_OUTPUT_VAL | AXP192_GPIO4_OUTPUT_VAL)
86
87 struct mfd_axp192_config {
88 struct i2c_dt_spec i2c;
89 };
90
91 struct mfd_axp192_data {
92 const struct device *gpio_mask_used[AXP192_GPIO_MAX_NUM];
93 uint8_t gpio_mask_output;
94 };
95
96 struct mfd_axp192_func_reg_desc {
97 uint8_t reg;
98 uint8_t mask;
99 };
100
101 const struct mfd_axp192_func_reg_desc gpio_reg_desc[AXP192_GPIO_MAX_NUM] = {
102 {
103 /* GPIO0 */
104 .reg = AXP192_GPIO0_REG_FUNC,
105 .mask = AXP192_GPIO012_FUNC_MASK,
106 },
107 {
108 /* GPIO1 */
109 .reg = AXP192_GPIO1_REG_FUNC,
110 .mask = AXP192_GPIO012_FUNC_MASK,
111 },
112 {
113 /* GPIO2 */
114 .reg = AXP192_GPIO2_REG_FUNC,
115 .mask = AXP192_GPIO012_FUNC_MASK,
116 },
117 {
118 /* GPIO3 */
119 .reg = AXP192_GPIO34_REG_FUNC,
120 .mask = AXP192_GPIO3_FUNC_MASK,
121 },
122 {
123 /* GPIO4 */
124 .reg = AXP192_GPIO34_REG_FUNC,
125 .mask = AXP192_GPIO4_FUNC_MASK,
126 },
127 };
128
mfd_axp192_init(const struct device * dev)129 static int mfd_axp192_init(const struct device *dev)
130 {
131 const struct mfd_axp192_config *config = dev->config;
132 uint8_t chip_id;
133 int ret;
134
135 LOG_DBG("Initializing instance");
136
137 if (!i2c_is_ready_dt(&config->i2c)) {
138 LOG_ERR("I2C bus not ready");
139 return -ENODEV;
140 }
141
142 /* Check if axp192 chip is available */
143 ret = i2c_reg_read_byte_dt(&config->i2c, AXP192_REG_CHIP_ID, &chip_id);
144 if (ret < 0) {
145 return ret;
146 }
147
148 if (chip_id != AXP192_CHIP_ID) {
149 LOG_ERR("Invalid Chip detected (%d)", chip_id);
150 return -EINVAL;
151 }
152
153 return 0;
154 }
155
mfd_axp192_gpio_func_get(const struct device * dev,uint8_t gpio,enum axp192_gpio_func * func)156 int mfd_axp192_gpio_func_get(const struct device *dev, uint8_t gpio, enum axp192_gpio_func *func)
157 {
158 const struct mfd_axp192_config *config = dev->config;
159 int ret;
160 uint8_t reg_fnc;
161
162 if (gpio >= AXP192_GPIO_MAX_NUM) {
163 LOG_ERR("Invalid gpio (%d)", gpio);
164 return -EINVAL;
165 }
166
167 ret = i2c_reg_read_byte_dt(&(config->i2c), gpio_reg_desc[gpio].reg, ®_fnc);
168 if (ret != 0) {
169 return ret;
170 }
171
172 switch (gpio) {
173 case 0U:
174 __fallthrough;
175 case 1U:
176 __fallthrough;
177 case 2U:
178 /* GPIO 0-2*/
179 switch (reg_fnc) {
180 case AXP192_GPIO012_FUNC_VAL_INPUT:
181 *func = AXP192_GPIO_FUNC_INPUT;
182 break;
183 case AXP192_GPIO012_FUNC_VAL_OUTPUT_OD:
184 *func = AXP192_GPIO_FUNC_OUTPUT_OD;
185 break;
186 case AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW:
187 *func = AXP192_GPIO_FUNC_OUTPUT_LOW;
188 break;
189 case AXP192_GPIO012_FUNC_VAL_LDO:
190 if (gpio == 0) {
191 /* LDO is only applicable on GPIO0 */
192 *func = AXP192_GPIO_FUNC_LDO;
193 } else {
194 ret = -ENOTSUP;
195 }
196 break;
197 case AXP192_GPIO012_FUNC_VAL_ADC:
198 *func = AXP192_GPIO_FUNC_ADC;
199 break;
200 case AXP192_GPIO012_FUNC_VAL_FLOAT:
201 *func = AXP192_GPIO_FUNC_FLOAT;
202 break;
203 default:
204 ret = -ENOTSUP;
205 break;
206 }
207 break;
208
209 case 3U:
210 /* GPIO3 */
211 switch (reg_fnc) {
212 case (AXP192_GPIO3_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA):
213 *func = AXP192_GPIO_FUNC_INPUT;
214 break;
215 case (AXP192_GPIO3_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA):
216 *func = AXP192_GPIO_FUNC_OUTPUT_OD;
217 break;
218 case AXP192_GPIO3_FUNC_VAL_CHARGE_CTL:
219 *func = AXP192_GPIO_FUNC_CHARGE_CTL;
220 break;
221 default:
222 ret = -ENOTSUP;
223 break;
224 }
225 break;
226
227 case 4U:
228 /* GPIO4 */
229 switch (reg_fnc) {
230 case (AXP192_GPIO4_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA):
231 *func = AXP192_GPIO_FUNC_INPUT;
232 break;
233 case (AXP192_GPIO4_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA):
234 *func = AXP192_GPIO_FUNC_OUTPUT_OD;
235 break;
236 case (AXP192_GPIO4_FUNC_VAL_ADC | AXP192_GPIO34_FUNC_ENA):
237 *func = AXP192_GPIO_FUNC_ADC;
238 break;
239 case AXP192_GPIO4_FUNC_VAL_CHARGE_CTL:
240 *func = AXP192_GPIO_FUNC_CHARGE_CTL;
241 break;
242 default:
243 ret = -ENOTSUP;
244 break;
245 }
246 break;
247
248 default:
249 ret = -EINVAL;
250 }
251
252 return ret;
253 }
254
mfd_axp192_gpio_func_ctrl(const struct device * dev,const struct device * client_dev,uint8_t gpio,enum axp192_gpio_func func)255 int mfd_axp192_gpio_func_ctrl(const struct device *dev, const struct device *client_dev,
256 uint8_t gpio, enum axp192_gpio_func func)
257 {
258 const struct mfd_axp192_config *config = dev->config;
259 struct mfd_axp192_data *data = dev->data;
260 bool is_output = false;
261 int ret = 0;
262 uint8_t reg_cfg;
263
264 if (!AXP192_GPIO_FUNC_VALID(func)) {
265 LOG_ERR("Invalid function");
266 return -EINVAL;
267 }
268
269 if (gpio >= AXP192_GPIO_MAX_NUM) {
270 LOG_ERR("Invalid gpio (%d)", gpio);
271 return -EINVAL;
272 }
273
274 if ((data->gpio_mask_used[gpio] != 0) && (data->gpio_mask_used[gpio] != client_dev)) {
275 LOG_INF("Warning: Pin already configured. Please check dt configuration");
276 }
277
278 switch (gpio) {
279 case 0U:
280 __fallthrough;
281 case 1U:
282 __fallthrough;
283 case 2U:
284 /* GPIO 0-2*/
285 switch (func) {
286 case AXP192_GPIO_FUNC_INPUT:
287 reg_cfg = AXP192_GPIO012_FUNC_VAL_INPUT;
288 break;
289 case AXP192_GPIO_FUNC_OUTPUT_OD:
290 reg_cfg = AXP192_GPIO012_FUNC_VAL_OUTPUT_OD;
291 is_output = true;
292 break;
293 case AXP192_GPIO_FUNC_OUTPUT_LOW:
294 reg_cfg = AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW;
295 is_output = true;
296 break;
297 case AXP192_GPIO_FUNC_LDO:
298 if (gpio == 0) {
299 /* LDO is only applicable on GPIO0 */
300 reg_cfg = AXP192_GPIO012_FUNC_VAL_LDO;
301 } else {
302 ret = -ENOTSUP;
303 }
304 break;
305 case AXP192_GPIO_FUNC_ADC:
306 reg_cfg = AXP192_GPIO012_FUNC_VAL_ADC;
307 break;
308 case AXP192_GPIO_FUNC_FLOAT:
309 reg_cfg = AXP192_GPIO012_FUNC_VAL_FLOAT;
310 break;
311 default:
312 ret = -ENOTSUP;
313 break;
314 }
315 break;
316
317 case 3U:
318 /* GPIO3 */
319 switch (func) {
320 case AXP192_GPIO_FUNC_INPUT:
321 reg_cfg = AXP192_GPIO3_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA;
322 break;
323 case AXP192_GPIO_FUNC_OUTPUT_OD:
324 reg_cfg = AXP192_GPIO3_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA;
325 is_output = true;
326 break;
327 case AXP192_GPIO_FUNC_CHARGE_CTL:
328 reg_cfg = AXP192_GPIO3_FUNC_VAL_CHARGE_CTL;
329 break;
330 default:
331 ret = -ENOTSUP;
332 break;
333 }
334 break;
335
336 case 4U:
337 /* GPIO4 */
338 switch (func) {
339 case AXP192_GPIO_FUNC_INPUT:
340 reg_cfg = AXP192_GPIO4_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA;
341 break;
342 case AXP192_GPIO_FUNC_OUTPUT_OD:
343 reg_cfg = AXP192_GPIO4_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA;
344 is_output = true;
345 break;
346 case AXP192_GPIO_FUNC_ADC:
347 reg_cfg = AXP192_GPIO4_FUNC_VAL_ADC | AXP192_GPIO34_FUNC_ENA;
348 break;
349 case AXP192_GPIO_FUNC_CHARGE_CTL:
350 reg_cfg = AXP192_GPIO4_FUNC_VAL_CHARGE_CTL;
351 break;
352 default:
353 ret = -ENOTSUP;
354 break;
355 }
356 break;
357
358 default:
359 ret = -EINVAL;
360 }
361 if (ret != 0) {
362 LOG_ERR("Invalid function (0x%x) for gpio %d", func, gpio);
363 return ret;
364 }
365
366 ret = i2c_reg_update_byte_dt(&(config->i2c), gpio_reg_desc[gpio].reg,
367 gpio_reg_desc[gpio].mask, reg_cfg);
368 if (ret != 0) {
369 return ret;
370 }
371
372 /* Save gpio configuration state */
373 data->gpio_mask_used[gpio] = client_dev;
374 if (is_output) {
375 data->gpio_mask_output |= (1u << gpio);
376 } else {
377 data->gpio_mask_output &= ~(1u << gpio);
378 }
379 LOG_DBG("GPIO %d configured successfully (func=0x%x)", gpio, reg_cfg);
380
381 return 0;
382 }
383
mfd_axp192_gpio_pd_get(const struct device * dev,uint8_t gpio,bool * enabled)384 int mfd_axp192_gpio_pd_get(const struct device *dev, uint8_t gpio, bool *enabled)
385 {
386 const struct mfd_axp192_config *config = dev->config;
387 uint8_t gpio_val;
388 uint8_t pd_reg_mask = 0;
389 int ret = 0;
390
391 switch (gpio) {
392 case 0U:
393 pd_reg_mask = AXP192_GPIO0_PULLDOWN_ENABLE;
394 break;
395 case 1U:
396 pd_reg_mask = AXP192_GPIO1_PULLDOWN_ENABLE;
397 break;
398 case 2U:
399 pd_reg_mask = AXP192_GPIO2_PULLDOWN_ENABLE;
400 break;
401
402 case 3U:
403 __fallthrough;
404 case 4U:
405 __fallthrough;
406 case 5U:
407 LOG_DBG("Pull-Down not support on gpio %d", gpio);
408 return -ENOTSUP;
409
410 default:
411 LOG_ERR("Invalid gpio (%d)", gpio);
412 return -EINVAL;
413 }
414
415 ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_GPIO012_REG_PULLDOWN, &gpio_val);
416
417 if (ret == 0) {
418 *enabled = ((gpio_val & pd_reg_mask) != 0);
419 LOG_DBG("Pull-Down stats of gpio %d: %d", gpio, *enabled);
420 }
421
422 return 0;
423 }
424
mfd_axp192_gpio_pd_ctrl(const struct device * dev,uint8_t gpio,bool enable)425 int mfd_axp192_gpio_pd_ctrl(const struct device *dev, uint8_t gpio, bool enable)
426 {
427 uint8_t reg_pd_val = 0;
428 uint8_t reg_pd_mask = 0;
429 const struct mfd_axp192_config *config = dev->config;
430 int ret = 0;
431
432 /* Configure pull-down. Pull-down is only supported by GPIO3 and GPIO4 */
433 switch (gpio) {
434 case 0U:
435 reg_pd_mask = AXP192_GPIO0_PULLDOWN_ENABLE;
436 if (enable) {
437 reg_pd_val = AXP192_GPIO0_PULLDOWN_ENABLE;
438 }
439 break;
440
441 case 1U:
442 reg_pd_mask = AXP192_GPIO1_PULLDOWN_ENABLE;
443 if (enable) {
444 reg_pd_val = AXP192_GPIO1_PULLDOWN_ENABLE;
445 }
446 break;
447
448 case 2U:
449 reg_pd_mask = AXP192_GPIO2_PULLDOWN_ENABLE;
450 if (enable) {
451 reg_pd_val = AXP192_GPIO2_PULLDOWN_ENABLE;
452 }
453 break;
454
455 case 3U:
456 __fallthrough;
457 case 4U:
458 __fallthrough;
459 case 5U:
460 LOG_ERR("Pull-Down not support on gpio %d", gpio);
461 return -ENOTSUP;
462
463 default:
464 LOG_ERR("Invalid gpio (%d)", gpio);
465 return -EINVAL;
466 }
467
468 ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_GPIO012_REG_PULLDOWN, reg_pd_mask,
469 reg_pd_val);
470
471 return ret;
472 }
473
mfd_axp192_gpio_read_port(const struct device * dev,uint8_t * value)474 int mfd_axp192_gpio_read_port(const struct device *dev, uint8_t *value)
475 {
476 const struct mfd_axp192_config *config = dev->config;
477 const struct mfd_axp192_data *data = dev->data;
478 int ret;
479 uint8_t gpio012_val;
480 uint8_t gpio34_val;
481 uint8_t gpio_input_val;
482 uint8_t gpio_output_val;
483
484 /* read gpio0-2 */
485 ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_GPIO012_REG_PINVAL, &gpio012_val);
486 if (ret != 0) {
487 return ret;
488 }
489
490 /* read gpio3-4 */
491 ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_GPIO34_REG_PINVAL, &gpio34_val);
492 if (ret != 0) {
493 return ret;
494 }
495 LOG_DBG("GPIO012 pinval-reg=0x%x", gpio012_val);
496 LOG_DBG("GPIO34 pinval-reg =0x%x", gpio34_val);
497 LOG_DBG("Output-Mask =0x%x", data->gpio_mask_output);
498
499 gpio_input_val =
500 ((gpio012_val & AXP192_GPIO012_INTPUT_MASK) >> AXP192_GPIO012_INTPUT_SHIFT);
501 gpio_input_val |=
502 (((gpio34_val & AXP192_GPIO34_INTPUT_MASK) >> AXP192_GPIO34_INTPUT_SHIFT) << 3u);
503
504 gpio_output_val = (gpio012_val & AXP192_GPIO012_OUTPUT_MASK);
505 gpio_output_val |= ((gpio34_val & AXP192_GPIO34_OUTPUT_MASK) << 3u);
506
507 *value = gpio_input_val & ~(data->gpio_mask_output);
508 *value |= (gpio_output_val & data->gpio_mask_output);
509
510 return 0;
511 }
512
mfd_axp192_gpio_write_port(const struct device * dev,uint8_t value,uint8_t mask)513 int mfd_axp192_gpio_write_port(const struct device *dev, uint8_t value, uint8_t mask)
514 {
515 const struct mfd_axp192_config *config = dev->config;
516 int ret;
517 uint8_t gpio_reg_val;
518 uint8_t gpio_reg_mask;
519
520 /* Write gpio0-2. Mask out other port pins */
521 gpio_reg_val = (value & AXP192_GPIO012_OUTPUT_MASK);
522 gpio_reg_mask = mask & AXP192_GPIO012_OUTPUT_MASK;
523 if (gpio_reg_mask != 0) {
524 ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_GPIO012_REG_PINVAL,
525 gpio_reg_mask, gpio_reg_val);
526 if (ret != 0) {
527 return ret;
528 }
529 LOG_DBG("GPIO012 pinval-reg=0x%x mask=0x%x", gpio_reg_val, gpio_reg_mask);
530 }
531
532 /* Write gpio3-4. Mask out other port pins */
533 gpio_reg_val = value >> 3U;
534 gpio_reg_mask = (mask >> 3U) & AXP192_GPIO34_OUTPUT_MASK;
535 if (gpio_reg_mask != 0) {
536 ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_GPIO34_REG_PINVAL,
537 gpio_reg_mask, gpio_reg_val);
538 if (ret != 0) {
539 return ret;
540 }
541 LOG_DBG("GPIO34 pinval-reg =0x%x mask=0x%x", gpio_reg_val, gpio_reg_mask);
542 }
543
544 return 0;
545 }
546
547 #define MFD_AXP192_DEFINE(inst) \
548 static const struct mfd_axp192_config config##inst = { \
549 .i2c = I2C_DT_SPEC_INST_GET(inst), \
550 }; \
551 \
552 static struct mfd_axp192_data data##inst; \
553 \
554 DEVICE_DT_INST_DEFINE(inst, mfd_axp192_init, NULL, &data##inst, &config##inst, \
555 POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL);
556
557 DT_INST_FOREACH_STATUS_OKAY(MFD_AXP192_DEFINE)
558