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/slab.h> |
12 | #include <linux/string.h> |
13 | #include <linux/types.h> |
14 | #include <linux/usb.h> |
15 | |
16 | #include <asm/errno.h> |
17 | |
18 | #include "ucsi.h" |
19 | |
20 | static struct dentry *ucsi_debugfs_root; |
21 | |
22 | static int ucsi_cmd(void *data, u64 val) |
23 | { |
24 | struct ucsi *ucsi = data; |
25 | int ret; |
26 | |
27 | memset(&ucsi->debugfs->response, 0, sizeof(ucsi->debugfs->response)); |
28 | ucsi->debugfs->status = 0; |
29 | |
30 | switch (UCSI_COMMAND(val)) { |
31 | case UCSI_SET_UOM: |
32 | case UCSI_SET_UOR: |
33 | case UCSI_SET_PDR: |
34 | case UCSI_CONNECTOR_RESET: |
35 | ret = ucsi_send_command(ucsi, command: val, NULL, size: 0); |
36 | break; |
37 | case UCSI_GET_CAPABILITY: |
38 | case UCSI_GET_CONNECTOR_CAPABILITY: |
39 | case UCSI_GET_ALTERNATE_MODES: |
40 | case UCSI_GET_CURRENT_CAM: |
41 | case UCSI_GET_PDOS: |
42 | case UCSI_GET_CABLE_PROPERTY: |
43 | case UCSI_GET_CONNECTOR_STATUS: |
44 | ret = ucsi_send_command(ucsi, command: val, |
45 | retval: &ucsi->debugfs->response, |
46 | size: sizeof(ucsi->debugfs->response)); |
47 | break; |
48 | default: |
49 | ret = -EOPNOTSUPP; |
50 | } |
51 | |
52 | if (ret < 0) { |
53 | ucsi->debugfs->status = ret; |
54 | return ret; |
55 | } |
56 | |
57 | return 0; |
58 | } |
59 | DEFINE_DEBUGFS_ATTRIBUTE(ucsi_cmd_fops, NULL, ucsi_cmd, "0x%llx\n" ); |
60 | |
61 | static int ucsi_resp_show(struct seq_file *s, void *not_used) |
62 | { |
63 | struct ucsi *ucsi = s->private; |
64 | |
65 | if (ucsi->debugfs->status) |
66 | return ucsi->debugfs->status; |
67 | |
68 | seq_printf(m: s, fmt: "0x%016llx%016llx\n" , ucsi->debugfs->response.high, |
69 | ucsi->debugfs->response.low); |
70 | return 0; |
71 | } |
72 | DEFINE_SHOW_ATTRIBUTE(ucsi_resp); |
73 | |
74 | void ucsi_debugfs_register(struct ucsi *ucsi) |
75 | { |
76 | ucsi->debugfs = kzalloc(size: sizeof(*ucsi->debugfs), GFP_KERNEL); |
77 | if (!ucsi->debugfs) |
78 | return; |
79 | |
80 | ucsi->debugfs->dentry = debugfs_create_dir(name: dev_name(dev: ucsi->dev), parent: ucsi_debugfs_root); |
81 | debugfs_create_file(name: "command" , mode: 0200, parent: ucsi->debugfs->dentry, data: ucsi, fops: &ucsi_cmd_fops); |
82 | debugfs_create_file(name: "response" , mode: 0400, parent: ucsi->debugfs->dentry, data: ucsi, fops: &ucsi_resp_fops); |
83 | } |
84 | |
85 | void ucsi_debugfs_unregister(struct ucsi *ucsi) |
86 | { |
87 | if (IS_ERR_OR_NULL(ptr: ucsi) || !ucsi->debugfs) |
88 | return; |
89 | |
90 | debugfs_remove_recursive(dentry: ucsi->debugfs->dentry); |
91 | kfree(objp: ucsi->debugfs); |
92 | } |
93 | |
94 | void ucsi_debugfs_init(void) |
95 | { |
96 | ucsi_debugfs_root = debugfs_create_dir(name: "ucsi" , parent: usb_debug_root); |
97 | } |
98 | |
99 | void ucsi_debugfs_exit(void) |
100 | { |
101 | debugfs_remove(dentry: ucsi_debugfs_root); |
102 | } |
103 | |