1// SPDX-License-Identifier: GPL-2.0 2/* 3 * List, select, and deselect mux controllers on the fly. 4 * 5 * Copyright (c) 2020 Texas Instruments Inc. 6 * Author: Pratyush Yadav <p.yadav@ti.com> 7 */ 8 9#include <common.h> 10#include <command.h> 11#include <errno.h> 12#include <dm.h> 13#include <dm/device_compat.h> 14#include <mux.h> 15#include <mux-internal.h> 16#include <linux/err.h> 17#include <dt-bindings/mux/mux.h> 18 19#define COLUMN_SIZE 16 20 21/* 22 * Print a member of a column. The total size of the text printed, including 23 * trailing whitespace, will always be COLUMN_SIZE. 24 */ 25#define PRINT_COLUMN(fmt, args...) do { \ 26 char buf[COLUMN_SIZE + 1]; \ 27 snprintf(buf, COLUMN_SIZE + 1, fmt, ##args); \ 28 printf("%-*s", COLUMN_SIZE, buf); \ 29} while (0) 30 31/* 32 * Find a mux based on its device name in argv[1] and index in the chip in 33 * argv[2]. 34 */ 35static struct mux_control *cmd_mux_find(char *const argv[]) 36{ 37 struct udevice *dev; 38 struct mux_chip *chip; 39 int ret; 40 unsigned long id; 41 42 ret = strict_strtoul(argv[2], 10, &id); 43 if (ret) 44 return ERR_PTR(ret); 45 46 ret = uclass_get_device_by_name(UCLASS_MUX, argv[1], &dev); 47 if (ret) 48 return ERR_PTR(ret); 49 50 chip = dev_get_uclass_priv(dev); 51 if (!chip) 52 return ERR_PTR(-EINVAL); 53 54 if (id >= chip->controllers) 55 return ERR_PTR(-EINVAL); 56 57 return &chip->mux[id]; 58} 59 60/* 61 * Print the details of a mux. The columns printed correspond to: "Selected", 62 * "Current State", "Idle State", and "Num States". 63 */ 64static void print_mux(struct mux_control *mux) 65{ 66 PRINT_COLUMN("%s", mux->in_use ? "yes" : "no"); 67 68 if (mux->cached_state == MUX_IDLE_AS_IS) 69 PRINT_COLUMN("%s", "unknown"); 70 else 71 PRINT_COLUMN("0x%x", mux->cached_state); 72 73 if (mux->idle_state == MUX_IDLE_AS_IS) 74 PRINT_COLUMN("%s", "as-is"); 75 else if (mux->idle_state == MUX_IDLE_DISCONNECT) 76 PRINT_COLUMN("%s", "disconnect"); 77 else 78 PRINT_COLUMN("0x%x", mux->idle_state); 79 80 PRINT_COLUMN("0x%x", mux->states); 81 82 printf("\n"); 83} 84 85static int do_mux_list(struct cmd_tbl *cmdtp, int flag, int argc, 86 char *const argv[]) 87{ 88 struct udevice *dev; 89 struct mux_chip *chip; 90 int j; 91 92 for (uclass_first_device(UCLASS_MUX, &dev); 93 dev; 94 uclass_next_device(&dev)) { 95 chip = dev_get_uclass_priv(dev); 96 if (!chip) { 97 dev_err(dev, "can't find mux chip\n"); 98 continue; 99 } 100 101 printf("%s:\n", dev->name); 102 103 printf(" "); 104 PRINT_COLUMN("ID"); 105 PRINT_COLUMN("Selected"); 106 PRINT_COLUMN("Current State"); 107 PRINT_COLUMN("Idle State"); 108 PRINT_COLUMN("Num States"); 109 printf("\n"); 110 for (j = 0; j < chip->controllers; j++) { 111 printf(" "); 112 PRINT_COLUMN("%d", j); 113 print_mux(&chip->mux[j]); 114 } 115 printf("\n"); 116 } 117 118 return 0; 119} 120 121static int do_mux_select(struct cmd_tbl *cmdtp, int flag, int argc, 122 char *const argv[]) 123{ 124 struct mux_control *mux; 125 int ret; 126 unsigned long state; 127 128 if (argc != 4) 129 return CMD_RET_USAGE; 130 131 mux = cmd_mux_find(argv); 132 if (IS_ERR_OR_NULL(mux)) { 133 printf("Failed to find the specified mux\n"); 134 return CMD_RET_FAILURE; 135 } 136 137 ret = strict_strtoul(argv[3], 16, &state); 138 if (ret) { 139 printf("Invalid state\n"); 140 return CMD_RET_FAILURE; 141 } 142 143 ret = mux_control_select(mux, state); 144 if (ret) { 145 printf("Failed to select requested state\n"); 146 return CMD_RET_FAILURE; 147 } 148 149 return CMD_RET_SUCCESS; 150} 151 152static int do_mux_deselect(struct cmd_tbl *cmdtp, int flag, int argc, 153 char *const argv[]) 154{ 155 struct mux_control *mux; 156 int ret; 157 158 if (argc != 3) 159 return CMD_RET_USAGE; 160 161 mux = cmd_mux_find(argv); 162 if (IS_ERR_OR_NULL(mux)) { 163 printf("Failed to find the specified mux\n"); 164 return CMD_RET_FAILURE; 165 } 166 167 ret = mux_control_deselect(mux); 168 if (ret) { 169 printf("Failed to deselect mux\n"); 170 return CMD_RET_FAILURE; 171 } 172 173 return CMD_RET_SUCCESS; 174} 175 176U_BOOT_LONGHELP(mux, 177 "list - List all Muxes and their states\n" 178 "select <chip> <id> <state> - Select the given mux state\n" 179 "deselect <chip> <id> - Deselect the given mux and reset it to its idle state"); 180 181U_BOOT_CMD_WITH_SUBCMDS(mux, "List, select, and deselect muxes", mux_help_text, 182 U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mux_list), 183 U_BOOT_SUBCMD_MKENT(select, 4, 0, do_mux_select), 184 U_BOOT_SUBCMD_MKENT(deselect, 3, 0, do_mux_deselect)); 185