]>
Commit | Line | Data |
---|---|---|
05115abe PY |
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 <[email protected]> | |
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 | */ | |
35 | static 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) | |
1ded89e7 | 52 | return ERR_PTR(-EINVAL); |
05115abe PY |
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 | */ | |
64 | static 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 | ||
85 | static 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 | ||
121 | static 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 | ||
152 | static 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 | ||
3616218b | 176 | U_BOOT_LONGHELP(mux, |
05115abe PY |
177 | "list - List all Muxes and their states\n" |
178 | "select <chip> <id> <state> - Select the given mux state\n" | |
3616218b | 179 | "deselect <chip> <id> - Deselect the given mux and reset it to its idle state"); |
05115abe PY |
180 | |
181 | U_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)); |