// SPDX-License-Identifier: GPL-2.0 /* * List, select, and deselect mux controllers on the fly. * * Copyright (c) 2020 Texas Instruments Inc. * Author: Pratyush Yadav */ #include #include #include #include #include #include #include #include #include #define COLUMN_SIZE 16 /* * Print a member of a column. The total size of the text printed, including * trailing whitespace, will always be COLUMN_SIZE. */ #define PRINT_COLUMN(fmt, args...) do { \ char buf[COLUMN_SIZE + 1]; \ snprintf(buf, COLUMN_SIZE + 1, fmt, ##args); \ printf("%-*s", COLUMN_SIZE, buf); \ } while (0) /* * Find a mux based on its device name in argv[1] and index in the chip in * argv[2]. */ static struct mux_control *cmd_mux_find(char *const argv[]) { struct udevice *dev; struct mux_chip *chip; int ret; unsigned long id; ret = strict_strtoul(argv[2], 10, &id); if (ret) return ERR_PTR(ret); ret = uclass_get_device_by_name(UCLASS_MUX, argv[1], &dev); if (ret) return ERR_PTR(ret); chip = dev_get_uclass_priv(dev); if (!chip) return ERR_PTR(-EINVAL); if (id >= chip->controllers) return ERR_PTR(-EINVAL); return &chip->mux[id]; } /* * Print the details of a mux. The columns printed correspond to: "Selected", * "Current State", "Idle State", and "Num States". */ static void print_mux(struct mux_control *mux) { PRINT_COLUMN("%s", mux->in_use ? "yes" : "no"); if (mux->cached_state == MUX_IDLE_AS_IS) PRINT_COLUMN("%s", "unknown"); else PRINT_COLUMN("0x%x", mux->cached_state); if (mux->idle_state == MUX_IDLE_AS_IS) PRINT_COLUMN("%s", "as-is"); else if (mux->idle_state == MUX_IDLE_DISCONNECT) PRINT_COLUMN("%s", "disconnect"); else PRINT_COLUMN("0x%x", mux->idle_state); PRINT_COLUMN("0x%x", mux->states); printf("\n"); } static int do_mux_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct udevice *dev; struct mux_chip *chip; int j; for (uclass_first_device(UCLASS_MUX, &dev); dev; uclass_next_device(&dev)) { chip = dev_get_uclass_priv(dev); if (!chip) { dev_err(dev, "can't find mux chip\n"); continue; } printf("%s:\n", dev->name); printf(" "); PRINT_COLUMN("ID"); PRINT_COLUMN("Selected"); PRINT_COLUMN("Current State"); PRINT_COLUMN("Idle State"); PRINT_COLUMN("Num States"); printf("\n"); for (j = 0; j < chip->controllers; j++) { printf(" "); PRINT_COLUMN("%d", j); print_mux(&chip->mux[j]); } printf("\n"); } return 0; } static int do_mux_select(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct mux_control *mux; int ret; unsigned long state; if (argc != 4) return CMD_RET_USAGE; mux = cmd_mux_find(argv); if (IS_ERR_OR_NULL(mux)) { printf("Failed to find the specified mux\n"); return CMD_RET_FAILURE; } ret = strict_strtoul(argv[3], 16, &state); if (ret) { printf("Invalid state\n"); return CMD_RET_FAILURE; } ret = mux_control_select(mux, state); if (ret) { printf("Failed to select requested state\n"); return CMD_RET_FAILURE; } return CMD_RET_SUCCESS; } static int do_mux_deselect(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct mux_control *mux; int ret; if (argc != 3) return CMD_RET_USAGE; mux = cmd_mux_find(argv); if (IS_ERR_OR_NULL(mux)) { printf("Failed to find the specified mux\n"); return CMD_RET_FAILURE; } ret = mux_control_deselect(mux); if (ret) { printf("Failed to deselect mux\n"); return CMD_RET_FAILURE; } return CMD_RET_SUCCESS; } U_BOOT_LONGHELP(mux, "list - List all Muxes and their states\n" "select - Select the given mux state\n" "deselect - Deselect the given mux and reset it to its idle state"); U_BOOT_CMD_WITH_SUBCMDS(mux, "List, select, and deselect muxes", mux_help_text, U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mux_list), U_BOOT_SUBCMD_MKENT(select, 4, 0, do_mux_select), U_BOOT_SUBCMD_MKENT(deselect, 3, 0, do_mux_deselect));