linux/drivers/usb/musb/musb_debugfs.c
<<
>>
Prefs
   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
  20struct musb_register_map {
  21        char                    *name;
  22        unsigned                offset;
  23        unsigned                size;
  24};
  25
  26static 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
  84static 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}
 113DEFINE_SHOW_ATTRIBUTE(musb_regdump);
 114
 115static 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
 158static 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
 163static 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
 218ret:
 219        pm_runtime_mark_last_busy(musb->controller);
 220        pm_runtime_put_autosuspend(musb->controller);
 221        return count;
 222}
 223
 224static 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
 232static 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
 258static int musb_softconnect_open(struct inode *inode, struct file *file)
 259{
 260        return single_open(file, musb_softconnect_show, inode->i_private);
 261}
 262
 263static 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 */
 316static 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
 324void 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
 338void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
 339{
 340        debugfs_remove_recursive(musb->debugfs_root);
 341}
 342