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@xxxxxx> --- drivers/usb/dwc3/debugfs.c | 110 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/gadget.c | 2 +- 2 files changed, 111 insertions(+), 1 deletions(-) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 17038b1..b99ee12 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -559,6 +559,109 @@ static const struct file_operations dwc3_testmode_fops = { .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) { struct dentry *root; @@ -594,6 +697,13 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc) 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; err1: diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2bbba94..70e1de1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -117,7 +117,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) if (DWC3_DSTS_USBLNKST(reg) == state) return 0; - usleep_range(500, 1500); + udelay(500); } dev_vdbg(dwc->dev, "link state change request timed out\n"); -- 1.7.8.2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html