blob: ec3e24e3354fd381f9bdc9d32e8681f6a877d694 [file] [log] [blame]
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/regulator.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/dt-bindings/gpio/nordic-npm6001-gpio.h>
#include <zephyr/dt-bindings/regulator/npm6001.h>
#include <zephyr/posix/unistd.h>
#include <zephyr/shell/shell.h>
#include <zephyr/sys/printk.h>
#include <getopt.h>
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);