1 /*
2  * Copyright 2023 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/device.h>
7 #include <zephyr/shell/shell.h>
8 #include <zephyr/drivers/usb_c/usbc_ppc.h>
9 
10 /** Macro used to iterate over USB-C connector and call a function if the node has PPC property */
11 #define CALL_IF_HAS_PPC(usb_node, func)                                                            \
12 	COND_CODE_1(DT_NODE_HAS_PROP(usb_node, ppc),                                               \
13 		    (ret |= func(DEVICE_DT_GET(DT_PHANDLE_BY_IDX(usb_node, ppc, 0)));), ())
14 
15 /**
16  * @brief Command that dumps registers of one or all of the PPCs
17  *
18  * @param sh Shell structure
19  * @param argc Arguments count
20  * @param argv Device name
21  * @return int ORed return values of all the functions executed, 0 in case of success
22  */
cmd_ppc_dump(const struct shell * sh,size_t argc,char ** argv)23 static int cmd_ppc_dump(const struct shell *sh, size_t argc, char **argv)
24 {
25 	int ret = 0;
26 
27 	if (argc <= 1) {
28 		DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, ppc_dump_regs);
29 	} else {
30 		const struct device *dev = shell_device_get_binding(argv[1]);
31 
32 		ret = ppc_dump_regs(dev);
33 	}
34 
35 	return ret;
36 }
37 
38 /**
39  * @brief Function used to pretty print status of the PPC
40  *
41  * @param dev Pointer to the PPC device structure
42  */
print_status(const struct device * dev)43 static int print_status(const struct device *dev)
44 {
45 	printk("PPC %s:\n", dev->name);
46 	printk("  Dead battery:    %d\n", ppc_is_dead_battery_mode(dev));
47 	printk("  Is sourcing:     %d\n", ppc_is_vbus_source(dev));
48 	printk("  Is sinking:      %d\n", ppc_is_vbus_sink(dev));
49 	printk("  Is VBUS present: %d\n", ppc_is_vbus_present(dev));
50 
51 	return 0;
52 }
53 
54 /**
55  * @brief Command that prints the status of one or all of the PPCs
56  *
57  * @param sh Shell structure
58  * @param argc Arguments count
59  * @param argv Device name
60  * @return int ORed return values of all the functions executed, 0 in case of success
61  */
cmd_ppc_status(const struct shell * sh,size_t argc,char ** argv)62 static int cmd_ppc_status(const struct shell *sh, size_t argc, char **argv)
63 {
64 	int ret = 0;
65 
66 	if (argc <= 1) {
67 		DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, print_status);
68 	} else {
69 		const struct device *dev = shell_device_get_binding(argv[1]);
70 
71 		ret = print_status(dev);
72 	}
73 
74 	return ret;
75 }
76 
77 /**
78  * @brief Command that requests one or all of the PPCs to try exiting the dead battery mode
79  *
80  * @param sh Shell structure
81  * @param argc Arguments count
82  * @param argv Device name
83  * @return int ORed return values of all the functions executed, 0 in case of success
84  */
cmd_ppc_exit_db(const struct shell * sh,size_t argc,char ** argv)85 static int cmd_ppc_exit_db(const struct shell *sh, size_t argc, char **argv)
86 {
87 	int ret = 0;
88 
89 	if (argc <= 1) {
90 		DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC,
91 					     ppc_exit_dead_battery_mode);
92 	} else {
93 		const struct device *dev = shell_device_get_binding(argv[1]);
94 
95 		ret = ppc_exit_dead_battery_mode(dev);
96 	}
97 
98 	return ret;
99 }
100 
101 /**
102  * @brief Function used to create subcommands with devices names
103  *
104  * @param idx counter of devices
105  * @param entry shell structure that will be filled
106  */
device_name_get(size_t idx,struct shell_static_entry * entry)107 static void device_name_get(size_t idx, struct shell_static_entry *entry)
108 {
109 	const struct device *dev = shell_device_lookup(idx, NULL);
110 
111 	entry->syntax = (dev != NULL) ? dev->name : NULL;
112 	entry->handler = NULL;
113 	entry->help = NULL;
114 	entry->subcmd = NULL;
115 }
116 
117 SHELL_DYNAMIC_CMD_CREATE(list_device_names, device_name_get);
118 
119 SHELL_STATIC_SUBCMD_SET_CREATE(sub_ppc_cmds,
120 			       SHELL_CMD_ARG(dump, &list_device_names,
121 					     "Dump PPC registers\n"
122 					     "Usage: ppc dump [<ppc device>]",
123 					     cmd_ppc_dump, 1, 1),
124 			       SHELL_CMD_ARG(status, &list_device_names,
125 					     "Write PPC power status\n"
126 					     "Usage: ppc status [<ppc device>]",
127 					     cmd_ppc_status, 1, 1),
128 			       SHELL_CMD_ARG(exitdb, &list_device_names,
129 					     "Exit from the dead battery mode\n"
130 					     "Usage: ppc exitdb [<ppc device>]",
131 					     cmd_ppc_exit_db, 1, 1),
132 			       SHELL_SUBCMD_SET_END);
133 
134 SHELL_CMD_REGISTER(ppc, &sub_ppc_cmds, "PPC (USB-C PD) diagnostics", NULL);
135