18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci// Copyright(c) 2017-2019 Intel Corporation. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/device.h> 58c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 68c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/soundwire/sdw.h> 98c2ecf20Sopenharmony_ci#include <linux/soundwire/sdw_registers.h> 108c2ecf20Sopenharmony_ci#include "bus.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic struct dentry *sdw_debugfs_root; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_civoid sdw_bus_debugfs_init(struct sdw_bus *bus) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci char name[16]; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci if (!sdw_debugfs_root) 198c2ecf20Sopenharmony_ci return; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* create the debugfs master-N */ 228c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "master-%d-%d", bus->id, bus->link_id); 238c2ecf20Sopenharmony_ci bus->debugfs = debugfs_create_dir(name, sdw_debugfs_root); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_civoid sdw_bus_debugfs_exit(struct sdw_bus *bus) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci debugfs_remove_recursive(bus->debugfs); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define RD_BUF (3 * PAGE_SIZE) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic ssize_t sdw_sprintf(struct sdw_slave *slave, 348c2ecf20Sopenharmony_ci char *buf, size_t pos, unsigned int reg) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int value; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci value = sdw_read(slave, reg); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (value < 0) 418c2ecf20Sopenharmony_ci return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg); 428c2ecf20Sopenharmony_ci else 438c2ecf20Sopenharmony_ci return scnprintf(buf + pos, RD_BUF - pos, 448c2ecf20Sopenharmony_ci "%3x\t%2x\n", reg, value); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic int sdw_slave_reg_show(struct seq_file *s_file, void *data) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct sdw_slave *slave = s_file->private; 508c2ecf20Sopenharmony_ci char *buf; 518c2ecf20Sopenharmony_ci ssize_t ret; 528c2ecf20Sopenharmony_ci int i, j; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci buf = kzalloc(RD_BUF, GFP_KERNEL); 558c2ecf20Sopenharmony_ci if (!buf) 568c2ecf20Sopenharmony_ci return -ENOMEM; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ret = scnprintf(buf, RD_BUF, "Register Value\n"); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* DP0 non-banked registers */ 618c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n"); 628c2ecf20Sopenharmony_ci for (i = SDW_DP0_INT; i <= SDW_DP0_PREPARECTRL; i++) 638c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, i); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* DP0 Bank 0 registers */ 668c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n"); 678c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN); 688c2ecf20Sopenharmony_ci for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++) 698c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, i); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* DP0 Bank 1 registers */ 728c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n"); 738c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, 748c2ecf20Sopenharmony_ci SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET); 758c2ecf20Sopenharmony_ci for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET; 768c2ecf20Sopenharmony_ci i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++) 778c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, i); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* SCP registers */ 808c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n"); 818c2ecf20Sopenharmony_ci for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++) 828c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, i); 838c2ecf20Sopenharmony_ci for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++) 848c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, i); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * SCP Bank 0/1 registers are read-only and cannot be 888c2ecf20Sopenharmony_ci * retrieved from the Slave. The Master typically keeps track 898c2ecf20Sopenharmony_ci * of the current frame size so the information can be found 908c2ecf20Sopenharmony_ci * in other places 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* DP1..14 registers */ 948c2ecf20Sopenharmony_ci for (i = 1; SDW_VALID_PORT_RANGE(i); i++) { 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* DPi registers */ 978c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i); 988c2ecf20Sopenharmony_ci for (j = SDW_DPN_INT(i); j <= SDW_DPN_PREPARECTRL(i); j++) 998c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, j); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* DPi Bank0 registers */ 1028c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n"); 1038c2ecf20Sopenharmony_ci for (j = SDW_DPN_CHANNELEN_B0(i); 1048c2ecf20Sopenharmony_ci j <= SDW_DPN_LANECTRL_B0(i); j++) 1058c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, j); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* DPi Bank1 registers */ 1088c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n"); 1098c2ecf20Sopenharmony_ci for (j = SDW_DPN_CHANNELEN_B1(i); 1108c2ecf20Sopenharmony_ci j <= SDW_DPN_LANECTRL_B1(i); j++) 1118c2ecf20Sopenharmony_ci ret += sdw_sprintf(slave, buf, ret, j); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci seq_printf(s_file, "%s", buf); 1158c2ecf20Sopenharmony_ci kfree(buf); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(sdw_slave_reg); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_civoid sdw_slave_debugfs_init(struct sdw_slave *slave) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct dentry *master; 1248c2ecf20Sopenharmony_ci struct dentry *d; 1258c2ecf20Sopenharmony_ci char name[32]; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci master = slave->bus->debugfs; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* create the debugfs slave-name */ 1308c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s", dev_name(&slave->dev)); 1318c2ecf20Sopenharmony_ci d = debugfs_create_dir(name, master); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci slave->debugfs = d; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_civoid sdw_slave_debugfs_exit(struct sdw_slave *slave) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci debugfs_remove_recursive(slave->debugfs); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_civoid sdw_debugfs_init(void) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci sdw_debugfs_root = debugfs_create_dir("soundwire", NULL); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_civoid sdw_debugfs_exit(void) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci debugfs_remove_recursive(sdw_debugfs_root); 1518c2ecf20Sopenharmony_ci} 152