From d89fdcf9cfdfc7ac5eaf57914dabddc0e4018979 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Mon, 20 Apr 2015 20:07:43 +0200 Subject: [PATCH] dm: pmic: add pmic command This is new command for the PMIC devices based on driver model PMIC API. Command features are unchanged: - list UCLASS pmic devices - show or [set] operating pmic device (NEW) - dump registers - read byte of register at address - write byte to register at address The only one change for this command is 'dev' subcommand. Signed-off-by: Przemyslaw Marczak Acked-by: Simon Glass --- common/Kconfig | 14 +++ common/Makefile | 3 + common/cmd_pmic.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 common/cmd_pmic.c diff --git a/common/Kconfig b/common/Kconfig index 15759f75aa..dd123f0a30 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -460,4 +460,18 @@ config BOOTSTAGE_STASH_SIZE endmenu +menu "Power commands" +config CMD_PMIC + bool "Enable Driver Model PMIC command" + depends on DM_PMIC + help + This is the pmic command, based on a driver model pmic's API. + Command features are unchanged: + - list - list pmic devices + - pmic dev - show or [set] operating pmic device (NEW) + - pmic dump - dump registers + - pmic read address - read byte of register at address + - pmic write address - write byte to register at address + The only one change for this command is 'dev' subcommand. +endmenu endmenu diff --git a/common/Makefile b/common/Makefile index 9084c73ad9..425658c4cd 100644 --- a/common/Makefile +++ b/common/Makefile @@ -211,6 +211,9 @@ obj-$(CONFIG_UPDATE_TFTP) += update.o obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o obj-$(CONFIG_CMD_DFU) += cmd_dfu.o obj-$(CONFIG_CMD_GPT) += cmd_gpt.o + +# Power +obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o endif ifdef CONFIG_SPL_BUILD diff --git a/common/cmd_pmic.c b/common/cmd_pmic.c new file mode 100644 index 0000000000..bd88d687cb --- /dev/null +++ b/common/cmd_pmic.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2014-2015 Samsung Electronics + * Przemyslaw Marczak + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include + +#define LIMIT_SEQ 3 +#define LIMIT_DEVNAME 20 + +static struct udevice *currdev; + +static int failed(const char *getset, const char *thing, + const char *for_dev, int ret) +{ + printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing, for_dev, + ret, errno_str(ret)); + return CMD_RET_FAILURE; +} + +static int pmic_dev_get(bool list_only, int get_seq, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + if (devp) + *devp = NULL; + + for (ret = uclass_first_device(UCLASS_PMIC, &dev); dev; + ret = uclass_next_device(&dev)) { + if (list_only) { + printf("|%*d | %-*.*s| %-*.*s| %s @ %d\n", + LIMIT_SEQ, dev->seq, + LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name, + LIMIT_DEVNAME, LIMIT_DEVNAME, dev->parent->name, + dev_get_uclass_name(dev->parent), + dev->parent->seq); + continue; + } + + if (dev->seq == get_seq) { + if (devp) + *devp = dev; + else + return -EINVAL; + + return 0; + } + } + + if (list_only) + return ret; + + return -ENODEV; +} + +static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int seq, ret = -ENODEV; + + switch (argc) { + case 2: + seq = simple_strtoul(argv[1], NULL, 0); + ret = uclass_get_device_by_seq(UCLASS_PMIC, seq, &currdev); + if (ret && (ret = pmic_dev_get(false, seq, &currdev))) + goto failed; + case 1: + if (!currdev) + goto failed; + + printf("dev: %d @ %s\n", currdev->seq, currdev->name); + } + + return CMD_RET_SUCCESS; +failed: + return failed("get", "the", "device", ret); +} + +static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + int ret; + + printf("|%*s | %-*.*s| %-*.*s| %s @ %s\n", + LIMIT_SEQ, "Seq", + LIMIT_DEVNAME, LIMIT_DEVNAME, "Name", + LIMIT_DEVNAME, LIMIT_DEVNAME, "Parent name", + "Parent uclass", "seq"); + + for (ret = uclass_first_device(UCLASS_PMIC, &dev); dev; + ret = uclass_next_device(&dev)) { + printf("|%*d | %-*.*s| %-*.*s| %s @ %d\n", + LIMIT_SEQ, dev->seq, + LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name, + LIMIT_DEVNAME, LIMIT_DEVNAME, dev->parent->name, + dev_get_uclass_name(dev->parent), dev->parent->seq); + } + + if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static int do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + uint8_t value; + uint reg; + int ret; + + if (!currdev) + return failed("get", "current", "device", -ENODEV); + + dev = currdev; + + printf("Dump pmic: %s registers\n", dev->name); + + for (reg = 0; reg < pmic_reg_count(dev); reg++) { + ret = pmic_read(dev, reg, &value, 1); + if (ret) + return failed("read", dev->name, "register", ret); + + if (!(reg % 16)) + printf("\n0x%02x: ", reg); + + printf("%2.2x ", value); + } + printf("\n"); + + return CMD_RET_SUCCESS; +} + +static int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + int regs, ret; + uint8_t value; + uint reg; + + if (!currdev) + return failed("get", "current", "device", -ENODEV); + + dev = currdev; + + if (argc != 2) + return CMD_RET_USAGE; + + reg = simple_strtoul(argv[1], NULL, 0); + regs = pmic_reg_count(dev); + if (reg > regs) { + printf("Pmic max reg: %d\n", regs); + return failed("read", "given", "address", -EFAULT); + } + + ret = pmic_read(dev, reg, &value, 1); + if (ret) + return failed("read", dev->name, "register", ret); + + printf("0x%02x: 0x%2.2x\n", reg, value); + + return CMD_RET_SUCCESS; +} + +static int do_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + int regs, ret; + uint8_t value; + uint reg; + + if (!currdev) + return failed("get", "current", "device", -ENODEV); + + dev = currdev; + + if (argc != 3) + return CMD_RET_USAGE; + + reg = simple_strtoul(argv[1], NULL, 0); + regs = pmic_reg_count(dev); + if (reg > regs) { + printf("Pmic max reg: %d\n", regs); + return failed("write", "given", "address", -EFAULT); + } + + value = simple_strtoul(argv[2], NULL, 0); + + ret = pmic_write(dev, reg, &value, 1); + if (ret) + return failed("write", dev->name, "register", ret); + + return CMD_RET_SUCCESS; +} + +static cmd_tbl_t subcmd[] = { + U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""), + U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""), + U_BOOT_CMD_MKENT(dump, 1, 1, do_dump, "", ""), + U_BOOT_CMD_MKENT(read, 2, 1, do_read, "", ""), + U_BOOT_CMD_MKENT(write, 3, 1, do_write, "", ""), +}; + +static int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + cmd_tbl_t *cmd; + + argc--; + argv++; + + cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd)); + if (cmd == NULL || argc > cmd->maxargs) + return CMD_RET_USAGE; + + return cmd->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD(pmic, CONFIG_SYS_MAXARGS, 1, do_pmic, + " operations", + "list - list pmic devices\n" + "pmic dev [id] - show or [set] operating pmic device\n" + "pmic dump - dump registers\n" + "pmic read address - read byte of register at address\n" + "pmic write address - write byte to register at address\n" +);