1 /*
2  * Copyright 2023 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/device.h>
7 #include <zephyr/logging/log.h>
8 #include <zephyr/usb_c/usbc.h>
9 #include <zephyr/shell/shell.h>
10 
11 /** Macro used to call the dump_std_reg function from the TCPC device pointer */
12 #define TCPC_DUMP_DEV(dev) ret |= tcpc_dump_std_reg(dev);
13 
14 /** Macro used to call the dump_std_reg function from the USB-C connector node */
15 #define TCPC_DUMP_CONN_NODE(node) TCPC_DUMP_DEV(DEVICE_DT_GET(DT_PROP(node, tcpc)))
16 
17 /** Macro used to call the vbus_measure function from the VBUS device pointer */
18 #define TCPC_VBUS_DEV(dev)                                                                         \
19 	{                                                                                          \
20 		int val;                                                                           \
21 		ret |= usbc_vbus_measure(dev, &val);                                               \
22 		shell_print(sh, "%s vbus: %d mV", dev->name, val);                                 \
23 	}
24 
25 /** Macro used to call the vbus_measure function from the USB-C connector node */
26 #define TCPC_VBUS_CONN_NODE(node) TCPC_VBUS_DEV(DEVICE_DT_GET(DT_PROP(node, vbus)))
27 
28 /** Macro used to call the get_chip function from the TCPC device pointer */
29 #define TCPC_GET_CHIP_DEV(dev)                                                                     \
30 	{                                                                                          \
31 		ret |= tcpc_get_chip_info(dev, &chip_info);                                        \
32 		shell_print(sh, "Chip: %s", dev->name);                                            \
33 		shell_print(sh, "\tVendor:   %04x", chip_info.vendor_id);                          \
34 		shell_print(sh, "\tProduct:  %04x", chip_info.product_id);                         \
35 		shell_print(sh, "\tDevice:   %04x", chip_info.device_id);                          \
36 		shell_print(sh, "\tFirmware: %llx", chip_info.fw_version_number);                  \
37 	}
38 
39 /** Macro used to call the get_chip function from the USB-C connector node */
40 #define TCPC_GET_CHIP_CONN_NODE(node) TCPC_GET_CHIP_DEV(DEVICE_DT_GET(DT_PROP(node, tcpc)))
41 
42 /**
43  * @brief Shell command that dumps standard registers of TCPCs for all available USB-C ports
44  *
45  * @param sh Shell structure
46  * @param argc Arguments count
47  * @param argv Device name
48  * @return int ORed return values of all the functions executed, 0 in case of success
49  */
cmd_tcpc_dump(const struct shell * sh,size_t argc,char ** argv)50 static int cmd_tcpc_dump(const struct shell *sh, size_t argc, char **argv)
51 {
52 	int ret = 0;
53 
54 	if (argc <= 1) {
55 		DT_FOREACH_STATUS_OKAY(usb_c_connector, TCPC_DUMP_CONN_NODE);
56 	} else {
57 		const struct device *dev = shell_device_get_binding(argv[1]);
58 
59 		if (dev != NULL) {
60 			TCPC_DUMP_DEV(dev);
61 		} else {
62 			ret = -ENODEV;
63 		}
64 	}
65 
66 	return ret;
67 }
68 
69 /**
70  * @brief Shell command that prints the vbus measures for all available USB-C ports
71  *
72  * @param sh Shell structure
73  * @param argc Arguments count
74  * @param argv Device name
75  * @return int ORed return values of all the functions executed, 0 in case of success
76  */
cmd_tcpc_vbus(const struct shell * sh,size_t argc,char ** argv)77 static int cmd_tcpc_vbus(const struct shell *sh, size_t argc, char **argv)
78 {
79 	int ret = 0;
80 
81 	if (argc <= 1) {
82 		DT_FOREACH_STATUS_OKAY(usb_c_connector, TCPC_VBUS_CONN_NODE);
83 	} else {
84 		const struct device *dev = shell_device_get_binding(argv[1]);
85 
86 		if (dev != NULL) {
87 			TCPC_VBUS_DEV(dev);
88 		} else {
89 			ret = -ENODEV;
90 		}
91 	}
92 
93 	return ret;
94 }
95 
96 /**
97  * @brief Shell command that prints the TCPCs chips information for all available USB-C ports
98  *
99  * @param sh Shell structure
100  * @param argc Arguments count
101  * @param argv Device name
102  * @return int ORed return values of all the functions executed, 0 in case of success
103  */
cmd_tcpc_chip_info(const struct shell * sh,size_t argc,char ** argv)104 static int cmd_tcpc_chip_info(const struct shell *sh, size_t argc, char **argv)
105 {
106 	struct tcpc_chip_info chip_info;
107 	int ret = 0;
108 
109 	if (argc <= 1) {
110 		DT_FOREACH_STATUS_OKAY(usb_c_connector, TCPC_GET_CHIP_CONN_NODE);
111 	} else {
112 		const struct device *dev = shell_device_get_binding(argv[1]);
113 
114 		if (dev != NULL) {
115 			TCPC_GET_CHIP_DEV(dev);
116 		} else {
117 			ret = -ENODEV;
118 		}
119 	}
120 
121 	return ret;
122 }
123 
124 /**
125  * @brief Function used to create subcommands with devices names
126  *
127  * @param idx counter of devices
128  * @param entry shell structure that will be filled
129  */
device_name_get(size_t idx,struct shell_static_entry * entry)130 static void device_name_get(size_t idx, struct shell_static_entry *entry)
131 {
132 	const struct device *dev = shell_device_lookup(idx, NULL);
133 
134 	entry->syntax = (dev != NULL) ? dev->name : NULL;
135 	entry->handler = NULL;
136 	entry->help = NULL;
137 	entry->subcmd = NULL;
138 }
139 
140 SHELL_DYNAMIC_CMD_CREATE(list_device_names, device_name_get);
141 
142 SHELL_STATIC_SUBCMD_SET_CREATE(sub_tcpc_cmds,
143 			       SHELL_CMD_ARG(dump, &list_device_names,
144 					     "Dump TCPC registers\n"
145 					     "Usage: tcpc dump [<tcpc device>]",
146 					     cmd_tcpc_dump, 1, 1),
147 			       SHELL_CMD_ARG(vbus, &list_device_names,
148 					     "Display VBUS voltage\n"
149 					     "Usage: tcpc vbus [<vbus device>]",
150 					     cmd_tcpc_vbus, 1, 1),
151 			       SHELL_CMD_ARG(chip, &list_device_names,
152 					     "Display chip information\n"
153 					     "Usage: tcpc chip [<tcpc device>]",
154 					     cmd_tcpc_chip_info, 1, 1),
155 			       SHELL_SUBCMD_SET_END);
156 
157 SHELL_CMD_REGISTER(tcpc, &sub_tcpc_cmds, "TCPC (USB-C PD) diagnostics", NULL);
158