These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / usb / musb / musb_debugfs.c
index 78a283e..9b22d94 100644 (file)
@@ -191,9 +191,16 @@ static ssize_t musb_test_mode_write(struct file *file,
 {
        struct seq_file         *s = file->private_data;
        struct musb             *musb = s->private;
-       u8                      test = 0;
+       u8                      test;
        char                    buf[18];
 
+       test = musb_readb(musb->mregs, MUSB_TESTMODE);
+       if (test) {
+               dev_err(musb->controller, "Error: test mode is already set. "
+                       "Please do USB Bus Reset to start a new test.\n");
+               return count;
+       }
+
        memset(buf, 0x00, sizeof(buf));
 
        if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
@@ -238,6 +245,90 @@ static const struct file_operations musb_test_mode_fops = {
        .release                = single_release,
 };
 
+static int musb_softconnect_show(struct seq_file *s, void *unused)
+{
+       struct musb     *musb = s->private;
+       u8              reg;
+       int             connect;
+
+       switch (musb->xceiv->otg->state) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_WAIT_BCON:
+               reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+               connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
+               break;
+       default:
+               connect = -1;
+       }
+
+       seq_printf(s, "%d\n", connect);
+
+       return 0;
+}
+
+static int musb_softconnect_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, musb_softconnect_show, inode->i_private);
+}
+
+static ssize_t musb_softconnect_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct musb             *musb = s->private;
+       char                    buf[2];
+       u8                      reg;
+
+       memset(buf, 0x00, sizeof(buf));
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "0", 1)) {
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_HOST:
+                       musb_root_disconnect(musb);
+                       reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+                       reg &= ~MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
+                       break;
+               default:
+                       break;
+               }
+       } else if (!strncmp(buf, "1", 1)) {
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_WAIT_BCON:
+                       /*
+                        * musb_save_context() called in musb_runtime_suspend()
+                        * might cache devctl with SESSION bit cleared during
+                        * soft-disconnect, so specifically set SESSION bit
+                        * here to preserve it for musb_runtime_resume().
+                        */
+                       musb->context.devctl |= MUSB_DEVCTL_SESSION;
+                       reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+                       reg |= MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, reg);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return count;
+}
+
+/*
+ * In host mode, connect/disconnect the bus without physically
+ * remove the devices.
+ */
+static const struct file_operations musb_softconnect_fops = {
+       .open                   = musb_softconnect_open,
+       .write                  = musb_softconnect_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
 int musb_init_debugfs(struct musb *musb)
 {
        struct dentry           *root;
@@ -264,6 +355,13 @@ int musb_init_debugfs(struct musb *musb)
                goto err1;
        }
 
+       file = debugfs_create_file("softconnect", S_IRUGO | S_IWUSR,
+                       root, musb, &musb_softconnect_fops);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
        musb->debugfs_root = root;
 
        return 0;