Merge remote-tracking branches 'asoc/topic/ts3a227e', 'asoc/topic/tsc42xx', 'asoc...
[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 #ifndef CONFIG_BLACKFIN
74         { "ConfigData", MUSB_CONFIGDATA,8 },
75         { "BabbleCtl",  MUSB_BABBLE_CTL,8 },
76         { "TxFIFOsz",   MUSB_TXFIFOSZ,  8 },
77         { "RxFIFOsz",   MUSB_RXFIFOSZ,  8 },
78         { "TxFIFOadd",  MUSB_TXFIFOADD, 16 },
79         { "RxFIFOadd",  MUSB_RXFIFOADD, 16 },
80         { "EPInfo",     MUSB_EPINFO,    8 },
81         { "RAMInfo",    MUSB_RAMINFO,   8 },
82 #endif
83         {  }    /* Terminating Entry */
84 };
85
86 static int musb_regdump_show(struct seq_file *s, void *unused)
87 {
88         struct musb             *musb = s->private;
89         unsigned                i;
90
91         seq_printf(s, "MUSB (M)HDRC Register Dump\n");
92         pm_runtime_get_sync(musb->controller);
93
94         for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
95                 switch (musb_regmap[i].size) {
96                 case 8:
97                         seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name,
98                                         musb_readb(musb->mregs, musb_regmap[i].offset));
99                         break;
100                 case 16:
101                         seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name,
102                                         musb_readw(musb->mregs, musb_regmap[i].offset));
103                         break;
104                 case 32:
105                         seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name,
106                                         musb_readl(musb->mregs, musb_regmap[i].offset));
107                         break;
108                 }
109         }
110
111         pm_runtime_mark_last_busy(musb->controller);
112         pm_runtime_put_autosuspend(musb->controller);
113         return 0;
114 }
115
116 static int musb_regdump_open(struct inode *inode, struct file *file)
117 {
118         return single_open(file, musb_regdump_show, inode->i_private);
119 }
120
121 static int musb_test_mode_show(struct seq_file *s, void *unused)
122 {
123         struct musb             *musb = s->private;
124         unsigned                test;
125
126         pm_runtime_get_sync(musb->controller);
127         test = musb_readb(musb->mregs, MUSB_TESTMODE);
128         pm_runtime_mark_last_busy(musb->controller);
129         pm_runtime_put_autosuspend(musb->controller);
130
131         if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS))
132                 seq_printf(s, "force host full-speed\n");
133
134         else if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS))
135                 seq_printf(s, "force host high-speed\n");
136
137         else if (test == MUSB_TEST_FORCE_HOST)
138                 seq_printf(s, "force host\n");
139
140         else if (test == MUSB_TEST_FIFO_ACCESS)
141                 seq_printf(s, "fifo access\n");
142
143         else if (test == MUSB_TEST_FORCE_FS)
144                 seq_printf(s, "force full-speed\n");
145
146         else if (test == MUSB_TEST_FORCE_HS)
147                 seq_printf(s, "force high-speed\n");
148
149         else if (test == MUSB_TEST_PACKET)
150                 seq_printf(s, "test packet\n");
151
152         else if (test == MUSB_TEST_K)
153                 seq_printf(s, "test K\n");
154
155         else if (test == MUSB_TEST_J)
156                 seq_printf(s, "test J\n");
157
158         else if (test == MUSB_TEST_SE0_NAK)
159                 seq_printf(s, "test SE0 NAK\n");
160
161         return 0;
162 }
163
164 static const struct file_operations musb_regdump_fops = {
165         .open                   = musb_regdump_open,
166         .read                   = seq_read,
167         .llseek                 = seq_lseek,
168         .release                = single_release,
169 };
170
171 static int musb_test_mode_open(struct inode *inode, struct file *file)
172 {
173         return single_open(file, musb_test_mode_show, inode->i_private);
174 }
175
176 static ssize_t musb_test_mode_write(struct file *file,
177                 const char __user *ubuf, size_t count, loff_t *ppos)
178 {
179         struct seq_file         *s = file->private_data;
180         struct musb             *musb = s->private;
181         u8                      test;
182         char                    buf[24];
183
184         pm_runtime_get_sync(musb->controller);
185         test = musb_readb(musb->mregs, MUSB_TESTMODE);
186         if (test) {
187                 dev_err(musb->controller, "Error: test mode is already set. "
188                         "Please do USB Bus Reset to start a new test.\n");
189                 goto ret;
190         }
191
192         memset(buf, 0x00, sizeof(buf));
193
194         if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
195                 return -EFAULT;
196
197         if (strstarts(buf, "force host full-speed"))
198                 test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS;
199
200         else if (strstarts(buf, "force host high-speed"))
201                 test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS;
202
203         else if (strstarts(buf, "force host"))
204                 test = MUSB_TEST_FORCE_HOST;
205
206         else if (strstarts(buf, "fifo access"))
207                 test = MUSB_TEST_FIFO_ACCESS;
208
209         else if (strstarts(buf, "force full-speed"))
210                 test = MUSB_TEST_FORCE_FS;
211
212         else if (strstarts(buf, "force high-speed"))
213                 test = MUSB_TEST_FORCE_HS;
214
215         else if (strstarts(buf, "test packet")) {
216                 test = MUSB_TEST_PACKET;
217                 musb_load_testpacket(musb);
218         }
219
220         else if (strstarts(buf, "test K"))
221                 test = MUSB_TEST_K;
222
223         else if (strstarts(buf, "test J"))
224                 test = MUSB_TEST_J;
225
226         else if (strstarts(buf, "test SE0 NAK"))
227                 test = MUSB_TEST_SE0_NAK;
228
229         musb_writeb(musb->mregs, MUSB_TESTMODE, test);
230
231 ret:
232         pm_runtime_mark_last_busy(musb->controller);
233         pm_runtime_put_autosuspend(musb->controller);
234         return count;
235 }
236
237 static const struct file_operations musb_test_mode_fops = {
238         .open                   = musb_test_mode_open,
239         .write                  = musb_test_mode_write,
240         .read                   = seq_read,
241         .llseek                 = seq_lseek,
242         .release                = single_release,
243 };
244
245 static int musb_softconnect_show(struct seq_file *s, void *unused)
246 {
247         struct musb     *musb = s->private;
248         u8              reg;
249         int             connect;
250
251         switch (musb->xceiv->otg->state) {
252         case OTG_STATE_A_HOST:
253         case OTG_STATE_A_WAIT_BCON:
254                 pm_runtime_get_sync(musb->controller);
255
256                 reg = musb_readb(musb->mregs, MUSB_DEVCTL);
257                 connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
258
259                 pm_runtime_mark_last_busy(musb->controller);
260                 pm_runtime_put_autosuspend(musb->controller);
261                 break;
262         default:
263                 connect = -1;
264         }
265
266         seq_printf(s, "%d\n", connect);
267
268         return 0;
269 }
270
271 static int musb_softconnect_open(struct inode *inode, struct file *file)
272 {
273         return single_open(file, musb_softconnect_show, inode->i_private);
274 }
275
276 static ssize_t musb_softconnect_write(struct file *file,
277                 const char __user *ubuf, size_t count, loff_t *ppos)
278 {
279         struct seq_file         *s = file->private_data;
280         struct musb             *musb = s->private;
281         char                    buf[2];
282         u8                      reg;
283
284         memset(buf, 0x00, sizeof(buf));
285
286         if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
287                 return -EFAULT;
288
289         pm_runtime_get_sync(musb->controller);
290         if (!strncmp(buf, "0", 1)) {
291                 switch (musb->xceiv->otg->state) {
292                 case OTG_STATE_A_HOST:
293                         musb_root_disconnect(musb);
294                         reg = musb_readb(musb->mregs, MUSB_DEVCTL);
295                         reg &= ~MUSB_DEVCTL_SESSION;
296                         musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
297                         break;
298                 default:
299                         break;
300                 }
301         } else if (!strncmp(buf, "1", 1)) {
302                 switch (musb->xceiv->otg->state) {
303                 case OTG_STATE_A_WAIT_BCON:
304                         /*
305                          * musb_save_context() called in musb_runtime_suspend()
306                          * might cache devctl with SESSION bit cleared during
307                          * soft-disconnect, so specifically set SESSION bit
308                          * here to preserve it for musb_runtime_resume().
309                          */
310                         musb->context.devctl |= MUSB_DEVCTL_SESSION;
311                         reg = musb_readb(musb->mregs, MUSB_DEVCTL);
312                         reg |= MUSB_DEVCTL_SESSION;
313                         musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
314                         break;
315                 default:
316                         break;
317                 }
318         }
319
320         pm_runtime_mark_last_busy(musb->controller);
321         pm_runtime_put_autosuspend(musb->controller);
322         return count;
323 }
324
325 /*
326  * In host mode, connect/disconnect the bus without physically
327  * remove the devices.
328  */
329 static const struct file_operations musb_softconnect_fops = {
330         .open                   = musb_softconnect_open,
331         .write                  = musb_softconnect_write,
332         .read                   = seq_read,
333         .llseek                 = seq_lseek,
334         .release                = single_release,
335 };
336
337 int musb_init_debugfs(struct musb *musb)
338 {
339         struct dentry           *root;
340         struct dentry           *file;
341         int                     ret;
342
343         root = debugfs_create_dir(dev_name(musb->controller), NULL);
344         if (!root) {
345                 ret = -ENOMEM;
346                 goto err0;
347         }
348
349         file = debugfs_create_file("regdump", S_IRUGO, root, musb,
350                         &musb_regdump_fops);
351         if (!file) {
352                 ret = -ENOMEM;
353                 goto err1;
354         }
355
356         file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
357                         root, musb, &musb_test_mode_fops);
358         if (!file) {
359                 ret = -ENOMEM;
360                 goto err1;
361         }
362
363         file = debugfs_create_file("softconnect", S_IRUGO | S_IWUSR,
364                         root, musb, &musb_softconnect_fops);
365         if (!file) {
366                 ret = -ENOMEM;
367                 goto err1;
368         }
369
370         musb->debugfs_root = root;
371
372         return 0;
373
374 err1:
375         debugfs_remove_recursive(root);
376
377 err0:
378         return ret;
379 }
380
381 void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
382 {
383         debugfs_remove_recursive(musb->debugfs_root);
384 }