Merge tag 'hsi-for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi
[linux-2.6-microblaze.git] / drivers / usb / musb / musb_debugfs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MUSB OTG driver debugfs support
4  *
5  * Copyright 2010 Nokia Corporation
6  * Contact: Felipe Balbi <felipe.balbi@nokia.com>
7  */
8
9 #include <linux/module.h>
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/debugfs.h>
13 #include <linux/seq_file.h>
14
15 #include <linux/uaccess.h>
16
17 #include "musb_core.h"
18 #include "musb_debug.h"
19
20 struct musb_register_map {
21         char                    *name;
22         unsigned                offset;
23         unsigned                size;
24 };
25
26 static const struct musb_register_map musb_regmap[] = {
27         { "FAddr",      MUSB_FADDR,     8 },
28         { "Power",      MUSB_POWER,     8 },
29         { "Frame",      MUSB_FRAME,     16 },
30         { "Index",      MUSB_INDEX,     8 },
31         { "Testmode",   MUSB_TESTMODE,  8 },
32         { "TxMaxPp",    MUSB_TXMAXP,    16 },
33         { "TxCSRp",     MUSB_TXCSR,     16 },
34         { "RxMaxPp",    MUSB_RXMAXP,    16 },
35         { "RxCSR",      MUSB_RXCSR,     16 },
36         { "RxCount",    MUSB_RXCOUNT,   16 },
37         { "IntrRxE",    MUSB_INTRRXE,   16 },
38         { "IntrTxE",    MUSB_INTRTXE,   16 },
39         { "IntrUsbE",   MUSB_INTRUSBE,  8 },
40         { "DevCtl",     MUSB_DEVCTL,    8 },
41         { "VControl",   0x68,           32 },
42         { "HWVers",     0x69,           16 },
43         { "LinkInfo",   MUSB_LINKINFO,  8 },
44         { "VPLen",      MUSB_VPLEN,     8 },
45         { "HS_EOF1",    MUSB_HS_EOF1,   8 },
46         { "FS_EOF1",    MUSB_FS_EOF1,   8 },
47         { "LS_EOF1",    MUSB_LS_EOF1,   8 },
48         { "SOFT_RST",   0x7F,           8 },
49         { "DMA_CNTLch0",        0x204,  16 },
50         { "DMA_ADDRch0",        0x208,  32 },
51         { "DMA_COUNTch0",       0x20C,  32 },
52         { "DMA_CNTLch1",        0x214,  16 },
53         { "DMA_ADDRch1",        0x218,  32 },
54         { "DMA_COUNTch1",       0x21C,  32 },
55         { "DMA_CNTLch2",        0x224,  16 },
56         { "DMA_ADDRch2",        0x228,  32 },
57         { "DMA_COUNTch2",       0x22C,  32 },
58         { "DMA_CNTLch3",        0x234,  16 },
59         { "DMA_ADDRch3",        0x238,  32 },
60         { "DMA_COUNTch3",       0x23C,  32 },
61         { "DMA_CNTLch4",        0x244,  16 },
62         { "DMA_ADDRch4",        0x248,  32 },
63         { "DMA_COUNTch4",       0x24C,  32 },
64         { "DMA_CNTLch5",        0x254,  16 },
65         { "DMA_ADDRch5",        0x258,  32 },
66         { "DMA_COUNTch5",       0x25C,  32 },
67         { "DMA_CNTLch6",        0x264,  16 },
68         { "DMA_ADDRch6",        0x268,  32 },
69         { "DMA_COUNTch6",       0x26C,  32 },
70         { "DMA_CNTLch7",        0x274,  16 },
71         { "DMA_ADDRch7",        0x278,  32 },
72         { "DMA_COUNTch7",       0x27C,  32 },
73         { "ConfigData", MUSB_CONFIGDATA,8 },
74         { "BabbleCtl",  MUSB_BABBLE_CTL,8 },
75         { "TxFIFOsz",   MUSB_TXFIFOSZ,  8 },
76         { "RxFIFOsz",   MUSB_RXFIFOSZ,  8 },
77         { "TxFIFOadd",  MUSB_TXFIFOADD, 16 },
78         { "RxFIFOadd",  MUSB_RXFIFOADD, 16 },
79         { "EPInfo",     MUSB_EPINFO,    8 },
80         { "RAMInfo",    MUSB_RAMINFO,   8 },
81         {  }    /* Terminating Entry */
82 };
83
84 static int musb_regdump_show(struct seq_file *s, void *unused)
85 {
86         struct musb             *musb = s->private;
87         unsigned                i;
88
89         seq_printf(s, "MUSB (M)HDRC Register Dump\n");
90         pm_runtime_get_sync(musb->controller);
91
92         for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
93                 switch (musb_regmap[i].size) {
94                 case 8:
95                         seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name,
96                                         musb_readb(musb->mregs, musb_regmap[i].offset));
97                         break;
98                 case 16:
99                         seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name,
100                                         musb_readw(musb->mregs, musb_regmap[i].offset));
101                         break;
102                 case 32:
103                         seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name,
104                                         musb_readl(musb->mregs, musb_regmap[i].offset));
105                         break;
106                 }
107         }
108
109         pm_runtime_mark_last_busy(musb->controller);
110         pm_runtime_put_autosuspend(musb->controller);
111         return 0;
112 }
113 DEFINE_SHOW_ATTRIBUTE(musb_regdump);
114
115 static int musb_test_mode_show(struct seq_file *s, void *unused)
116 {
117         struct musb             *musb = s->private;
118         unsigned                test;
119
120         pm_runtime_get_sync(musb->controller);
121         test = musb_readb(musb->mregs, MUSB_TESTMODE);
122         pm_runtime_mark_last_busy(musb->controller);
123         pm_runtime_put_autosuspend(musb->controller);
124
125         if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS))
126                 seq_printf(s, "force host full-speed\n");
127
128         else if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS))
129                 seq_printf(s, "force host high-speed\n");
130
131         else if (test == MUSB_TEST_FORCE_HOST)
132                 seq_printf(s, "force host\n");
133
134         else if (test == MUSB_TEST_FIFO_ACCESS)
135                 seq_printf(s, "fifo access\n");
136
137         else if (test == MUSB_TEST_FORCE_FS)
138                 seq_printf(s, "force full-speed\n");
139
140         else if (test == MUSB_TEST_FORCE_HS)
141                 seq_printf(s, "force high-speed\n");
142
143         else if (test == MUSB_TEST_PACKET)
144                 seq_printf(s, "test packet\n");
145
146         else if (test == MUSB_TEST_K)
147                 seq_printf(s, "test K\n");
148
149         else if (test == MUSB_TEST_J)
150                 seq_printf(s, "test J\n");
151
152         else if (test == MUSB_TEST_SE0_NAK)
153                 seq_printf(s, "test SE0 NAK\n");
154
155         return 0;
156 }
157
158 static int musb_test_mode_open(struct inode *inode, struct file *file)
159 {
160         return single_open(file, musb_test_mode_show, inode->i_private);
161 }
162
163 static ssize_t musb_test_mode_write(struct file *file,
164                 const char __user *ubuf, size_t count, loff_t *ppos)
165 {
166         struct seq_file         *s = file->private_data;
167         struct musb             *musb = s->private;
168         u8                      test;
169         char                    buf[24];
170
171         memset(buf, 0x00, sizeof(buf));
172
173         if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
174                 return -EFAULT;
175
176         pm_runtime_get_sync(musb->controller);
177         test = musb_readb(musb->mregs, MUSB_TESTMODE);
178         if (test) {
179                 dev_err(musb->controller, "Error: test mode is already set. "
180                         "Please do USB Bus Reset to start a new test.\n");
181                 goto ret;
182         }
183
184         if (strstarts(buf, "force host full-speed"))
185                 test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS;
186
187         else if (strstarts(buf, "force host high-speed"))
188                 test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS;
189
190         else if (strstarts(buf, "force host"))
191                 test = MUSB_TEST_FORCE_HOST;
192
193         else if (strstarts(buf, "fifo access"))
194                 test = MUSB_TEST_FIFO_ACCESS;
195
196         else if (strstarts(buf, "force full-speed"))
197                 test = MUSB_TEST_FORCE_FS;
198
199         else if (strstarts(buf, "force high-speed"))
200                 test = MUSB_TEST_FORCE_HS;
201
202         else if (strstarts(buf, "test packet")) {
203                 test = MUSB_TEST_PACKET;
204                 musb_load_testpacket(musb);
205         }
206
207         else if (strstarts(buf, "test K"))
208                 test = MUSB_TEST_K;
209
210         else if (strstarts(buf, "test J"))
211                 test = MUSB_TEST_J;
212
213         else if (strstarts(buf, "test SE0 NAK"))
214                 test = MUSB_TEST_SE0_NAK;
215
216         musb_writeb(musb->mregs, MUSB_TESTMODE, test);
217
218 ret:
219         pm_runtime_mark_last_busy(musb->controller);
220         pm_runtime_put_autosuspend(musb->controller);
221         return count;
222 }
223
224 static const struct file_operations musb_test_mode_fops = {
225         .open                   = musb_test_mode_open,
226         .write                  = musb_test_mode_write,
227         .read                   = seq_read,
228         .llseek                 = seq_lseek,
229         .release                = single_release,
230 };
231
232 static int musb_softconnect_show(struct seq_file *s, void *unused)
233 {
234         struct musb     *musb = s->private;
235         u8              reg;
236         int             connect;
237
238         switch (musb->xceiv->otg->state) {
239         case OTG_STATE_A_HOST:
240         case OTG_STATE_A_WAIT_BCON:
241                 pm_runtime_get_sync(musb->controller);
242
243                 reg = musb_readb(musb->mregs, MUSB_DEVCTL);
244                 connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
245
246                 pm_runtime_mark_last_busy(musb->controller);
247                 pm_runtime_put_autosuspend(musb->controller);
248                 break;
249         default:
250                 connect = -1;
251         }
252
253         seq_printf(s, "%d\n", connect);
254
255         return 0;
256 }
257
258 static int musb_softconnect_open(struct inode *inode, struct file *file)
259 {
260         return single_open(file, musb_softconnect_show, inode->i_private);
261 }
262
263 static ssize_t musb_softconnect_write(struct file *file,
264                 const char __user *ubuf, size_t count, loff_t *ppos)
265 {
266         struct seq_file         *s = file->private_data;
267         struct musb             *musb = s->private;
268         char                    buf[2];
269         u8                      reg;
270
271         memset(buf, 0x00, sizeof(buf));
272
273         if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
274                 return -EFAULT;
275
276         pm_runtime_get_sync(musb->controller);
277         if (!strncmp(buf, "0", 1)) {
278                 switch (musb->xceiv->otg->state) {
279                 case OTG_STATE_A_HOST:
280                         musb_root_disconnect(musb);
281                         reg = musb_readb(musb->mregs, MUSB_DEVCTL);
282                         reg &= ~MUSB_DEVCTL_SESSION;
283                         musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
284                         break;
285                 default:
286                         break;
287                 }
288         } else if (!strncmp(buf, "1", 1)) {
289                 switch (musb->xceiv->otg->state) {
290                 case OTG_STATE_A_WAIT_BCON:
291                         /*
292                          * musb_save_context() called in musb_runtime_suspend()
293                          * might cache devctl with SESSION bit cleared during
294                          * soft-disconnect, so specifically set SESSION bit
295                          * here to preserve it for musb_runtime_resume().
296                          */
297                         musb->context.devctl |= MUSB_DEVCTL_SESSION;
298                         reg = musb_readb(musb->mregs, MUSB_DEVCTL);
299                         reg |= MUSB_DEVCTL_SESSION;
300                         musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
301                         break;
302                 default:
303                         break;
304                 }
305         }
306
307         pm_runtime_mark_last_busy(musb->controller);
308         pm_runtime_put_autosuspend(musb->controller);
309         return count;
310 }
311
312 /*
313  * In host mode, connect/disconnect the bus without physically
314  * remove the devices.
315  */
316 static const struct file_operations musb_softconnect_fops = {
317         .open                   = musb_softconnect_open,
318         .write                  = musb_softconnect_write,
319         .read                   = seq_read,
320         .llseek                 = seq_lseek,
321         .release                = single_release,
322 };
323
324 void musb_init_debugfs(struct musb *musb)
325 {
326         struct dentry *root;
327
328         root = debugfs_create_dir(dev_name(musb->controller), usb_debug_root);
329         musb->debugfs_root = root;
330
331         debugfs_create_file("regdump", S_IRUGO, root, musb, &musb_regdump_fops);
332         debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, musb,
333                             &musb_test_mode_fops);
334         debugfs_create_file("softconnect", S_IRUGO | S_IWUSR, root, musb,
335                             &musb_softconnect_fops);
336 }
337
338 void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
339 {
340         debugfs_remove_recursive(musb->debugfs_root);
341 }