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