Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
musb_debugfs.c
Go to the documentation of this file.
1 /*
2  * MUSB OTG driver debugfs support
3  *
4  * Copyright 2010 Nokia Corporation
5  * Contact: Felipe Balbi <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  *
21  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
24  * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/init.h>
37 #include <linux/debugfs.h>
38 #include <linux/seq_file.h>
39 
40 #include <asm/uaccess.h>
41 
42 #include "musb_core.h"
43 #include "musb_debug.h"
44 
46  char *name;
47  unsigned offset;
48  unsigned size;
49 };
50 
51 static const struct musb_register_map musb_regmap[] = {
52  { "FAddr", 0x00, 8 },
53  { "Power", 0x01, 8 },
54  { "Frame", 0x0c, 16 },
55  { "Index", 0x0e, 8 },
56  { "Testmode", 0x0f, 8 },
57  { "TxMaxPp", 0x10, 16 },
58  { "TxCSRp", 0x12, 16 },
59  { "RxMaxPp", 0x14, 16 },
60  { "RxCSR", 0x16, 16 },
61  { "RxCount", 0x18, 16 },
62  { "ConfigData", 0x1f, 8 },
63  { "DevCtl", 0x60, 8 },
64  { "MISC", 0x61, 8 },
65  { "TxFIFOsz", 0x62, 8 },
66  { "RxFIFOsz", 0x63, 8 },
67  { "TxFIFOadd", 0x64, 16 },
68  { "RxFIFOadd", 0x66, 16 },
69  { "VControl", 0x68, 32 },
70  { "HWVers", 0x6C, 16 },
71  { "EPInfo", 0x78, 8 },
72  { "RAMInfo", 0x79, 8 },
73  { "LinkInfo", 0x7A, 8 },
74  { "VPLen", 0x7B, 8 },
75  { "HS_EOF1", 0x7C, 8 },
76  { "FS_EOF1", 0x7D, 8 },
77  { "LS_EOF1", 0x7E, 8 },
78  { "SOFT_RST", 0x7F, 8 },
79  { "DMA_CNTLch0", 0x204, 16 },
80  { "DMA_ADDRch0", 0x208, 32 },
81  { "DMA_COUNTch0", 0x20C, 32 },
82  { "DMA_CNTLch1", 0x214, 16 },
83  { "DMA_ADDRch1", 0x218, 32 },
84  { "DMA_COUNTch1", 0x21C, 32 },
85  { "DMA_CNTLch2", 0x224, 16 },
86  { "DMA_ADDRch2", 0x228, 32 },
87  { "DMA_COUNTch2", 0x22C, 32 },
88  { "DMA_CNTLch3", 0x234, 16 },
89  { "DMA_ADDRch3", 0x238, 32 },
90  { "DMA_COUNTch3", 0x23C, 32 },
91  { "DMA_CNTLch4", 0x244, 16 },
92  { "DMA_ADDRch4", 0x248, 32 },
93  { "DMA_COUNTch4", 0x24C, 32 },
94  { "DMA_CNTLch5", 0x254, 16 },
95  { "DMA_ADDRch5", 0x258, 32 },
96  { "DMA_COUNTch5", 0x25C, 32 },
97  { "DMA_CNTLch6", 0x264, 16 },
98  { "DMA_ADDRch6", 0x268, 32 },
99  { "DMA_COUNTch6", 0x26C, 32 },
100  { "DMA_CNTLch7", 0x274, 16 },
101  { "DMA_ADDRch7", 0x278, 32 },
102  { "DMA_COUNTch7", 0x27C, 32 },
103  { } /* Terminating Entry */
104 };
105 
106 static int musb_regdump_show(struct seq_file *s, void *unused)
107 {
108  struct musb *musb = s->private;
109  unsigned i;
110 
111  seq_printf(s, "MUSB (M)HDRC Register Dump\n");
112 
113  for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
114  switch (musb_regmap[i].size) {
115  case 8:
116  seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name,
117  musb_readb(musb->mregs, musb_regmap[i].offset));
118  break;
119  case 16:
120  seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name,
121  musb_readw(musb->mregs, musb_regmap[i].offset));
122  break;
123  case 32:
124  seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name,
125  musb_readl(musb->mregs, musb_regmap[i].offset));
126  break;
127  }
128  }
129 
130  return 0;
131 }
132 
133 static int musb_regdump_open(struct inode *inode, struct file *file)
134 {
135  return single_open(file, musb_regdump_show, inode->i_private);
136 }
137 
138 static int musb_test_mode_show(struct seq_file *s, void *unused)
139 {
140  struct musb *musb = s->private;
141  unsigned test;
142 
143  test = musb_readb(musb->mregs, MUSB_TESTMODE);
144 
145  if (test & MUSB_TEST_FORCE_HOST)
146  seq_printf(s, "force host\n");
147 
148  if (test & MUSB_TEST_FIFO_ACCESS)
149  seq_printf(s, "fifo access\n");
150 
151  if (test & MUSB_TEST_FORCE_FS)
152  seq_printf(s, "force full-speed\n");
153 
154  if (test & MUSB_TEST_FORCE_HS)
155  seq_printf(s, "force high-speed\n");
156 
157  if (test & MUSB_TEST_PACKET)
158  seq_printf(s, "test packet\n");
159 
160  if (test & MUSB_TEST_K)
161  seq_printf(s, "test K\n");
162 
163  if (test & MUSB_TEST_J)
164  seq_printf(s, "test J\n");
165 
166  if (test & MUSB_TEST_SE0_NAK)
167  seq_printf(s, "test SE0 NAK\n");
168 
169  return 0;
170 }
171 
172 static const struct file_operations musb_regdump_fops = {
173  .open = musb_regdump_open,
174  .read = seq_read,
175  .llseek = seq_lseek,
176  .release = single_release,
177 };
178 
179 static int musb_test_mode_open(struct inode *inode, struct file *file)
180 {
181  return single_open(file, musb_test_mode_show, inode->i_private);
182 }
183 
184 static ssize_t musb_test_mode_write(struct file *file,
185  const char __user *ubuf, size_t count, loff_t *ppos)
186 {
187  struct seq_file *s = file->private_data;
188  struct musb *musb = s->private;
189  u8 test = 0;
190  char buf[18];
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 (!strncmp(buf, "force host", 9))
198  test = MUSB_TEST_FORCE_HOST;
199 
200  if (!strncmp(buf, "fifo access", 11))
201  test = MUSB_TEST_FIFO_ACCESS;
202 
203  if (!strncmp(buf, "force full-speed", 15))
204  test = MUSB_TEST_FORCE_FS;
205 
206  if (!strncmp(buf, "force high-speed", 15))
207  test = MUSB_TEST_FORCE_HS;
208 
209  if (!strncmp(buf, "test packet", 10)) {
210  test = MUSB_TEST_PACKET;
211  musb_load_testpacket(musb);
212  }
213 
214  if (!strncmp(buf, "test K", 6))
215  test = MUSB_TEST_K;
216 
217  if (!strncmp(buf, "test J", 6))
218  test = MUSB_TEST_J;
219 
220  if (!strncmp(buf, "test SE0 NAK", 12))
221  test = MUSB_TEST_SE0_NAK;
222 
223  musb_writeb(musb->mregs, MUSB_TESTMODE, test);
224 
225  return count;
226 }
227 
228 static const struct file_operations musb_test_mode_fops = {
229  .open = musb_test_mode_open,
230  .write = musb_test_mode_write,
231  .read = seq_read,
232  .llseek = seq_lseek,
233  .release = single_release,
234 };
235 
236 int __devinit musb_init_debugfs(struct musb *musb)
237 {
238  struct dentry *root;
239  struct dentry *file;
240  int ret;
241 
242  root = debugfs_create_dir(dev_name(musb->controller), NULL);
243  if (!root) {
244  ret = -ENOMEM;
245  goto err0;
246  }
247 
248  file = debugfs_create_file("regdump", S_IRUGO, root, musb,
249  &musb_regdump_fops);
250  if (!file) {
251  ret = -ENOMEM;
252  goto err1;
253  }
254 
255  file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
256  root, musb, &musb_test_mode_fops);
257  if (!file) {
258  ret = -ENOMEM;
259  goto err1;
260  }
261 
262  musb->debugfs_root = root;
263 
264  return 0;
265 
266 err1:
268 
269 err0:
270  return ret;
271 }
272 
273 void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
274 {
275  debugfs_remove_recursive(musb->debugfs_root);
276 }