Commit ffc1d299 authored by Bin Liu's avatar Bin Liu Committed by Felipe Balbi

usb: musb: add softconnect for host mode

Add a debugfs interface - softconnect - for host mode to
connect/disconnect the devices without physically remove the
them.

This adds the capability to re-enumerate the devices which are
permanently mounted on the board with the MUSB controller
together.
Signed-off-by: default avatarBin Liu <b-liu@ti.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent d6d22922
......@@ -245,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;
......@@ -271,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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment