linux/drivers/usb/musb/musb_debugfs.c
<<
>>
Prefs
   1/*
   2 * MUSB OTG driver debugfs support
   3 *
   4 * Copyright 2010 Nokia Corporation
   5 * Contact: Felipe Balbi <felipe.balbi@nokia.com>
   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
  45struct musb_register_map {
  46        char                    *name;
  47        unsigned                offset;
  48        unsigned                size;
  49};
  50
  51static const struct musb_register_map musb_regmap[] = {
  52        { "FAddr",      MUSB_FADDR,     8 },
  53        { "Power",      MUSB_POWER,     8 },
  54        { "Frame",      MUSB_FRAME,     16 },
  55        { "Index",      MUSB_INDEX,     8 },
  56        { "Testmode",   MUSB_TESTMODE,  8 },
  57        { "TxMaxPp",    MUSB_TXMAXP,    16 },
  58        { "TxCSRp",     MUSB_TXCSR,     16 },
  59        { "RxMaxPp",    MUSB_RXMAXP,    16 },
  60        { "RxCSR",      MUSB_RXCSR,     16 },
  61        { "RxCount",    MUSB_RXCOUNT,   16 },
  62        { "IntrRxE",    MUSB_INTRRXE,   16 },
  63        { "IntrTxE",    MUSB_INTRTXE,   16 },
  64        { "IntrUsbE",   MUSB_INTRUSBE,  8 },
  65        { "DevCtl",     MUSB_DEVCTL,    8 },
  66        { "VControl",   0x68,           32 },
  67        { "HWVers",     0x69,           16 },
  68        { "LinkInfo",   MUSB_LINKINFO,  8 },
  69        { "VPLen",      MUSB_VPLEN,     8 },
  70        { "HS_EOF1",    MUSB_HS_EOF1,   8 },
  71        { "FS_EOF1",    MUSB_FS_EOF1,   8 },
  72        { "LS_EOF1",    MUSB_LS_EOF1,   8 },
  73        { "SOFT_RST",   0x7F,           8 },
  74        { "DMA_CNTLch0",        0x204,  16 },
  75        { "DMA_ADDRch0",        0x208,  32 },
  76        { "DMA_COUNTch0",       0x20C,  32 },
  77        { "DMA_CNTLch1",        0x214,  16 },
  78        { "DMA_ADDRch1",        0x218,  32 },
  79        { "DMA_COUNTch1",       0x21C,  32 },
  80        { "DMA_CNTLch2",        0x224,  16 },
  81        { "DMA_ADDRch2",        0x228,  32 },
  82        { "DMA_COUNTch2",       0x22C,  32 },
  83        { "DMA_CNTLch3",        0x234,  16 },
  84        { "DMA_ADDRch3",        0x238,  32 },
  85        { "DMA_COUNTch3",       0x23C,  32 },
  86        { "DMA_CNTLch4",        0x244,  16 },
  87        { "DMA_ADDRch4",        0x248,  32 },
  88        { "DMA_COUNTch4",       0x24C,  32 },
  89        { "DMA_CNTLch5",        0x254,  16 },
  90        { "DMA_ADDRch5",        0x258,  32 },
  91        { "DMA_COUNTch5",       0x25C,  32 },
  92        { "DMA_CNTLch6",        0x264,  16 },
  93        { "DMA_ADDRch6",        0x268,  32 },
  94        { "DMA_COUNTch6",       0x26C,  32 },
  95        { "DMA_CNTLch7",        0x274,  16 },
  96        { "DMA_ADDRch7",        0x278,  32 },
  97        { "DMA_COUNTch7",       0x27C,  32 },
  98#ifndef CONFIG_BLACKFIN
  99        { "ConfigData", MUSB_CONFIGDATA,8 },
 100        { "BabbleCtl",  MUSB_BABBLE_CTL,8 },
 101        { "TxFIFOsz",   MUSB_TXFIFOSZ,  8 },
 102        { "RxFIFOsz",   MUSB_RXFIFOSZ,  8 },
 103        { "TxFIFOadd",  MUSB_TXFIFOADD, 16 },
 104        { "RxFIFOadd",  MUSB_RXFIFOADD, 16 },
 105        { "EPInfo",     MUSB_EPINFO,    8 },
 106        { "RAMInfo",    MUSB_RAMINFO,   8 },
 107#endif
 108        {  }    /* Terminating Entry */
 109};
 110
 111static int musb_regdump_show(struct seq_file *s, void *unused)
 112{
 113        struct musb             *musb = s->private;
 114        unsigned                i;
 115
 116        seq_printf(s, "MUSB (M)HDRC Register Dump\n");
 117
 118        for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
 119                switch (musb_regmap[i].size) {
 120                case 8:
 121                        seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name,
 122                                        musb_readb(musb->mregs, musb_regmap[i].offset));
 123                        break;
 124                case 16:
 125                        seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name,
 126                                        musb_readw(musb->mregs, musb_regmap[i].offset));
 127                        break;
 128                case 32:
 129                        seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name,
 130                                        musb_readl(musb->mregs, musb_regmap[i].offset));
 131                        break;
 132                }
 133        }
 134
 135        return 0;
 136}
 137
 138static int musb_regdump_open(struct inode *inode, struct file *file)
 139{
 140        return single_open(file, musb_regdump_show, inode->i_private);
 141}
 142
 143static int musb_test_mode_show(struct seq_file *s, void *unused)
 144{
 145        struct musb             *musb = s->private;
 146        unsigned                test;
 147
 148        test = musb_readb(musb->mregs, MUSB_TESTMODE);
 149
 150        if (test & MUSB_TEST_FORCE_HOST)
 151                seq_printf(s, "force host\n");
 152
 153        if (test & MUSB_TEST_FIFO_ACCESS)
 154                seq_printf(s, "fifo access\n");
 155
 156        if (test & MUSB_TEST_FORCE_FS)
 157                seq_printf(s, "force full-speed\n");
 158
 159        if (test & MUSB_TEST_FORCE_HS)
 160                seq_printf(s, "force high-speed\n");
 161
 162        if (test & MUSB_TEST_PACKET)
 163                seq_printf(s, "test packet\n");
 164
 165        if (test & MUSB_TEST_K)
 166                seq_printf(s, "test K\n");
 167
 168        if (test & MUSB_TEST_J)
 169                seq_printf(s, "test J\n");
 170
 171        if (test & MUSB_TEST_SE0_NAK)
 172                seq_printf(s, "test SE0 NAK\n");
 173
 174        return 0;
 175}
 176
 177static const struct file_operations musb_regdump_fops = {
 178        .open                   = musb_regdump_open,
 179        .read                   = seq_read,
 180        .llseek                 = seq_lseek,
 181        .release                = single_release,
 182};
 183
 184static int musb_test_mode_open(struct inode *inode, struct file *file)
 185{
 186        return single_open(file, musb_test_mode_show, inode->i_private);
 187}
 188
 189static ssize_t musb_test_mode_write(struct file *file,
 190                const char __user *ubuf, size_t count, loff_t *ppos)
 191{
 192        struct seq_file         *s = file->private_data;
 193        struct musb             *musb = s->private;
 194        u8                      test;
 195        char                    buf[18];
 196
 197        test = musb_readb(musb->mregs, MUSB_TESTMODE);
 198        if (test) {
 199                dev_err(musb->controller, "Error: test mode is already set. "
 200                        "Please do USB Bus Reset to start a new test.\n");
 201                return count;
 202        }
 203
 204        memset(buf, 0x00, sizeof(buf));
 205
 206        if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 207                return -EFAULT;
 208
 209        if (strstarts(buf, "force host"))
 210                test = MUSB_TEST_FORCE_HOST;
 211
 212        if (strstarts(buf, "fifo access"))
 213                test = MUSB_TEST_FIFO_ACCESS;
 214
 215        if (strstarts(buf, "force full-speed"))
 216                test = MUSB_TEST_FORCE_FS;
 217
 218        if (strstarts(buf, "force high-speed"))
 219                test = MUSB_TEST_FORCE_HS;
 220
 221        if (strstarts(buf, "test packet")) {
 222                test = MUSB_TEST_PACKET;
 223                musb_load_testpacket(musb);
 224        }
 225
 226        if (strstarts(buf, "test K"))
 227                test = MUSB_TEST_K;
 228
 229        if (strstarts(buf, "test J"))
 230                test = MUSB_TEST_J;
 231
 232        if (strstarts(buf, "test SE0 NAK"))
 233                test = MUSB_TEST_SE0_NAK;
 234
 235        musb_writeb(musb->mregs, MUSB_TESTMODE, test);
 236
 237        return count;
 238}
 239
 240static const struct file_operations musb_test_mode_fops = {
 241        .open                   = musb_test_mode_open,
 242        .write                  = musb_test_mode_write,
 243        .read                   = seq_read,
 244        .llseek                 = seq_lseek,
 245        .release                = single_release,
 246};
 247
 248static int musb_softconnect_show(struct seq_file *s, void *unused)
 249{
 250        struct musb     *musb = s->private;
 251        u8              reg;
 252        int             connect;
 253
 254        switch (musb->xceiv->otg->state) {
 255        case OTG_STATE_A_HOST:
 256        case OTG_STATE_A_WAIT_BCON:
 257                reg = musb_readb(musb->mregs, MUSB_DEVCTL);
 258                connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
 259                break;
 260        default:
 261                connect = -1;
 262        }
 263
 264        seq_printf(s, "%d\n", connect);
 265
 266        return 0;
 267}
 268
 269static int musb_softconnect_open(struct inode *inode, struct file *file)
 270{
 271        return single_open(file, musb_softconnect_show, inode->i_private);
 272}
 273
 274static ssize_t musb_softconnect_write(struct file *file,
 275                const char __user *ubuf, size_t count, loff_t *ppos)
 276{
 277        struct seq_file         *s = file->private_data;
 278        struct musb             *musb = s->private;
 279        char                    buf[2];
 280        u8                      reg;
 281
 282        memset(buf, 0x00, sizeof(buf));
 283
 284        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 285                return -EFAULT;
 286
 287        if (!strncmp(buf, "0", 1)) {
 288                switch (musb->xceiv->otg->state) {
 289                case OTG_STATE_A_HOST:
 290                        musb_root_disconnect(musb);
 291                        reg = musb_readb(musb->mregs, MUSB_DEVCTL);
 292                        reg &= ~MUSB_DEVCTL_SESSION;
 293                        musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
 294                        break;
 295                default:
 296                        break;
 297                }
 298        } else if (!strncmp(buf, "1", 1)) {
 299                switch (musb->xceiv->otg->state) {
 300                case OTG_STATE_A_WAIT_BCON:
 301                        /*
 302                         * musb_save_context() called in musb_runtime_suspend()
 303                         * might cache devctl with SESSION bit cleared during
 304                         * soft-disconnect, so specifically set SESSION bit
 305                         * here to preserve it for musb_runtime_resume().
 306                         */
 307                        musb->context.devctl |= MUSB_DEVCTL_SESSION;
 308                        reg = musb_readb(musb->mregs, MUSB_DEVCTL);
 309                        reg |= MUSB_DEVCTL_SESSION;
 310                        musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
 311                        break;
 312                default:
 313                        break;
 314                }
 315        }
 316
 317        return count;
 318}
 319
 320/*
 321 * In host mode, connect/disconnect the bus without physically
 322 * remove the devices.
 323 */
 324static const struct file_operations musb_softconnect_fops = {
 325        .open                   = musb_softconnect_open,
 326        .write                  = musb_softconnect_write,
 327        .read                   = seq_read,
 328        .llseek                 = seq_lseek,
 329        .release                = single_release,
 330};
 331
 332int musb_init_debugfs(struct musb *musb)
 333{
 334        struct dentry           *root;
 335        struct dentry           *file;
 336        int                     ret;
 337
 338        root = debugfs_create_dir(dev_name(musb->controller), NULL);
 339        if (!root) {
 340                ret = -ENOMEM;
 341                goto err0;
 342        }
 343
 344        file = debugfs_create_file("regdump", S_IRUGO, root, musb,
 345                        &musb_regdump_fops);
 346        if (!file) {
 347                ret = -ENOMEM;
 348                goto err1;
 349        }
 350
 351        file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
 352                        root, musb, &musb_test_mode_fops);
 353        if (!file) {
 354                ret = -ENOMEM;
 355                goto err1;
 356        }
 357
 358        file = debugfs_create_file("softconnect", S_IRUGO | S_IWUSR,
 359                        root, musb, &musb_softconnect_fops);
 360        if (!file) {
 361                ret = -ENOMEM;
 362                goto err1;
 363        }
 364
 365        musb->debugfs_root = root;
 366
 367        return 0;
 368
 369err1:
 370        debugfs_remove_recursive(root);
 371
 372err0:
 373        return ret;
 374}
 375
 376void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
 377{
 378        debugfs_remove_recursive(musb->debugfs_root);
 379}
 380