usb: dwc3: gadget: allow Link state changes via debugfs
This is very useful for low level link testing where we might not have a USB Host stack, only a scope to verify signal integrity. Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
8598bde7fa
commit
138801aaa5
2 changed files with 111 additions and 1 deletions
|
@ -549,6 +549,109 @@ static const struct file_operations dwc3_testmode_fops = {
|
||||||
.release = single_release,
|
.release = single_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int dwc3_link_state_show(struct seq_file *s, void *unused)
|
||||||
|
{
|
||||||
|
struct dwc3 *dwc = s->private;
|
||||||
|
unsigned long flags;
|
||||||
|
enum dwc3_link_state state;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
|
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||||
|
state = DWC3_DSTS_USBLNKST(reg);
|
||||||
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case DWC3_LINK_STATE_U0:
|
||||||
|
seq_printf(s, "U0\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_U1:
|
||||||
|
seq_printf(s, "U1\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_U2:
|
||||||
|
seq_printf(s, "U2\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_U3:
|
||||||
|
seq_printf(s, "U3\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_SS_DIS:
|
||||||
|
seq_printf(s, "SS.Disabled\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_RX_DET:
|
||||||
|
seq_printf(s, "Rx.Detect\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_SS_INACT:
|
||||||
|
seq_printf(s, "SS.Inactive\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_POLL:
|
||||||
|
seq_printf(s, "Poll\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_RECOV:
|
||||||
|
seq_printf(s, "Recovery\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_HRESET:
|
||||||
|
seq_printf(s, "HRESET\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_CMPLY:
|
||||||
|
seq_printf(s, "Compliance\n");
|
||||||
|
break;
|
||||||
|
case DWC3_LINK_STATE_LPBK:
|
||||||
|
seq_printf(s, "Loopback\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
seq_printf(s, "UNKNOWN %d\n", reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwc3_link_state_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, dwc3_link_state_show, inode->i_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t dwc3_link_state_write(struct file *file,
|
||||||
|
const char __user *ubuf, size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct seq_file *s = file->private_data;
|
||||||
|
struct dwc3 *dwc = s->private;
|
||||||
|
unsigned long flags;
|
||||||
|
enum dwc3_link_state state = 0;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (!strncmp(buf, "SS.Disabled", 11))
|
||||||
|
state = DWC3_LINK_STATE_SS_DIS;
|
||||||
|
else if (!strncmp(buf, "Rx.Detect", 9))
|
||||||
|
state = DWC3_LINK_STATE_RX_DET;
|
||||||
|
else if (!strncmp(buf, "SS.Inactive", 11))
|
||||||
|
state = DWC3_LINK_STATE_SS_INACT;
|
||||||
|
else if (!strncmp(buf, "Recovery", 8))
|
||||||
|
state = DWC3_LINK_STATE_RECOV;
|
||||||
|
else if (!strncmp(buf, "Compliance", 10))
|
||||||
|
state = DWC3_LINK_STATE_CMPLY;
|
||||||
|
else if (!strncmp(buf, "Loopback", 8))
|
||||||
|
state = DWC3_LINK_STATE_LPBK;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
|
dwc3_gadget_set_link_state(dwc, state);
|
||||||
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations dwc3_link_state_fops = {
|
||||||
|
.open = dwc3_link_state_open,
|
||||||
|
.write = dwc3_link_state_write,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
||||||
{
|
{
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
|
@ -584,6 +687,13 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
|
||||||
|
dwc, &dwc3_link_state_fops);
|
||||||
|
if (IS_ERR(file)) {
|
||||||
|
ret = PTR_ERR(file);
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err1:
|
err1:
|
||||||
|
|
|
@ -117,7 +117,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||||
if (DWC3_DSTS_USBLNKST(reg) == state)
|
if (DWC3_DSTS_USBLNKST(reg) == state)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
usleep_range(500, 1500);
|
udelay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_vdbg(dwc->dev, "link state change request timed out\n");
|
dev_vdbg(dwc->dev, "link state change request timed out\n");
|
||||||
|
|
Loading…
Add table
Reference in a new issue