uboot/cmd/mux.c
<<
>>
Prefs
   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(ret);
  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
 176static char mux_help_text[] =
 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