From: Lothar Waßmann Date: Mon, 13 Mar 2017 15:03:57 +0000 (+0100) Subject: cmd: add support for Qualcomm SPMI bus access X-Git-Tag: KARO-TXSD-2017-03-15~13 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=05a06bc85efddde9c6d114ff120c6ecfd9dee2a9;p=karo-tx-uboot.git cmd: add support for Qualcomm SPMI bus access This patch adds an 'spmi' command for low level access to the SPMI bus similar to the 'i2c' command from which it was inspired. --- diff --git a/cmd/Kconfig b/cmd/Kconfig index 86554ea362..17808de716 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -388,7 +388,7 @@ config CMD_SF SPI Flash support config CMD_SPI - bool "sspi" + bool "spi" help SPI utility command. @@ -431,6 +431,11 @@ config CMD_GPIO help GPIO support. +config CMD_SPMI + bool "spmi" + help + SPMI bus utility command. + endmenu diff --git a/cmd/Makefile b/cmd/Makefile index 81b98ee0d7..5d911f50f8 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -121,6 +121,7 @@ obj-$(CONFIG_CMD_SETEXPR) += setexpr.o obj-$(CONFIG_CMD_SOFTSWITCH) += softswitch.o obj-$(CONFIG_CMD_SPI) += spi.o obj-$(CONFIG_CMD_SPIBOOTLDR) += spibootldr.o +obj-$(CONFIG_CMD_SPMI) += spmi.o obj-$(CONFIG_CMD_STRINGS) += strings.o obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o diff --git a/cmd/spmi.c b/cmd/spmi.c new file mode 100644 index 0000000000..fd80b3a7d8 --- /dev/null +++ b/cmd/spmi.c @@ -0,0 +1,185 @@ +/* + * (C) Copyright 2017 Lothar Waßmann + * + * SPDX-License-Identifier: GPL-2.0+ + * + * based on: cmd/i2c.c + * (C) Copyright 2009 + * Sergey Kubushyn, himself, ksi@koi8.net + * + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +enum spmi_err_op { + SPMI_ERR_READ, + SPMI_ERR_WRITE, +}; + +static int spmi_report_err(int ret, enum spmi_err_op op) +{ + printf("Error %s the chip: %d\n", + op == SPMI_ERR_READ ? "reading" : "writing", ret); + + return CMD_RET_FAILURE; +} + +/** + * do_spmi_read() - Handle the "spmi read" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * + * Syntax: + * spmi read {spmi_chip} {devaddr}{.0, .1, .2} {len} {memaddr} + */ +static int do_spmi_read(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + uint sid, pid, reg; + int ret; + struct udevice *dev; + + if (argc != 4) + return cmd_usage(cmdtp); + + ret = uclass_get_device_by_name(UCLASS_SPMI, "spmi", &dev); + if (ret) { + printf("Failed to get SPMI bus: %d\n", ret); + return CMD_RET_FAILURE; + } + + /* + * SPMI chip address + */ + sid = simple_strtoul(argv[1], NULL, 16); + + /* + * SPMI data address within the chip. This can be 1 or + * 2 bytes long. Some day it might be 3 bytes long :-). + */ + pid = simple_strtoul(argv[2], NULL, 16); + reg = simple_strtoul(argv[3], NULL, 16); + + ret = spmi_reg_read(dev, sid, pid, reg); + if (ret < 0) + return spmi_report_err(ret, SPMI_ERR_READ); + + printf("%02x\n", ret); + return CMD_RET_SUCCESS; +} + +static int do_spmi_write(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + uint sid, pid, reg; + uint val; + int ret; + struct udevice *dev; + + if (argc != 5) + return cmd_usage(cmdtp); + + ret = uclass_get_device_by_name(UCLASS_SPMI, "spmi", &dev); + if (ret) { + printf("Failed to get SPMI bus: %d\n", ret); + return CMD_RET_FAILURE; + } + + /* + * SPMI chip address + */ + sid = simple_strtoul(argv[1], NULL, 16); + pid = simple_strtoul(argv[2], NULL, 16); + reg = simple_strtoul(argv[3], NULL, 16); + val = simple_strtoul(argv[4], NULL, 16); + if (val > 255) { + printf("Value %08x out of range [0..255]\n", val); + return CMD_RET_FAILURE; + } + + ret = spmi_reg_write(dev, sid, pid, reg, val); + if (ret) + return spmi_report_err(ret, SPMI_ERR_WRITE); + + return CMD_RET_SUCCESS; +} + +static cmd_tbl_t cmd_spmi_sub[] = { + U_BOOT_CMD_MKENT(read, 4, 1, do_spmi_read, "", ""), + U_BOOT_CMD_MKENT(write, 5, 0, do_spmi_write, "", ""), +}; + +static __maybe_unused void spmi_reloc(void) +{ + static int relocated; + + if (!relocated) { + fixup_cmdtable(cmd_spmi_sub, ARRAY_SIZE(cmd_spmi_sub)); + relocated = 1; + }; +} + +/** + * do_spmi() - Handle the "spmi" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int do_spmi(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + cmd_tbl_t *c; + +#ifdef CONFIG_NEEDS_MANUAL_RELOC + spmi_reloc(); +#endif + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading 'spmi' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_spmi_sub, ARRAY_SIZE(cmd_spmi_sub)); + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + printf("subcommand '%s' not found\n", argv[0]); + return CMD_RET_USAGE; +} + +#ifdef CONFIG_SYS_LONGHELP +static char spmi_help_text[] = + "\tspmi read - read register of peripheral on slave \n" + "\tspmi write - write to register of peripheral on slave \n" + ; +#endif + +U_BOOT_CMD( + spmi, 6, 1, do_spmi, + "SPMI sub-system", + spmi_help_text +);