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", MUSB_HWVERS, 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_put_autosuspend(musb->controller); 110 return 0; 111 } 112 DEFINE_SHOW_ATTRIBUTE(musb_regdump); 113 114 static int musb_test_mode_show(struct seq_file *s, void *unused) 115 { 116 struct musb *musb = s->private; 117 unsigned test; 118 119 pm_runtime_get_sync(musb->controller); 120 test = musb_readb(musb->mregs, MUSB_TESTMODE); 121 pm_runtime_put_autosuspend(musb->controller); 122 123 if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS)) 124 seq_printf(s, "force host full-speed\n"); 125 126 else if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS)) 127 seq_printf(s, "force host high-speed\n"); 128 129 else if (test == MUSB_TEST_FORCE_HOST) 130 seq_printf(s, "force host\n"); 131 132 else if (test == MUSB_TEST_FIFO_ACCESS) 133 seq_printf(s, "fifo access\n"); 134 135 else if (test == MUSB_TEST_FORCE_FS) 136 seq_printf(s, "force full-speed\n"); 137 138 else if (test == MUSB_TEST_FORCE_HS) 139 seq_printf(s, "force high-speed\n"); 140 141 else if (test == MUSB_TEST_PACKET) 142 seq_printf(s, "test packet\n"); 143 144 else if (test == MUSB_TEST_K) 145 seq_printf(s, "test K\n"); 146 147 else if (test == MUSB_TEST_J) 148 seq_printf(s, "test J\n"); 149 150 else if (test == MUSB_TEST_SE0_NAK) 151 seq_printf(s, "test SE0 NAK\n"); 152 153 return 0; 154 } 155 156 static int musb_test_mode_open(struct inode *inode, struct file *file) 157 { 158 return single_open(file, musb_test_mode_show, inode->i_private); 159 } 160 161 static ssize_t musb_test_mode_write(struct file *file, 162 const char __user *ubuf, size_t count, loff_t *ppos) 163 { 164 struct seq_file *s = file->private_data; 165 struct musb *musb = s->private; 166 u8 test; 167 char buf[24]; 168 169 memset(buf, 0x00, sizeof(buf)); 170 171 if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 172 return -EFAULT; 173 174 pm_runtime_get_sync(musb->controller); 175 test = musb_readb(musb->mregs, MUSB_TESTMODE); 176 if (test) { 177 dev_err(musb->controller, "Error: test mode is already set. " 178 "Please do USB Bus Reset to start a new test.\n"); 179 goto ret; 180 } 181 182 if (strstarts(buf, "force host full-speed")) 183 test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS; 184 185 else if (strstarts(buf, "force host high-speed")) 186 test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS; 187 188 else if (strstarts(buf, "force host")) 189 test = MUSB_TEST_FORCE_HOST; 190 191 else if (strstarts(buf, "fifo access")) 192 test = MUSB_TEST_FIFO_ACCESS; 193 194 else if (strstarts(buf, "force full-speed")) 195 test = MUSB_TEST_FORCE_FS; 196 197 else if (strstarts(buf, "force high-speed")) 198 test = MUSB_TEST_FORCE_HS; 199 200 else if (strstarts(buf, "test packet")) { 201 test = MUSB_TEST_PACKET; 202 musb_load_testpacket(musb); 203 } 204 205 else if (strstarts(buf, "test K")) 206 test = MUSB_TEST_K; 207 208 else if (strstarts(buf, "test J")) 209 test = MUSB_TEST_J; 210 211 else if (strstarts(buf, "test SE0 NAK")) 212 test = MUSB_TEST_SE0_NAK; 213 214 musb_writeb(musb->mregs, MUSB_TESTMODE, test); 215 216 ret: 217 pm_runtime_put_autosuspend(musb->controller); 218 return count; 219 } 220 221 static const struct file_operations musb_test_mode_fops = { 222 .open = musb_test_mode_open, 223 .write = musb_test_mode_write, 224 .read = seq_read, 225 .llseek = seq_lseek, 226 .release = single_release, 227 }; 228 229 static int musb_softconnect_show(struct seq_file *s, void *unused) 230 { 231 struct musb *musb = s->private; 232 u8 reg; 233 int connect; 234 235 switch (musb_get_state(musb)) { 236 case OTG_STATE_A_HOST: 237 case OTG_STATE_A_WAIT_BCON: 238 pm_runtime_get_sync(musb->controller); 239 240 reg = musb_readb(musb->mregs, MUSB_DEVCTL); 241 connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0; 242 243 pm_runtime_put_autosuspend(musb->controller); 244 break; 245 default: 246 connect = -1; 247 } 248 249 seq_printf(s, "%d\n", connect); 250 251 return 0; 252 } 253 254 static int musb_softconnect_open(struct inode *inode, struct file *file) 255 { 256 return single_open(file, musb_softconnect_show, inode->i_private); 257 } 258 259 static ssize_t musb_softconnect_write(struct file *file, 260 const char __user *ubuf, size_t count, loff_t *ppos) 261 { 262 struct seq_file *s = file->private_data; 263 struct musb *musb = s->private; 264 char buf[2]; 265 u8 reg; 266 267 memset(buf, 0x00, sizeof(buf)); 268 269 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 270 return -EFAULT; 271 272 pm_runtime_get_sync(musb->controller); 273 if (!strncmp(buf, "0", 1)) { 274 switch (musb_get_state(musb)) { 275 case OTG_STATE_A_HOST: 276 musb_root_disconnect(musb); 277 reg = musb_readb(musb->mregs, MUSB_DEVCTL); 278 reg &= ~MUSB_DEVCTL_SESSION; 279 musb_writeb(musb->mregs, MUSB_DEVCTL, reg); 280 break; 281 default: 282 break; 283 } 284 } else if (!strncmp(buf, "1", 1)) { 285 switch (musb_get_state(musb)) { 286 case OTG_STATE_A_WAIT_BCON: 287 /* 288 * musb_save_context() called in musb_runtime_suspend() 289 * might cache devctl with SESSION bit cleared during 290 * soft-disconnect, so specifically set SESSION bit 291 * here to preserve it for musb_runtime_resume(). 292 */ 293 musb->context.devctl |= MUSB_DEVCTL_SESSION; 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 } 302 303 pm_runtime_put_autosuspend(musb->controller); 304 return count; 305 } 306 307 /* 308 * In host mode, connect/disconnect the bus without physically 309 * remove the devices. 310 */ 311 static const struct file_operations musb_softconnect_fops = { 312 .open = musb_softconnect_open, 313 .write = musb_softconnect_write, 314 .read = seq_read, 315 .llseek = seq_lseek, 316 .release = single_release, 317 }; 318 319 void musb_init_debugfs(struct musb *musb) 320 { 321 struct dentry *root; 322 323 root = debugfs_create_dir(dev_name(musb->controller), usb_debug_root); 324 musb->debugfs_root = root; 325 326 debugfs_create_file("regdump", S_IRUGO, root, musb, &musb_regdump_fops); 327 debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, musb, 328 &musb_test_mode_fops); 329 debugfs_create_file("softconnect", S_IRUGO | S_IWUSR, root, musb, 330 &musb_softconnect_fops); 331 } 332 333 void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb) 334 { 335 debugfs_remove_recursive(musb->debugfs_root); 336 } 337