1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4  */
5 
6 #include <command.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <dm/pinctrl.h>
10 #include <dm/uclass-internal.h>
11 
12 #define LIMIT_DEVNAME	30
13 
14 static struct udevice *currdev;
15 
do_dev(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])16 static int do_dev(struct cmd_tbl *cmdtp, int flag, int argc,
17 		  char *const argv[])
18 {
19 	const char *name;
20 	int ret;
21 
22 	switch (argc) {
23 	case 2:
24 		name = argv[1];
25 		ret = uclass_get_device_by_name(UCLASS_PINCTRL, name, &currdev);
26 		if (ret) {
27 			printf("Can't get the pin-controller: %s!\n", name);
28 			return CMD_RET_FAILURE;
29 		}
30 		/* fall through */
31 	case 1:
32 		if (!currdev) {
33 			printf("Pin-controller device is not set!\n");
34 			return CMD_RET_USAGE;
35 		}
36 
37 		printf("dev: %s\n", currdev->name);
38 	}
39 
40 	return CMD_RET_SUCCESS;
41 }
42 
43 /**
44  * Print the muxing information for one or all pins of one pinctrl device
45  *
46  * @param dev		pinctrl device
47  * @param name		NULL to display all the pins
48  *			or name of the pin to display
49  * Return: 0 on success, non-0 on error
50  */
show_pinmux(struct udevice * dev,char * name)51 static int show_pinmux(struct udevice *dev, char *name)
52 {
53 	char pin_name[PINNAME_SIZE];
54 	char pin_mux[PINMUX_SIZE];
55 	int pins_count;
56 	int i;
57 	int ret;
58 	bool found = false;
59 
60 	pins_count = pinctrl_get_pins_count(dev);
61 
62 	if (pins_count == -ENOSYS) {
63 		printf("Ops get_pins_count not supported by %s\n", dev->name);
64 		return pins_count;
65 	}
66 
67 	for (i = 0; i < pins_count; i++) {
68 		ret = pinctrl_get_pin_name(dev, i, pin_name, PINNAME_SIZE);
69 		if (ret) {
70 			printf("Ops get_pin_name error (%d) by %s\n", ret, dev->name);
71 			return ret;
72 		}
73 		if (name && strcmp(name, pin_name))
74 			continue;
75 		found = true;
76 		ret = pinctrl_get_pin_muxing(dev, i, pin_mux, PINMUX_SIZE);
77 		if (ret) {
78 			printf("Ops get_pin_muxing error (%d) by %s in %s\n",
79 			       ret, pin_name, dev->name);
80 			return ret;
81 		}
82 
83 		printf("%-*s: %-*s\n", PINNAME_SIZE, pin_name,
84 		       PINMUX_SIZE, pin_mux);
85 	}
86 
87 	if (!found)
88 		return -ENOENT;
89 
90 	return 0;
91 }
92 
do_status(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])93 static int do_status(struct cmd_tbl *cmdtp, int flag, int argc,
94 		     char *const argv[])
95 {
96 	struct udevice *dev;
97 	char *name;
98 	int ret;
99 
100 	if (argc < 2) {
101 		if (!currdev) {
102 			printf("pin-controller device not selected\n");
103 			return CMD_RET_FAILURE;
104 		}
105 		show_pinmux(currdev, NULL);
106 		return CMD_RET_SUCCESS;
107 	}
108 
109 	if (strcmp(argv[1], "-a"))
110 		name = argv[1];
111 	else
112 		name = NULL;
113 
114 	uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) {
115 		if (!name) {
116 			/* insert a separator between each pin-controller display */
117 			printf("--------------------------\n");
118 			printf("%s:\n", dev->name);
119 		}
120 		ret = show_pinmux(dev, name);
121 		/* stop when the status of requested pin is displayed */
122 		if (name && !ret)
123 			return CMD_RET_SUCCESS;
124 	}
125 
126 	if (name) {
127 		printf("%s not found\n", name);
128 		return CMD_RET_FAILURE;
129 	}
130 
131 	return CMD_RET_SUCCESS;
132 }
133 
do_list(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])134 static int do_list(struct cmd_tbl *cmdtp, int flag, int argc,
135 		   char *const argv[])
136 {
137 	struct udevice *dev;
138 
139 	printf("| %-*.*s| %-*.*s| %s\n",
140 	       LIMIT_DEVNAME, LIMIT_DEVNAME, "Device",
141 	       LIMIT_DEVNAME, LIMIT_DEVNAME, "Driver",
142 	       "Parent");
143 
144 	uclass_foreach_dev_probe(UCLASS_PINCTRL, dev) {
145 		printf("| %-*.*s| %-*.*s| %s\n",
146 		       LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
147 		       LIMIT_DEVNAME, LIMIT_DEVNAME, dev->driver->name,
148 		       dev->parent->name);
149 	}
150 
151 	return CMD_RET_SUCCESS;
152 }
153 
154 static struct cmd_tbl pinmux_subcmd[] = {
155 	U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
156 	U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
157 	U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
158 };
159 
do_pinmux(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])160 static int do_pinmux(struct cmd_tbl *cmdtp, int flag, int argc,
161 		     char *const argv[])
162 {
163 	struct cmd_tbl *cmd;
164 
165 	argc--;
166 	argv++;
167 
168 	cmd = find_cmd_tbl(argv[0], pinmux_subcmd, ARRAY_SIZE(pinmux_subcmd));
169 	if (!cmd || argc > cmd->maxargs)
170 		return CMD_RET_USAGE;
171 
172 	return cmd->cmd(cmdtp, flag, argc, argv);
173 }
174 
175 U_BOOT_CMD(pinmux, CONFIG_SYS_MAXARGS, 1, do_pinmux,
176 	   "show pin-controller muxing",
177 	   "list                     - list UCLASS_PINCTRL devices\n"
178 	   "pinmux dev [pincontroller-name] - select pin-controller device\n"
179 	   "pinmux status [-a | pin-name]   - print pin-controller muxing [for all | for pin-name]\n"
180 );
181