Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * MUSB OTG driver debugfs support
0004  *
0005  * Copyright 2010 Nokia Corporation
0006  * Contact: Felipe Balbi <felipe.balbi@nokia.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/debugfs.h>
0013 #include <linux/seq_file.h>
0014 
0015 #include <linux/uaccess.h>
0016 
0017 #include "musb_core.h"
0018 #include "musb_debug.h"
0019 
0020 struct musb_register_map {
0021     char            *name;
0022     unsigned        offset;
0023     unsigned        size;
0024 };
0025 
0026 static const struct musb_register_map musb_regmap[] = {
0027     { "FAddr",  MUSB_FADDR, 8 },
0028     { "Power",  MUSB_POWER, 8 },
0029     { "Frame",  MUSB_FRAME, 16 },
0030     { "Index",  MUSB_INDEX, 8 },
0031     { "Testmode",   MUSB_TESTMODE,  8 },
0032     { "TxMaxPp",    MUSB_TXMAXP,    16 },
0033     { "TxCSRp", MUSB_TXCSR, 16 },
0034     { "RxMaxPp",    MUSB_RXMAXP,    16 },
0035     { "RxCSR",  MUSB_RXCSR, 16 },
0036     { "RxCount",    MUSB_RXCOUNT,   16 },
0037     { "IntrRxE",    MUSB_INTRRXE,   16 },
0038     { "IntrTxE",    MUSB_INTRTXE,   16 },
0039     { "IntrUsbE",   MUSB_INTRUSBE,  8 },
0040     { "DevCtl", MUSB_DEVCTL,    8 },
0041     { "VControl",   0x68,       32 },
0042     { "HWVers", 0x69,       16 },
0043     { "LinkInfo",   MUSB_LINKINFO,  8 },
0044     { "VPLen",  MUSB_VPLEN, 8 },
0045     { "HS_EOF1",    MUSB_HS_EOF1,   8 },
0046     { "FS_EOF1",    MUSB_FS_EOF1,   8 },
0047     { "LS_EOF1",    MUSB_LS_EOF1,   8 },
0048     { "SOFT_RST",   0x7F,       8 },
0049     { "DMA_CNTLch0",    0x204,  16 },
0050     { "DMA_ADDRch0",    0x208,  32 },
0051     { "DMA_COUNTch0",   0x20C,  32 },
0052     { "DMA_CNTLch1",    0x214,  16 },
0053     { "DMA_ADDRch1",    0x218,  32 },
0054     { "DMA_COUNTch1",   0x21C,  32 },
0055     { "DMA_CNTLch2",    0x224,  16 },
0056     { "DMA_ADDRch2",    0x228,  32 },
0057     { "DMA_COUNTch2",   0x22C,  32 },
0058     { "DMA_CNTLch3",    0x234,  16 },
0059     { "DMA_ADDRch3",    0x238,  32 },
0060     { "DMA_COUNTch3",   0x23C,  32 },
0061     { "DMA_CNTLch4",    0x244,  16 },
0062     { "DMA_ADDRch4",    0x248,  32 },
0063     { "DMA_COUNTch4",   0x24C,  32 },
0064     { "DMA_CNTLch5",    0x254,  16 },
0065     { "DMA_ADDRch5",    0x258,  32 },
0066     { "DMA_COUNTch5",   0x25C,  32 },
0067     { "DMA_CNTLch6",    0x264,  16 },
0068     { "DMA_ADDRch6",    0x268,  32 },
0069     { "DMA_COUNTch6",   0x26C,  32 },
0070     { "DMA_CNTLch7",    0x274,  16 },
0071     { "DMA_ADDRch7",    0x278,  32 },
0072     { "DMA_COUNTch7",   0x27C,  32 },
0073     { "ConfigData", MUSB_CONFIGDATA,8 },
0074     { "BabbleCtl",  MUSB_BABBLE_CTL,8 },
0075     { "TxFIFOsz",   MUSB_TXFIFOSZ,  8 },
0076     { "RxFIFOsz",   MUSB_RXFIFOSZ,  8 },
0077     { "TxFIFOadd",  MUSB_TXFIFOADD, 16 },
0078     { "RxFIFOadd",  MUSB_RXFIFOADD, 16 },
0079     { "EPInfo", MUSB_EPINFO,    8 },
0080     { "RAMInfo",    MUSB_RAMINFO,   8 },
0081     {  }    /* Terminating Entry */
0082 };
0083 
0084 static int musb_regdump_show(struct seq_file *s, void *unused)
0085 {
0086     struct musb     *musb = s->private;
0087     unsigned        i;
0088 
0089     seq_printf(s, "MUSB (M)HDRC Register Dump\n");
0090     pm_runtime_get_sync(musb->controller);
0091 
0092     for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
0093         switch (musb_regmap[i].size) {
0094         case 8:
0095             seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name,
0096                     musb_readb(musb->mregs, musb_regmap[i].offset));
0097             break;
0098         case 16:
0099             seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name,
0100                     musb_readw(musb->mregs, musb_regmap[i].offset));
0101             break;
0102         case 32:
0103             seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name,
0104                     musb_readl(musb->mregs, musb_regmap[i].offset));
0105             break;
0106         }
0107     }
0108 
0109     pm_runtime_mark_last_busy(musb->controller);
0110     pm_runtime_put_autosuspend(musb->controller);
0111     return 0;
0112 }
0113 DEFINE_SHOW_ATTRIBUTE(musb_regdump);
0114 
0115 static int musb_test_mode_show(struct seq_file *s, void *unused)
0116 {
0117     struct musb     *musb = s->private;
0118     unsigned        test;
0119 
0120     pm_runtime_get_sync(musb->controller);
0121     test = musb_readb(musb->mregs, MUSB_TESTMODE);
0122     pm_runtime_mark_last_busy(musb->controller);
0123     pm_runtime_put_autosuspend(musb->controller);
0124 
0125     if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS))
0126         seq_printf(s, "force host full-speed\n");
0127 
0128     else if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS))
0129         seq_printf(s, "force host high-speed\n");
0130 
0131     else if (test == MUSB_TEST_FORCE_HOST)
0132         seq_printf(s, "force host\n");
0133 
0134     else if (test == MUSB_TEST_FIFO_ACCESS)
0135         seq_printf(s, "fifo access\n");
0136 
0137     else if (test == MUSB_TEST_FORCE_FS)
0138         seq_printf(s, "force full-speed\n");
0139 
0140     else if (test == MUSB_TEST_FORCE_HS)
0141         seq_printf(s, "force high-speed\n");
0142 
0143     else if (test == MUSB_TEST_PACKET)
0144         seq_printf(s, "test packet\n");
0145 
0146     else if (test == MUSB_TEST_K)
0147         seq_printf(s, "test K\n");
0148 
0149     else if (test == MUSB_TEST_J)
0150         seq_printf(s, "test J\n");
0151 
0152     else if (test == MUSB_TEST_SE0_NAK)
0153         seq_printf(s, "test SE0 NAK\n");
0154 
0155     return 0;
0156 }
0157 
0158 static int musb_test_mode_open(struct inode *inode, struct file *file)
0159 {
0160     return single_open(file, musb_test_mode_show, inode->i_private);
0161 }
0162 
0163 static ssize_t musb_test_mode_write(struct file *file,
0164         const char __user *ubuf, size_t count, loff_t *ppos)
0165 {
0166     struct seq_file     *s = file->private_data;
0167     struct musb     *musb = s->private;
0168     u8          test;
0169     char            buf[24];
0170 
0171     memset(buf, 0x00, sizeof(buf));
0172 
0173     if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
0174         return -EFAULT;
0175 
0176     pm_runtime_get_sync(musb->controller);
0177     test = musb_readb(musb->mregs, MUSB_TESTMODE);
0178     if (test) {
0179         dev_err(musb->controller, "Error: test mode is already set. "
0180             "Please do USB Bus Reset to start a new test.\n");
0181         goto ret;
0182     }
0183 
0184     if (strstarts(buf, "force host full-speed"))
0185         test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS;
0186 
0187     else if (strstarts(buf, "force host high-speed"))
0188         test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS;
0189 
0190     else if (strstarts(buf, "force host"))
0191         test = MUSB_TEST_FORCE_HOST;
0192 
0193     else if (strstarts(buf, "fifo access"))
0194         test = MUSB_TEST_FIFO_ACCESS;
0195 
0196     else if (strstarts(buf, "force full-speed"))
0197         test = MUSB_TEST_FORCE_FS;
0198 
0199     else if (strstarts(buf, "force high-speed"))
0200         test = MUSB_TEST_FORCE_HS;
0201 
0202     else if (strstarts(buf, "test packet")) {
0203         test = MUSB_TEST_PACKET;
0204         musb_load_testpacket(musb);
0205     }
0206 
0207     else if (strstarts(buf, "test K"))
0208         test = MUSB_TEST_K;
0209 
0210     else if (strstarts(buf, "test J"))
0211         test = MUSB_TEST_J;
0212 
0213     else if (strstarts(buf, "test SE0 NAK"))
0214         test = MUSB_TEST_SE0_NAK;
0215 
0216     musb_writeb(musb->mregs, MUSB_TESTMODE, test);
0217 
0218 ret:
0219     pm_runtime_mark_last_busy(musb->controller);
0220     pm_runtime_put_autosuspend(musb->controller);
0221     return count;
0222 }
0223 
0224 static const struct file_operations musb_test_mode_fops = {
0225     .open           = musb_test_mode_open,
0226     .write          = musb_test_mode_write,
0227     .read           = seq_read,
0228     .llseek         = seq_lseek,
0229     .release        = single_release,
0230 };
0231 
0232 static int musb_softconnect_show(struct seq_file *s, void *unused)
0233 {
0234     struct musb *musb = s->private;
0235     u8      reg;
0236     int     connect;
0237 
0238     switch (musb->xceiv->otg->state) {
0239     case OTG_STATE_A_HOST:
0240     case OTG_STATE_A_WAIT_BCON:
0241         pm_runtime_get_sync(musb->controller);
0242 
0243         reg = musb_readb(musb->mregs, MUSB_DEVCTL);
0244         connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
0245 
0246         pm_runtime_mark_last_busy(musb->controller);
0247         pm_runtime_put_autosuspend(musb->controller);
0248         break;
0249     default:
0250         connect = -1;
0251     }
0252 
0253     seq_printf(s, "%d\n", connect);
0254 
0255     return 0;
0256 }
0257 
0258 static int musb_softconnect_open(struct inode *inode, struct file *file)
0259 {
0260     return single_open(file, musb_softconnect_show, inode->i_private);
0261 }
0262 
0263 static ssize_t musb_softconnect_write(struct file *file,
0264         const char __user *ubuf, size_t count, loff_t *ppos)
0265 {
0266     struct seq_file     *s = file->private_data;
0267     struct musb     *musb = s->private;
0268     char            buf[2];
0269     u8          reg;
0270 
0271     memset(buf, 0x00, sizeof(buf));
0272 
0273     if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
0274         return -EFAULT;
0275 
0276     pm_runtime_get_sync(musb->controller);
0277     if (!strncmp(buf, "0", 1)) {
0278         switch (musb->xceiv->otg->state) {
0279         case OTG_STATE_A_HOST:
0280             musb_root_disconnect(musb);
0281             reg = musb_readb(musb->mregs, MUSB_DEVCTL);
0282             reg &= ~MUSB_DEVCTL_SESSION;
0283             musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
0284             break;
0285         default:
0286             break;
0287         }
0288     } else if (!strncmp(buf, "1", 1)) {
0289         switch (musb->xceiv->otg->state) {
0290         case OTG_STATE_A_WAIT_BCON:
0291             /*
0292              * musb_save_context() called in musb_runtime_suspend()
0293              * might cache devctl with SESSION bit cleared during
0294              * soft-disconnect, so specifically set SESSION bit
0295              * here to preserve it for musb_runtime_resume().
0296              */
0297             musb->context.devctl |= MUSB_DEVCTL_SESSION;
0298             reg = musb_readb(musb->mregs, MUSB_DEVCTL);
0299             reg |= MUSB_DEVCTL_SESSION;
0300             musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
0301             break;
0302         default:
0303             break;
0304         }
0305     }
0306 
0307     pm_runtime_mark_last_busy(musb->controller);
0308     pm_runtime_put_autosuspend(musb->controller);
0309     return count;
0310 }
0311 
0312 /*
0313  * In host mode, connect/disconnect the bus without physically
0314  * remove the devices.
0315  */
0316 static const struct file_operations musb_softconnect_fops = {
0317     .open           = musb_softconnect_open,
0318     .write          = musb_softconnect_write,
0319     .read           = seq_read,
0320     .llseek         = seq_lseek,
0321     .release        = single_release,
0322 };
0323 
0324 void musb_init_debugfs(struct musb *musb)
0325 {
0326     struct dentry *root;
0327 
0328     root = debugfs_create_dir(dev_name(musb->controller), usb_debug_root);
0329     musb->debugfs_root = root;
0330 
0331     debugfs_create_file("regdump", S_IRUGO, root, musb, &musb_regdump_fops);
0332     debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, musb,
0333                 &musb_test_mode_fops);
0334     debugfs_create_file("softconnect", S_IRUGO | S_IWUSR, root, musb,
0335                 &musb_softconnect_fops);
0336 }
0337 
0338 void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
0339 {
0340     debugfs_remove_recursive(musb->debugfs_root);
0341 }