| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * UCSI debugfs interface |
| * |
| * Copyright (C) 2023 Intel Corporation |
| * |
| * Authors: Rajaram Regupathy <rajaram.regupathy@intel.com> |
| * Gopal Saranya <saranya.gopal@intel.com> |
| */ |
| #include <linux/debugfs.h> |
| #include <linux/slab.h> |
| #include <linux/string.h> |
| #include <linux/types.h> |
| #include <linux/usb.h> |
| |
| #include <asm/errno.h> |
| |
| #include "ucsi.h" |
| |
| static struct dentry *ucsi_debugfs_root; |
| |
| static int ucsi_cmd(void *data, u64 val) |
| { |
| struct ucsi *ucsi = data; |
| int ret; |
| |
| memset(&ucsi->debugfs->response, 0, sizeof(ucsi->debugfs->response)); |
| ucsi->debugfs->status = 0; |
| |
| switch (UCSI_COMMAND(val)) { |
| case UCSI_SET_UOM: |
| case UCSI_SET_UOR: |
| case UCSI_SET_PDR: |
| case UCSI_CONNECTOR_RESET: |
| ret = ucsi_send_command(ucsi, val, NULL, 0); |
| break; |
| case UCSI_GET_CAPABILITY: |
| case UCSI_GET_CONNECTOR_CAPABILITY: |
| case UCSI_GET_ALTERNATE_MODES: |
| case UCSI_GET_CURRENT_CAM: |
| case UCSI_GET_PDOS: |
| case UCSI_GET_CABLE_PROPERTY: |
| case UCSI_GET_CONNECTOR_STATUS: |
| ret = ucsi_send_command(ucsi, val, |
| &ucsi->debugfs->response, |
| sizeof(ucsi->debugfs->response)); |
| break; |
| default: |
| ret = -EOPNOTSUPP; |
| } |
| |
| if (ret < 0) { |
| ucsi->debugfs->status = ret; |
| return ret; |
| } |
| |
| return 0; |
| } |
| DEFINE_DEBUGFS_ATTRIBUTE(ucsi_cmd_fops, NULL, ucsi_cmd, "0x%llx\n"); |
| |
| static int ucsi_resp_show(struct seq_file *s, void *not_used) |
| { |
| struct ucsi *ucsi = s->private; |
| |
| if (ucsi->debugfs->status) |
| return ucsi->debugfs->status; |
| |
| seq_printf(s, "0x%016llx%016llx\n", ucsi->debugfs->response.high, |
| ucsi->debugfs->response.low); |
| return 0; |
| } |
| DEFINE_SHOW_ATTRIBUTE(ucsi_resp); |
| |
| void ucsi_debugfs_register(struct ucsi *ucsi) |
| { |
| ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL); |
| if (!ucsi->debugfs) |
| return; |
| |
| ucsi->debugfs->dentry = debugfs_create_dir(dev_name(ucsi->dev), ucsi_debugfs_root); |
| debugfs_create_file("command", 0200, ucsi->debugfs->dentry, ucsi, &ucsi_cmd_fops); |
| debugfs_create_file("response", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_resp_fops); |
| } |
| |
| void ucsi_debugfs_unregister(struct ucsi *ucsi) |
| { |
| if (IS_ERR_OR_NULL(ucsi) || !ucsi->debugfs) |
| return; |
| |
| debugfs_remove_recursive(ucsi->debugfs->dentry); |
| kfree(ucsi->debugfs); |
| } |
| |
| void ucsi_debugfs_init(void) |
| { |
| ucsi_debugfs_root = debugfs_create_dir("ucsi", usb_debug_root); |
| } |
| |
| void ucsi_debugfs_exit(void) |
| { |
| debugfs_remove(ucsi_debugfs_root); |
| } |