1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun // Copyright(c) 2017-2019 Intel Corporation.
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/device.h>
5*4882a593Smuzhiyun #include <linux/debugfs.h>
6*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
7*4882a593Smuzhiyun #include <linux/slab.h>
8*4882a593Smuzhiyun #include <linux/soundwire/sdw.h>
9*4882a593Smuzhiyun #include <linux/soundwire/sdw_registers.h>
10*4882a593Smuzhiyun #include "bus.h"
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun static struct dentry *sdw_debugfs_root;
13*4882a593Smuzhiyun
sdw_bus_debugfs_init(struct sdw_bus * bus)14*4882a593Smuzhiyun void sdw_bus_debugfs_init(struct sdw_bus *bus)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun char name[16];
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun if (!sdw_debugfs_root)
19*4882a593Smuzhiyun return;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* create the debugfs master-N */
22*4882a593Smuzhiyun snprintf(name, sizeof(name), "master-%d-%d", bus->id, bus->link_id);
23*4882a593Smuzhiyun bus->debugfs = debugfs_create_dir(name, sdw_debugfs_root);
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun
sdw_bus_debugfs_exit(struct sdw_bus * bus)26*4882a593Smuzhiyun void sdw_bus_debugfs_exit(struct sdw_bus *bus)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun debugfs_remove_recursive(bus->debugfs);
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define RD_BUF (3 * PAGE_SIZE)
32*4882a593Smuzhiyun
sdw_sprintf(struct sdw_slave * slave,char * buf,size_t pos,unsigned int reg)33*4882a593Smuzhiyun static ssize_t sdw_sprintf(struct sdw_slave *slave,
34*4882a593Smuzhiyun char *buf, size_t pos, unsigned int reg)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun int value;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun value = sdw_read(slave, reg);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if (value < 0)
41*4882a593Smuzhiyun return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
42*4882a593Smuzhiyun else
43*4882a593Smuzhiyun return scnprintf(buf + pos, RD_BUF - pos,
44*4882a593Smuzhiyun "%3x\t%2x\n", reg, value);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
sdw_slave_reg_show(struct seq_file * s_file,void * data)47*4882a593Smuzhiyun static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun struct sdw_slave *slave = s_file->private;
50*4882a593Smuzhiyun char *buf;
51*4882a593Smuzhiyun ssize_t ret;
52*4882a593Smuzhiyun int i, j;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun buf = kzalloc(RD_BUF, GFP_KERNEL);
55*4882a593Smuzhiyun if (!buf)
56*4882a593Smuzhiyun return -ENOMEM;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun ret = scnprintf(buf, RD_BUF, "Register Value\n");
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* DP0 non-banked registers */
61*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
62*4882a593Smuzhiyun for (i = SDW_DP0_INT; i <= SDW_DP0_PREPARECTRL; i++)
63*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, i);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* DP0 Bank 0 registers */
66*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
67*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
68*4882a593Smuzhiyun for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
69*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, i);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* DP0 Bank 1 registers */
72*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
73*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret,
74*4882a593Smuzhiyun SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
75*4882a593Smuzhiyun for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
76*4882a593Smuzhiyun i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
77*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, i);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* SCP registers */
80*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
81*4882a593Smuzhiyun for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++)
82*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, i);
83*4882a593Smuzhiyun for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
84*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, i);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /*
87*4882a593Smuzhiyun * SCP Bank 0/1 registers are read-only and cannot be
88*4882a593Smuzhiyun * retrieved from the Slave. The Master typically keeps track
89*4882a593Smuzhiyun * of the current frame size so the information can be found
90*4882a593Smuzhiyun * in other places
91*4882a593Smuzhiyun */
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /* DP1..14 registers */
94*4882a593Smuzhiyun for (i = 1; SDW_VALID_PORT_RANGE(i); i++) {
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* DPi registers */
97*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
98*4882a593Smuzhiyun for (j = SDW_DPN_INT(i); j <= SDW_DPN_PREPARECTRL(i); j++)
99*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, j);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* DPi Bank0 registers */
102*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
103*4882a593Smuzhiyun for (j = SDW_DPN_CHANNELEN_B0(i);
104*4882a593Smuzhiyun j <= SDW_DPN_LANECTRL_B0(i); j++)
105*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, j);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* DPi Bank1 registers */
108*4882a593Smuzhiyun ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
109*4882a593Smuzhiyun for (j = SDW_DPN_CHANNELEN_B1(i);
110*4882a593Smuzhiyun j <= SDW_DPN_LANECTRL_B1(i); j++)
111*4882a593Smuzhiyun ret += sdw_sprintf(slave, buf, ret, j);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun seq_printf(s_file, "%s", buf);
115*4882a593Smuzhiyun kfree(buf);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg);
120*4882a593Smuzhiyun
sdw_slave_debugfs_init(struct sdw_slave * slave)121*4882a593Smuzhiyun void sdw_slave_debugfs_init(struct sdw_slave *slave)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct dentry *master;
124*4882a593Smuzhiyun struct dentry *d;
125*4882a593Smuzhiyun char name[32];
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun master = slave->bus->debugfs;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* create the debugfs slave-name */
130*4882a593Smuzhiyun snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
131*4882a593Smuzhiyun d = debugfs_create_dir(name, master);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun slave->debugfs = d;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
sdw_slave_debugfs_exit(struct sdw_slave * slave)138*4882a593Smuzhiyun void sdw_slave_debugfs_exit(struct sdw_slave *slave)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun debugfs_remove_recursive(slave->debugfs);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
sdw_debugfs_init(void)143*4882a593Smuzhiyun void sdw_debugfs_init(void)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun sdw_debugfs_root = debugfs_create_dir("soundwire", NULL);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
sdw_debugfs_exit(void)148*4882a593Smuzhiyun void sdw_debugfs_exit(void)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun debugfs_remove_recursive(sdw_debugfs_root);
151*4882a593Smuzhiyun }
152