mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-21 01:18:52 +09:00
185 lines
4.0 KiB
C
185 lines
4.0 KiB
C
![]() |
// SPDX-License-Identifier: GPL-2.0
|
||
|
/*
|
||
|
* List, select, and deselect mux controllers on the fly.
|
||
|
*
|
||
|
* Copyright (c) 2020 Texas Instruments Inc.
|
||
|
* Author: Pratyush Yadav <p.yadav@ti.com>
|
||
|
*/
|
||
|
|
||
|
#include <common.h>
|
||
|
#include <command.h>
|
||
|
#include <errno.h>
|
||
|
#include <dm.h>
|
||
|
#include <dm/device_compat.h>
|
||
|
#include <mux.h>
|
||
|
#include <mux-internal.h>
|
||
|
#include <linux/err.h>
|
||
|
#include <dt-bindings/mux/mux.h>
|
||
|
|
||
|
#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(ret);
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
static char mux_help_text[] =
|
||
|
"list - List all Muxes and their states\n"
|
||
|
"select <chip> <id> <state> - Select the given mux state\n"
|
||
|
"deselect <chip> <id> - 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));
|