From 460f2d04faf807e079c081b25a4d13ddb7229c00 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Dec 2022 12:34:16 +0100 Subject: [PATCH] samples: shields: npm6001_ek: add utility to test regulators Add a utility sub-shell to test all regulators embedded in the nPM6001 PMIC. Signed-off-by: Gerard Marull-Paretas --- samples/shields/npm6001_ek/doc/index.rst | 63 ++++++ samples/shields/npm6001_ek/src/main.c | 254 +++++++++++++++++++++++ 2 files changed, 317 insertions(+) diff --git a/samples/shields/npm6001_ek/doc/index.rst b/samples/shields/npm6001_ek/doc/index.rst index b91db245863..a7954c45b82 100644 --- a/samples/shields/npm6001_ek/doc/index.rst +++ b/samples/shields/npm6001_ek/doc/index.rst @@ -10,6 +10,7 @@ This sample is provided as an example to test the :ref:`npm6001_ek`. The sample provides a shell interface that allows to test multiple functionalities offered by the nPM6001 PMIC, including: +- Regulators (BUCK0/1/2/3 and LDO0/1) - GPIO - Watchdog @@ -41,6 +42,68 @@ Note that this sample automatically sets ``SHIELD`` to ``npm6001_ek``. Once flashed, you should boot into the shell interface. The ``npm6001`` command is provided to test the PMIC. Below you can find details for each subcommand. +Regulators +========== + +The ``npm6001`` shell interface provides the ``regulator`` subcommand to test +the regulators embedded in the PMIC (BUCK0/1/2/3 and LDO0/1). Below you can +find some command examples. + +.. code-block:: bash + + # list all the available regulators + npm6001 regulator list + BUCK0 + BUCK1 + BUCK2 + BUCK3 + LDO0 + LDO1 + +.. code-block:: bash + + # list all the supported voltages by BUCK2 + npm6001 regulator voltages BUCK2 + 1200 mV + 1250 mV + 1300 mV + 1350 mV + 1400 mV + +.. code-block:: bash + + # enable BUCK3 + npm6001 regulator enable BUCK3 + # disable BUCK3 + npm6001 regulator disable BUCK3 + +.. code-block:: bash + + # set BUCK3 voltage to exactly 3000 mV + npm6001 regulator set BUCK3 3000 + # obtain the actual BUCK3 configured voltage + npm6001 regulator get BUCK3 + 3000 mV + # set BUCK0 voltage to a value between 2350 mV and 2450 mV + npm6001 regulator set BUCK0 2350 2450 + # obtain the actual BUCK0 configured voltage + npm6001 regulator get BUCK3 + 2400 mV + +.. code-block:: bash + + # set BUCK0 to hysteretic mode + npm6001 regulator modeset BUCK0 hys + # set BUCK0 to PWM mode + npm6001 regulator modeset BUCK0 pwm + +.. code-block:: bash + + # get active errors on BUCK0 + npm6001 regulator errors BUCK0 + Overcurrent: [ ] + Overtemp.: [ ] + GPIO ==== diff --git a/samples/shields/npm6001_ek/src/main.c b/samples/shields/npm6001_ek/src/main.c index 45db22dd1dd..08b62b760b2 100644 --- a/samples/shields/npm6001_ek/src/main.c +++ b/samples/shields/npm6001_ek/src/main.c @@ -7,16 +7,42 @@ #include #include +#include #include #include +#include #include #include #include #include +struct regulators_map { + const char *name; + const struct device *dev; +}; + static const struct device *const gpio = DEVICE_DT_GET_ONE(nordic_npm6001_gpio); static const struct device *const wdt = DEVICE_DT_GET_ONE(nordic_npm6001_wdt); +static const struct regulators_map regulators[] = { + { "BUCK0", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck0)) }, + { "BUCK1", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck1)) }, + { "BUCK2", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck2)) }, + { "BUCK3", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_buck3)) }, + { "LDO0", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_ldo0)) }, + { "LDO1", DEVICE_DT_GET_OR_NULL(DT_NODELABEL(npm6001_ek_ldo1)) }, +}; + +static const struct device *name2reg(const char *name) +{ + for (size_t i = 0U; i < ARRAY_SIZE(regulators); i++) { + if (strcmp(name, regulators[i].name) == 0) { + return regulators[i].dev; + } + } + + return NULL; +} void main(void) { @@ -29,6 +55,213 @@ void main(void) printk("nPM6001 Watchdog device not ready\n"); return; } + + for (size_t i = 0U; i < ARRAY_SIZE(regulators); i++) { + if ((regulators[i].dev != NULL) && + !device_is_ready(regulators[i].dev)) { + printk("nPM6001 %s regulator device not ready\n", + regulators[i].name); + return; + } + } +} + +static int cmd_regulator_list(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + for (size_t i = 0U; i < ARRAY_SIZE(regulators); i++) { + if (regulators[i].dev != NULL) { + shell_print(sh, "%s", regulators[i].name); + } + } + + return 0; +} + +static int cmd_regulator_voltages(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + unsigned int volt_cnt; + + ARG_UNUSED(argc); + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + volt_cnt = regulator_count_voltages(dev); + + for (unsigned int i = 0U; i < volt_cnt; i++) { + int32_t volt_uv; + + (void)regulator_list_voltage(dev, i, &volt_uv); + shell_print(sh, "%d mV", volt_uv / 1000); + } + + return 0; +} + +static int cmd_regulator_enable(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int ret; + + ARG_UNUSED(argc); + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + ret = regulator_enable(dev); + if (ret < 0) { + shell_error(sh, "Could not enable regulator (%d)", ret); + return ret; + } + + return 0; +} + +static int cmd_regulator_disable(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int ret; + + ARG_UNUSED(argc); + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + ret = regulator_disable(dev); + if (ret < 0) { + shell_error(sh, "Could not disable regulator (%d)", ret); + return ret; + } + + return 0; +} + +static int cmd_regulator_set(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int32_t min_uv, max_uv; + int ret; + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + min_uv = (int32_t)strtoul(argv[2], NULL, 10) * 1000; + if (argc == 4) { + max_uv = (int32_t)strtoul(argv[3], NULL, 10) * 1000; + } else { + max_uv = min_uv; + } + + ret = regulator_set_voltage(dev, min_uv, max_uv); + if (ret < 0) { + shell_error(sh, "Could not set voltage (%d)", ret); + return ret; + } + + return 0; +} + +static int cmd_regulator_get(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int32_t volt_uv; + int ret; + + ARG_UNUSED(argc); + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + volt_uv = (int32_t)strtoul(argv[1], NULL, 10) * 1000; + + ret = regulator_get_voltage(dev, &volt_uv); + if (ret < 0) { + shell_error(sh, "Could not get voltage (%d)", ret); + return ret; + } + + shell_print(sh, "%d mV", volt_uv / 1000); + + return 0; +} + +static int cmd_regulator_modeset(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + regulator_mode_t mode; + int ret; + + ARG_UNUSED(argc); + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + if (strcmp(argv[2], "pwm") == 0) { + mode = NPM6001_MODE_PWM; + } else if (strcmp(argv[2], "hys") == 0) { + mode = NPM6001_MODE_HYS; + } else { + shell_error(sh, "Invalid mode: %s", argv[1]); + return -EINVAL; + } + + ret = regulator_set_mode(dev, mode); + if (ret < 0) { + shell_error(sh, "Could not set mode (%d)", ret); + return ret; + } + + return 0; +} + +static int cmd_regulator_errors(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + regulator_error_flags_t errors; + int ret; + + ARG_UNUSED(argc); + + dev = name2reg(argv[1]); + if (dev == NULL) { + shell_error(sh, "Invalid regulator: %s", argv[1]); + return -ENODEV; + } + + ret = regulator_get_error_flags(dev, &errors); + if (ret < 0) { + shell_error(sh, "Could not get error flags (%d)", ret); + return ret; + } + + shell_print(sh, "Overcurrent:\t[%s]", + ((errors & REGULATOR_ERROR_OVER_CURRENT) != 0U) ? "X" : " "); + shell_print(sh, "Overtemp.:\t[%s]", + ((errors & REGULATOR_ERROR_OVER_TEMP) != 0U) ? "X" : " "); + + return 0; } static int cmd_gpio_configure(const struct shell *sh, size_t argc, char **argv) @@ -190,6 +423,25 @@ static int cmd_wdt_kick(const struct shell *sh, size_t argc, char **argv) return 0; } +SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_regulator_cmds, + SHELL_CMD(list, NULL, "List regulator names", + cmd_regulator_list), + SHELL_CMD_ARG(voltages, NULL, "List voltages", + cmd_regulator_voltages, 2, 0), + SHELL_CMD_ARG(enable, NULL, "Enable regulator", + cmd_regulator_enable, 2, 0), + SHELL_CMD_ARG(disable, NULL, "Disable regulator", + cmd_regulator_disable, 2, 0), + SHELL_CMD_ARG(set, NULL, "Set voltage", + cmd_regulator_set, 3, 1), + SHELL_CMD_ARG(get, NULL, "Get voltage", + cmd_regulator_get, 2, 0), + SHELL_CMD_ARG(modeset, NULL, "Set mode PWM/HYS", + cmd_regulator_modeset, 3, 0), + SHELL_CMD_ARG(errors, NULL, "Get active errors", + cmd_regulator_errors, 2, 0), + SHELL_SUBCMD_SET_END); + SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_gpio_cmds, SHELL_CMD_ARG(configure, NULL, "Configure GPIO", cmd_gpio_configure, 5, 3), @@ -211,6 +463,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_wdt_cmds, SHELL_SUBCMD_SET_END); SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_cmds, + SHELL_CMD(regulator, &sub_npm6001_regulator_cmds, + "Regulators", NULL), SHELL_CMD(gpio, &sub_npm6001_gpio_cmds, "GPIO", NULL), SHELL_CMD(wdt, &sub_npm6001_wdt_cmds, "Watchdog",