Skip to content

Commit

Permalink
usb: dwc3: gadget: allow Link state changes via debugfs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Felipe Balbi committed Feb 6, 2012
1 parent 8598bde commit 138801a
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 1 deletion.
110 changes: 110 additions & 0 deletions drivers/usb/dwc3/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,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;
Expand Down Expand Up @@ -584,6 +687,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:
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down

0 comments on commit 138801a

Please sign in to comment.