/* * Copyright (c) 2022 Nordic Semiconductor ASA * SPDX-License-Identifier: Apache-2.0 */ #include #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; } int main(void) { if (!device_is_ready(gpio)) { printk("nPM6001 GPIO device not ready\n"); return 0; } if (!device_is_ready(wdt)) { printk("nPM6001 Watchdog device not ready\n"); return 0; } 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 0; } } return 0; } 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; } 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_modeget(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; } ret = regulator_get_mode(dev, &mode); if (ret < 0) { shell_error(sh, "Could not get mode (%d)", ret); return ret; } if (mode == NPM6001_MODE_PWM) { shell_print(sh, "PWM"); } else if (mode == NPM6001_MODE_HYS) { shell_print(sh, "Hysteretic"); } else { shell_error(sh, "Invalid mode: %u", mode); return -EINVAL; } 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) { int ret; int opt, long_index = 0; static int high_drive, pull_down, cmos; gpio_pin_t pin = 0U; gpio_flags_t flags = 0U; static const struct option long_options[] = { {"pin", required_argument, NULL, 'p'}, {"direction", required_argument, NULL, 'd'}, {"high-drive", no_argument, &high_drive, 1}, {"pull-down", no_argument, &pull_down, 1}, {"cmos", no_argument, &cmos, 1}, {NULL, 0, NULL, 0}, }; high_drive = 0; pull_down = 0; cmos = 0; while ((opt = getopt_long(argc, argv, "p:d:", long_options, &long_index)) != -1) { switch (opt) { case 0: /* options setting a flag, do nothing */ break; case 'p': pin = atoi(optarg); break; case 'd': if (strcmp(optarg, "in") == 0) { flags |= GPIO_INPUT; } else if (strcmp(optarg, "out") == 0) { flags |= GPIO_OUTPUT; } else if (strcmp(optarg, "outh") == 0) { flags |= GPIO_OUTPUT_HIGH; } else if (strcmp(optarg, "outl") == 0) { flags |= GPIO_OUTPUT_LOW; } break; default: shell_error(sh, "Invalid option: %c", opt); return -EINVAL; } } if (pull_down == 1) { flags |= GPIO_PULL_DOWN; } if (high_drive == 1) { flags |= NPM6001_GPIO_DRIVE_HIGH; } if (cmos == 1) { flags |= NPM6001_GPIO_SENSE_CMOS; } ret = gpio_pin_configure(gpio, pin, flags); if (ret < 0) { shell_error(sh, "Configuration failed (%d)", ret); return ret; } return 0; } static int cmd_gpio_get(const struct shell *sh, size_t argc, char **argv) { gpio_pin_t pin; int val; pin = (gpio_pin_t)atoi(argv[1]); val = gpio_pin_get(gpio, pin); if (val < 0) { shell_error(sh, "Could not get pin level (%d)", val); return val; } shell_print(sh, "Level: %d", val); return 0; } static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv) { gpio_pin_t pin; int val; int ret; pin = (gpio_pin_t)atoi(argv[1]); val = atoi(argv[2]); ret = gpio_pin_set(gpio, pin, val); if (ret < 0) { shell_error(sh, "Could not set pin level (%d)", ret); return ret; } return 0; } static int cmd_gpio_toggle(const struct shell *sh, size_t argc, char **argv) { gpio_pin_t pin; int ret; pin = (gpio_pin_t)atoi(argv[1]); ret = gpio_pin_toggle(gpio, pin); if (ret < 0) { shell_error(sh, "Could not toggle pin level (%d)", ret); return ret; } return 0; } static int cmd_wdt_enable(const struct shell *sh, size_t argc, char **argv) { int ret; struct wdt_timeout_cfg cfg = { 0 }; cfg.window.max = (uint32_t)strtoul(argv[1], NULL, 10) * 1000U; ret = wdt_install_timeout(wdt, &cfg); if (ret < 0) { shell_error(sh, "Could not install watchdog timeout (%d)", ret); } return 0; } static int cmd_wdt_disable(const struct shell *sh, size_t argc, char **argv) { int ret; ret = wdt_disable(wdt); if (ret < 0) { shell_error(sh, "Could not disable watchdog (%d)", ret); } return 0; } static int cmd_wdt_kick(const struct shell *sh, size_t argc, char **argv) { int ret; ret = wdt_feed(wdt, 0); if (ret < 0) { shell_error(sh, "Could not kick watchdog (%d)", ret); } 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(modeget, NULL, "Get mode PWM/HYS", cmd_regulator_modeget, 2, 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), SHELL_CMD_ARG(get, NULL, "Get GPIO level", cmd_gpio_get, 2, 0), SHELL_CMD_ARG(set, NULL, "Set GPIO level", cmd_gpio_set, 3, 0), SHELL_CMD_ARG(toggle, NULL, "Toggle GPIO level", cmd_gpio_toggle, 2, 0), SHELL_SUBCMD_SET_END); SHELL_STATIC_SUBCMD_SET_CREATE(sub_npm6001_wdt_cmds, SHELL_CMD_ARG(enable, NULL, "Enable watchdog", cmd_wdt_enable, 2, 0), SHELL_CMD(disable, NULL, "Disable watchdog", cmd_wdt_disable), SHELL_CMD(kick, NULL, "Kick watchdog", cmd_wdt_kick), 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", NULL), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(npm6001, &sub_npm6001_cmds, "nPM6001 commands", NULL);