1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * UCSI debugfs interface
4 *
5 * Copyright (C) 2023 Intel Corporation
6 *
7 * Authors: Rajaram Regupathy <rajaram.regupathy@intel.com>
8 * Gopal Saranya <saranya.gopal@intel.com>
9 */
10 #include <linux/debugfs.h>
11 #include <linux/hex.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
14 #include <linux/types.h>
15 #include <linux/usb.h>
16
17 #include <asm/errno.h>
18
19 #include "ucsi.h"
20
21 static struct dentry *ucsi_debugfs_root;
22
ucsi_cmd(void * data,u64 val)23 static int ucsi_cmd(void *data, u64 val)
24 {
25 struct ucsi *ucsi = data;
26 int ret;
27
28 memset(&ucsi->debugfs->response, 0, sizeof(ucsi->debugfs->response));
29 ucsi->debugfs->status = 0;
30
31 switch (UCSI_COMMAND(val)) {
32 case UCSI_SET_CCOM:
33 case UCSI_SET_UOR:
34 case UCSI_SET_PDR:
35 case UCSI_CONNECTOR_RESET:
36 case UCSI_SET_SINK_PATH:
37 case UCSI_SET_NEW_CAM:
38 case UCSI_SET_USB:
39 case UCSI_SET_POWER_LEVEL:
40 case UCSI_READ_POWER_LEVEL:
41 ret = ucsi_send_command(ucsi, val, NULL, 0);
42 break;
43 case UCSI_GET_CAPABILITY:
44 case UCSI_GET_CONNECTOR_CAPABILITY:
45 case UCSI_GET_ALTERNATE_MODES:
46 case UCSI_GET_CAM_SUPPORTED:
47 case UCSI_GET_CURRENT_CAM:
48 case UCSI_GET_PDOS:
49 case UCSI_GET_CABLE_PROPERTY:
50 case UCSI_GET_CONNECTOR_STATUS:
51 case UCSI_GET_ERROR_STATUS:
52 case UCSI_GET_PD_MESSAGE:
53 case UCSI_GET_ATTENTION_VDO:
54 case UCSI_GET_CAM_CS:
55 case UCSI_GET_LPM_PPM_INFO:
56 ret = ucsi_send_command(ucsi, val,
57 &ucsi->debugfs->response,
58 sizeof(ucsi->debugfs->response));
59 break;
60 default:
61 ret = -EOPNOTSUPP;
62 }
63
64 if (ret < 0) {
65 ucsi->debugfs->status = ret;
66 return ret;
67 }
68
69 return 0;
70 }
71 DEFINE_DEBUGFS_ATTRIBUTE(ucsi_cmd_fops, NULL, ucsi_cmd, "0x%llx\n");
72
ucsi_resp_show(struct seq_file * s,void * not_used)73 static int ucsi_resp_show(struct seq_file *s, void *not_used)
74 {
75 struct ucsi *ucsi = s->private;
76
77 if (ucsi->debugfs->status)
78 return ucsi->debugfs->status;
79
80 seq_printf(s, "0x%016llx%016llx\n", ucsi->debugfs->response.high,
81 ucsi->debugfs->response.low);
82 return 0;
83 }
84 DEFINE_SHOW_ATTRIBUTE(ucsi_resp);
85
ucsi_peak_curr_show(struct seq_file * m,void * v)86 static int ucsi_peak_curr_show(struct seq_file *m, void *v)
87 {
88 struct ucsi *ucsi = m->private;
89
90 seq_printf(m, "%u mA\n", ucsi->connector->peak_current);
91 return 0;
92 }
93 DEFINE_SHOW_ATTRIBUTE(ucsi_peak_curr);
94
ucsi_avg_curr_show(struct seq_file * m,void * v)95 static int ucsi_avg_curr_show(struct seq_file *m, void *v)
96 {
97 struct ucsi *ucsi = m->private;
98
99 seq_printf(m, "%u mA\n", ucsi->connector->avg_current);
100 return 0;
101 }
102 DEFINE_SHOW_ATTRIBUTE(ucsi_avg_curr);
103
ucsi_vbus_volt_show(struct seq_file * m,void * v)104 static int ucsi_vbus_volt_show(struct seq_file *m, void *v)
105 {
106 struct ucsi *ucsi = m->private;
107
108 seq_printf(m, "%u mV\n", ucsi->connector->vbus_voltage);
109 return 0;
110 }
111 DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt);
112
ucsi_debugfs_register(struct ucsi * ucsi)113 void ucsi_debugfs_register(struct ucsi *ucsi)
114 {
115 ucsi->debugfs = kzalloc_obj(*ucsi->debugfs);
116 if (!ucsi->debugfs)
117 return;
118
119 ucsi->debugfs->dentry = debugfs_create_dir(dev_name(ucsi->dev), ucsi_debugfs_root);
120 debugfs_create_file("command", 0200, ucsi->debugfs->dentry, ucsi, &ucsi_cmd_fops);
121 debugfs_create_file("response", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_resp_fops);
122 debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops);
123 debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops);
124 debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops);
125 }
126
ucsi_debugfs_unregister(struct ucsi * ucsi)127 void ucsi_debugfs_unregister(struct ucsi *ucsi)
128 {
129 if (IS_ERR_OR_NULL(ucsi) || !ucsi->debugfs)
130 return;
131
132 debugfs_remove_recursive(ucsi->debugfs->dentry);
133 kfree(ucsi->debugfs);
134 }
135
ucsi_debugfs_init(void)136 void ucsi_debugfs_init(void)
137 {
138 ucsi_debugfs_root = debugfs_create_dir("ucsi", usb_debug_root);
139 }
140
ucsi_debugfs_exit(void)141 void ucsi_debugfs_exit(void)
142 {
143 debugfs_remove(ucsi_debugfs_root);
144 }
145