diff options
author | Felipe Balbi <balbi@ti.com> | 2012-01-02 12:25:16 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-02-06 04:48:25 -0500 |
commit | 138801aaa566ecb5a5739a85909b9ec7285efd70 (patch) | |
tree | f7f2712f31e5f9914fa73044eae733a3754b02e6 /drivers/usb/dwc3/debugfs.c | |
parent | 8598bde7fa125e85bc97decd6513d37dcf1e7bd9 (diff) |
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>
Diffstat (limited to 'drivers/usb/dwc3/debugfs.c')
-rw-r--r-- | drivers/usb/dwc3/debugfs.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index c7e85024fda8..a2c1cc64b48d 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c | |||
@@ -549,6 +549,109 @@ static const struct file_operations dwc3_testmode_fops = { | |||
549 | .release = single_release, | 549 | .release = single_release, |
550 | }; | 550 | }; |
551 | 551 | ||
552 | static int dwc3_link_state_show(struct seq_file *s, void *unused) | ||
553 | { | ||
554 | struct dwc3 *dwc = s->private; | ||
555 | unsigned long flags; | ||
556 | enum dwc3_link_state state; | ||
557 | u32 reg; | ||
558 | |||
559 | spin_lock_irqsave(&dwc->lock, flags); | ||
560 | reg = dwc3_readl(dwc->regs, DWC3_DSTS); | ||
561 | state = DWC3_DSTS_USBLNKST(reg); | ||
562 | spin_unlock_irqrestore(&dwc->lock, flags); | ||
563 | |||
564 | switch (state) { | ||
565 | case DWC3_LINK_STATE_U0: | ||
566 | seq_printf(s, "U0\n"); | ||
567 | break; | ||
568 | case DWC3_LINK_STATE_U1: | ||
569 | seq_printf(s, "U1\n"); | ||
570 | break; | ||
571 | case DWC3_LINK_STATE_U2: | ||
572 | seq_printf(s, "U2\n"); | ||
573 | break; | ||
574 | case DWC3_LINK_STATE_U3: | ||
575 | seq_printf(s, "U3\n"); | ||
576 | break; | ||
577 | case DWC3_LINK_STATE_SS_DIS: | ||
578 | seq_printf(s, "SS.Disabled\n"); | ||
579 | break; | ||
580 | case DWC3_LINK_STATE_RX_DET: | ||
581 | seq_printf(s, "Rx.Detect\n"); | ||
582 | break; | ||
583 | case DWC3_LINK_STATE_SS_INACT: | ||
584 | seq_printf(s, "SS.Inactive\n"); | ||
585 | break; | ||
586 | case DWC3_LINK_STATE_POLL: | ||
587 | seq_printf(s, "Poll\n"); | ||
588 | break; | ||
589 | case DWC3_LINK_STATE_RECOV: | ||
590 | seq_printf(s, "Recovery\n"); | ||
591 | break; | ||
592 | case DWC3_LINK_STATE_HRESET: | ||
593 | seq_printf(s, "HRESET\n"); | ||
594 | break; | ||
595 | case DWC3_LINK_STATE_CMPLY: | ||
596 | seq_printf(s, "Compliance\n"); | ||
597 | break; | ||
598 | case DWC3_LINK_STATE_LPBK: | ||
599 | seq_printf(s, "Loopback\n"); | ||
600 | break; | ||
601 | default: | ||
602 | seq_printf(s, "UNKNOWN %d\n", reg); | ||
603 | } | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int dwc3_link_state_open(struct inode *inode, struct file *file) | ||
609 | { | ||
610 | return single_open(file, dwc3_link_state_show, inode->i_private); | ||
611 | } | ||
612 | |||
613 | static ssize_t dwc3_link_state_write(struct file *file, | ||
614 | const char __user *ubuf, size_t count, loff_t *ppos) | ||
615 | { | ||
616 | struct seq_file *s = file->private_data; | ||
617 | struct dwc3 *dwc = s->private; | ||
618 | unsigned long flags; | ||
619 | enum dwc3_link_state state = 0; | ||
620 | char buf[32]; | ||
621 | |||
622 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) | ||
623 | return -EFAULT; | ||
624 | |||
625 | if (!strncmp(buf, "SS.Disabled", 11)) | ||
626 | state = DWC3_LINK_STATE_SS_DIS; | ||
627 | else if (!strncmp(buf, "Rx.Detect", 9)) | ||
628 | state = DWC3_LINK_STATE_RX_DET; | ||
629 | else if (!strncmp(buf, "SS.Inactive", 11)) | ||
630 | state = DWC3_LINK_STATE_SS_INACT; | ||
631 | else if (!strncmp(buf, "Recovery", 8)) | ||
632 | state = DWC3_LINK_STATE_RECOV; | ||
633 | else if (!strncmp(buf, "Compliance", 10)) | ||
634 | state = DWC3_LINK_STATE_CMPLY; | ||
635 | else if (!strncmp(buf, "Loopback", 8)) | ||
636 | state = DWC3_LINK_STATE_LPBK; | ||
637 | else | ||
638 | return -EINVAL; | ||
639 | |||
640 | spin_lock_irqsave(&dwc->lock, flags); | ||
641 | dwc3_gadget_set_link_state(dwc, state); | ||
642 | spin_unlock_irqrestore(&dwc->lock, flags); | ||
643 | |||
644 | return count; | ||
645 | } | ||
646 | |||
647 | static const struct file_operations dwc3_link_state_fops = { | ||
648 | .open = dwc3_link_state_open, | ||
649 | .write = dwc3_link_state_write, | ||
650 | .read = seq_read, | ||
651 | .llseek = seq_lseek, | ||
652 | .release = single_release, | ||
653 | }; | ||
654 | |||
552 | int __devinit dwc3_debugfs_init(struct dwc3 *dwc) | 655 | int __devinit dwc3_debugfs_init(struct dwc3 *dwc) |
553 | { | 656 | { |
554 | struct dentry *root; | 657 | struct dentry *root; |
@@ -584,6 +687,13 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc) | |||
584 | goto err1; | 687 | goto err1; |
585 | } | 688 | } |
586 | 689 | ||
690 | file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, | ||
691 | dwc, &dwc3_link_state_fops); | ||
692 | if (IS_ERR(file)) { | ||
693 | ret = PTR_ERR(file); | ||
694 | goto err1; | ||
695 | } | ||
696 | |||
587 | return 0; | 697 | return 0; |
588 | 698 | ||
589 | err1: | 699 | err1: |