1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <stdlib.h>
7
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/regulator.h>
11 #include <zephyr/drivers/watchdog.h>
12 #include <zephyr/dt-bindings/gpio/nordic-npm6001-gpio.h>
13 #include <zephyr/dt-bindings/regulator/npm6001.h>
14 #include <zephyr/posix/unistd.h>
15 #include <zephyr/shell/shell.h>
16 #include <zephyr/sys/printk.h>
17
18 #include <getopt.h>
19
20 struct regulators_map {
21 const char *name;
22 const struct device *dev;
23 };
24
25 static const struct device *const gpio = DEVICE_DT_GET_ONE(nordic_npm6001_gpio);
26 static const struct device *const wdt = DEVICE_DT_GET_ONE(nordic_npm6001_wdt);
27 static const struct regulators_map regulators[] = {
28 { "BUCK0", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck0)) },
29 { "BUCK1", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck1)) },
30 { "BUCK2", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck2)) },
31 { "BUCK3", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck3)) },
32 { "LDO0", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_ldo0)) },
33 { "LDO1", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_ldo1)) },
34 };
35
name2reg(const char * name)36 static const struct device *name2reg(const char *name)
37 {
38 for (size_t i = 0U; i < ARRAY_SIZE(regulators); i++) {
39 if (strcmp(name, regulators[i].name) == 0) {
40 return regulators[i].dev;
41 }
42 }
43
44 return NULL;
45 }
46
main(void)47 int main(void)
48 {
49 if (!device_is_ready(gpio)) {
50 printk("nPM6001 GPIO device not ready\n");
51 return 0;
52 }
53
54 if (!device_is_ready(wdt)) {
55 printk("nPM6001 Watchdog device not ready\n");
56 return 0;
57 }
58
59 for (size_t i = 0U; i < ARRAY_SIZE(regulators); i++) {
60 if ((regulators[i].dev != NULL) &&
61 !device_is_ready(regulators[i].dev)) {
62 printk("nPM6001 %s regulator device not ready\n",
63 regulators[i].name);
64 return 0;
65 }
66 }
67 return 0;
68 }
69
cmd_regulator_list(const struct shell * sh,size_t argc,char ** argv)70 static int cmd_regulator_list(const struct shell *sh, size_t argc, char **argv)
71 {
72 ARG_UNUSED(argc);
73 ARG_UNUSED(argv);
74
75 for (size_t i = 0U; i < ARRAY_SIZE(regulators); i++) {
76 if (regulators[i].dev != NULL) {
77 shell_print(sh, "%s", regulators[i].name);
78 }
79 }
80
81 return 0;
82 }
83
cmd_regulator_voltages(const struct shell * sh,size_t argc,char ** argv)84 static int cmd_regulator_voltages(const struct shell *sh, size_t argc, char **argv)
85 {
86 const struct device *dev;
87 unsigned int volt_cnt;
88
89 ARG_UNUSED(argc);
90
91 dev = name2reg(argv[1]);
92 if (dev == NULL) {
93 shell_error(sh, "Invalid regulator: %s", argv[1]);
94 return -ENODEV;
95 }
96
97 volt_cnt = regulator_count_voltages(dev);
98
99 for (unsigned int i = 0U; i < volt_cnt; i++) {
100 int32_t volt_uv;
101
102 (void)regulator_list_voltage(dev, i, &volt_uv);
103 shell_print(sh, "%d mV", volt_uv / 1000);
104 }
105
106 return 0;
107 }
108
cmd_regulator_enable(const struct shell * sh,size_t argc,char ** argv)109 static int cmd_regulator_enable(const struct shell *sh, size_t argc, char **argv)
110 {
111 const struct device *dev;
112 int ret;
113
114 ARG_UNUSED(argc);
115
116 dev = name2reg(argv[1]);
117 if (dev == NULL) {
118 shell_error(sh, "Invalid regulator: %s", argv[1]);
119 return -ENODEV;
120 }
121
122 ret = regulator_enable(dev);
123 if (ret < 0) {
124 shell_error(sh, "Could not enable regulator (%d)", ret);
125 return ret;
126 }
127
128 return 0;
129 }
130
cmd_regulator_disable(const struct shell * sh,size_t argc,char ** argv)131 static int cmd_regulator_disable(const struct shell *sh, size_t argc, char **argv)
132 {
133 const struct device *dev;
134 int ret;
135
136 ARG_UNUSED(argc);
137
138 dev = name2reg(argv[1]);
139 if (dev == NULL) {
140 shell_error(sh, "Invalid regulator: %s", argv[1]);
141 return -ENODEV;
142 }
143
144 ret = regulator_disable(dev);
145 if (ret < 0) {
146 shell_error(sh, "Could not disable regulator (%d)", ret);
147 return ret;
148 }
149
150 return 0;
151 }
152
cmd_regulator_set(const struct shell * sh,size_t argc,char ** argv)153 static int cmd_regulator_set(const struct shell *sh, size_t argc, char **argv)
154 {
155 const struct device *dev;
156 int32_t min_uv, max_uv;
157 int ret;
158
159 dev = name2reg(argv[1]);
160 if (dev == NULL) {
161 shell_error(sh, "Invalid regulator: %s", argv[1]);
162 return -ENODEV;
163 }
164
165 min_uv = (int32_t)strtoul(argv[2], NULL, 10) * 1000;
166 if (argc == 4) {
167 max_uv = (int32_t)strtoul(argv[3], NULL, 10) * 1000;
168 } else {
169 max_uv = min_uv;
170 }
171
172 ret = regulator_set_voltage(dev, min_uv, max_uv);
173 if (ret < 0) {
174 shell_error(sh, "Could not set voltage (%d)", ret);
175 return ret;
176 }
177
178 return 0;
179 }
180
cmd_regulator_get(const struct shell * sh,size_t argc,char ** argv)181 static int cmd_regulator_get(const struct shell *sh, size_t argc, char **argv)
182 {
183 const struct device *dev;
184 int32_t volt_uv;
185 int ret;
186
187 ARG_UNUSED(argc);
188
189 dev = name2reg(argv[1]);
190 if (dev == NULL) {
191 shell_error(sh, "Invalid regulator: %s", argv[1]);
192 return -ENODEV;
193 }
194
195 ret = regulator_get_voltage(dev, &volt_uv);
196 if (ret < 0) {
197 shell_error(sh, "Could not get voltage (%d)", ret);
198 return ret;
199 }
200
201 shell_print(sh, "%d mV", volt_uv / 1000);
202
203 return 0;
204 }
205
cmd_regulator_modeset(const struct shell * sh,size_t argc,char ** argv)206 static int cmd_regulator_modeset(const struct shell *sh, size_t argc, char **argv)
207 {
208 const struct device *dev;
209 regulator_mode_t mode;
210 int ret;
211
212 ARG_UNUSED(argc);
213
214 dev = name2reg(argv[1]);
215 if (dev == NULL) {
216 shell_error(sh, "Invalid regulator: %s", argv[1]);
217 return -ENODEV;
218 }
219
220 if (strcmp(argv[2], "pwm") == 0) {
221 mode = NPM6001_MODE_PWM;
222 } else if (strcmp(argv[2], "hys") == 0) {
223 mode = NPM6001_MODE_HYS;
224 } else {
225 shell_error(sh, "Invalid mode: %s", argv[1]);
226 return -EINVAL;
227 }
228
229 ret = regulator_set_mode(dev, mode);
230 if (ret < 0) {
231 shell_error(sh, "Could not set mode (%d)", ret);
232 return ret;
233 }
234
235 return 0;
236 }
237
cmd_regulator_modeget(const struct shell * sh,size_t argc,char ** argv)238 static int cmd_regulator_modeget(const struct shell *sh, size_t argc, char **argv)
239 {
240 const struct device *dev;
241 regulator_mode_t mode;
242 int ret;
243
244 ARG_UNUSED(argc);
245
246 dev = name2reg(argv[1]);
247 if (dev == NULL) {
248 shell_error(sh, "Invalid regulator: %s", argv[1]);
249 return -ENODEV;
250 }
251
252 ret = regulator_get_mode(dev, &mode);
253 if (ret < 0) {
254 shell_error(sh, "Could not get mode (%d)", ret);
255 return ret;
256 }
257
258 if (mode == NPM6001_MODE_PWM) {
259 shell_print(sh, "PWM");
260 } else if (mode == NPM6001_MODE_HYS) {
261 shell_print(sh, "Hysteretic");
262 } else {
263 shell_error(sh, "Invalid mode: %u", mode);
264 return -EINVAL;
265 }
266
267 return 0;
268 }
269
cmd_regulator_errors(const struct shell * sh,size_t argc,char ** argv)270 static int cmd_regulator_errors(const struct shell *sh, size_t argc, char **argv)
271 {
272 const struct device *dev;
273 regulator_error_flags_t errors;
274 int ret;
275
276 ARG_UNUSED(argc);
277
278 dev = name2reg(argv[1]);
279 if (dev == NULL) {
280 shell_error(sh, "Invalid regulator: %s", argv[1]);
281 return -ENODEV;
282 }
283
284 ret = regulator_get_error_flags(dev, &errors);
285 if (ret < 0) {
286 shell_error(sh, "Could not get error flags (%d)", ret);
287 return ret;
288 }
289
290 shell_print(sh, "Overcurrent:\t[%s]",
291 ((errors & REGULATOR_ERROR_OVER_CURRENT) != 0U) ? "X" : " ");
292 shell_print(sh, "Overtemp.:\t[%s]",
293 ((errors & REGULATOR_ERROR_OVER_TEMP) != 0U) ? "X" : " ");
294
295 return 0;
296 }
297
cmd_gpio_configure(const struct shell * sh,size_t argc,char ** argv)298 static int cmd_gpio_configure(const struct shell *sh, size_t argc, char **argv)
299 {
300 int ret;
301 int opt, long_index = 0;
302 static int high_drive, pull_down, cmos;
303 gpio_pin_t pin = 0U;
304 gpio_flags_t flags = 0U;
305
306 static const struct option long_options[] = {
307 {"pin", required_argument, NULL, 'p'},
308 {"direction", required_argument, NULL, 'd'},
309 {"high-drive", no_argument, &high_drive, 1},
310 {"pull-down", no_argument, &pull_down, 1},
311 {"cmos", no_argument, &cmos, 1},
312 {NULL, 0, NULL, 0},
313 };
314
315 high_drive = 0;
316 pull_down = 0;
317 cmos = 0;
318
319 while ((opt = getopt_long(argc, argv, "p:d:", long_options,
320 &long_index)) != -1) {
321 switch (opt) {
322 case 0:
323 /* options setting a flag, do nothing */
324 break;
325 case 'p':
326 pin = atoi(optarg);
327 break;
328 case 'd':
329 if (strcmp(optarg, "in") == 0) {
330 flags |= GPIO_INPUT;
331 } else if (strcmp(optarg, "out") == 0) {
332 flags |= GPIO_OUTPUT;
333 } else if (strcmp(optarg, "outh") == 0) {
334 flags |= GPIO_OUTPUT_HIGH;
335 } else if (strcmp(optarg, "outl") == 0) {
336 flags |= GPIO_OUTPUT_LOW;
337 }
338 break;
339 default:
340 shell_error(sh, "Invalid option: %c", opt);
341 return -EINVAL;
342 }
343 }
344
345 if (pull_down == 1) {
346 flags |= GPIO_PULL_DOWN;
347 }
348
349 if (high_drive == 1) {
350 flags |= NPM6001_GPIO_DRIVE_HIGH;
351 }
352
353 if (cmos == 1) {
354 flags |= NPM6001_GPIO_SENSE_CMOS;
355 }
356
357 ret = gpio_pin_configure(gpio, pin, flags);
358 if (ret < 0) {
359 shell_error(sh, "Configuration failed (%d)", ret);
360 return ret;
361 }
362
363 return 0;
364 }
365
cmd_gpio_get(const struct shell * sh,size_t argc,char ** argv)366 static int cmd_gpio_get(const struct shell *sh, size_t argc, char **argv)
367 {
368 gpio_pin_t pin;
369 int val;
370
371 pin = (gpio_pin_t)atoi(argv[1]);
372
373 val = gpio_pin_get(gpio, pin);
374 if (val < 0) {
375 shell_error(sh, "Could not get pin level (%d)", val);
376 return val;
377 }
378
379 shell_print(sh, "Level: %d", val);
380
381 return 0;
382 }
383
cmd_gpio_set(const struct shell * sh,size_t argc,char ** argv)384 static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv)
385 {
386 gpio_pin_t pin;
387 int val;
388 int ret;
389
390 pin = (gpio_pin_t)atoi(argv[1]);
391 val = atoi(argv[2]);
392
393 ret = gpio_pin_set(gpio, pin, val);
394 if (ret < 0) {
395 shell_error(sh, "Could not set pin level (%d)", ret);
396 return ret;
397 }
398
399 return 0;
400 }
401
cmd_gpio_toggle(const struct shell * sh,size_t argc,char ** argv)402 static int cmd_gpio_toggle(const struct shell *sh, size_t argc, char **argv)
403 {
404 gpio_pin_t pin;
405 int ret;
406
407 pin = (gpio_pin_t)atoi(argv[1]);
408
409 ret = gpio_pin_toggle(gpio, pin);
410 if (ret < 0) {
411 shell_error(sh, "Could not toggle pin level (%d)", ret);
412 return ret;
413 }
414
415 return 0;
416 }
417
cmd_wdt_enable(const struct shell * sh,size_t argc,char ** argv)418 static int cmd_wdt_enable(const struct shell *sh, size_t argc, char **argv)
419 {
420 int ret;
421 struct wdt_timeout_cfg cfg = { 0 };
422
423 cfg.window.max = (uint32_t)strtoul(argv[1], NULL, 10) * 1000U;
424
425 ret = wdt_install_timeout(wdt, &cfg);
426 if (ret < 0) {
427 shell_error(sh, "Could not install watchdog timeout (%d)", ret);
428 }
429
430 return 0;
431 }
432
cmd_wdt_disable(const struct shell * sh,size_t argc,char ** argv)433 static int cmd_wdt_disable(const struct shell *sh, size_t argc, char **argv)
434 {
435 int ret;
436
437 ret = wdt_disable(wdt);
438 if (ret < 0) {
439 shell_error(sh, "Could not disable watchdog (%d)", ret);
440 }
441
442 return 0;
443 }
444
cmd_wdt_kick(const struct shell * sh,size_t argc,char ** argv)445 static int cmd_wdt_kick(const struct shell *sh, size_t argc, char **argv)
446 {
447 int ret;
448
449 ret = wdt_feed(wdt, 0);
450 if (ret < 0) {
451 shell_error(sh, "Could not kick watchdog (%d)", ret);
452 }
453
454 return 0;
455 }
456
457 SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_regulator_cmds,
458 SHELL_CMD(list, NULL, "List regulator names",
459 cmd_regulator_list),
460 SHELL_CMD_ARG(voltages, NULL, "List voltages",
461 cmd_regulator_voltages, 2, 0),
462 SHELL_CMD_ARG(enable, NULL, "Enable regulator",
463 cmd_regulator_enable, 2, 0),
464 SHELL_CMD_ARG(disable, NULL, "Disable regulator",
465 cmd_regulator_disable, 2, 0),
466 SHELL_CMD_ARG(set, NULL, "Set voltage",
467 cmd_regulator_set, 3, 1),
468 SHELL_CMD_ARG(get, NULL, "Get voltage",
469 cmd_regulator_get, 2, 0),
470 SHELL_CMD_ARG(modeset, NULL, "Set mode PWM/HYS",
471 cmd_regulator_modeset, 3, 0),
472 SHELL_CMD_ARG(modeget, NULL, "Get mode PWM/HYS",
473 cmd_regulator_modeget, 2, 0),
474 SHELL_CMD_ARG(errors, NULL, "Get active errors",
475 cmd_regulator_errors, 2, 0),
476 SHELL_SUBCMD_SET_END);
477
478 SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_gpio_cmds,
479 SHELL_CMD_ARG(configure, NULL, "Configure GPIO",
480 cmd_gpio_configure, 5, 3),
481 SHELL_CMD_ARG(get, NULL, "Get GPIO level",
482 cmd_gpio_get, 2, 0),
483 SHELL_CMD_ARG(set, NULL, "Set GPIO level",
484 cmd_gpio_set, 3, 0),
485 SHELL_CMD_ARG(toggle, NULL, "Toggle GPIO level",
486 cmd_gpio_toggle, 2, 0),
487 SHELL_SUBCMD_SET_END);
488
489 SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_wdt_cmds,
490 SHELL_CMD_ARG(enable, NULL, "Enable watchdog",
491 cmd_wdt_enable, 2, 0),
492 SHELL_CMD(disable, NULL, "Disable watchdog",
493 cmd_wdt_disable),
494 SHELL_CMD(kick, NULL, "Kick watchdog",
495 cmd_wdt_kick),
496 SHELL_SUBCMD_SET_END);
497
498 SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_cmds,
499 SHELL_CMD(regulator, &sub_npm6001_regulator_cmds,
500 "Regulators", NULL),
501 SHELL_CMD(gpio, &sub_npm6001_gpio_cmds, "GPIO",
502 NULL),
503 SHELL_CMD(wdt, &sub_npm6001_wdt_cmds, "Watchdog",
504 NULL),
505 SHELL_SUBCMD_SET_END);
506
507 SHELL_CMD_REGISTER(npm6001, &sub_npm6001_cmds, "nPM6001 commands", NULL);
508