summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/debugfs.c
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2012-01-02 18:38:30 +0200
committerFelipe Balbi <balbi@ti.com>2012-02-06 11:48:22 +0200
commit080d921fe7a8d27c07eba7723fe53a3bea100327 (patch)
treee0841e4deed5284473d39d3203e846afd14a6353 /drivers/usb/dwc3/debugfs.c
parent04a9bfcd50dd568a8f1a10194a7f336f6b3ad81c (diff)
usb: dwc3: gadget: allow testmodes 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.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 433c97c15fc5..c7e85024fda8 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -46,6 +46,8 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
+#include <linux/usb/ch9.h>
+
#include "core.h"
#include "gadget.h"
#include "io.h"
@@ -464,6 +466,89 @@ static const struct file_operations dwc3_mode_fops = {
.release = single_release,
};
+static int dwc3_testmode_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= DWC3_DCTL_TSTCTRL_MASK;
+ reg >>= 1;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ switch (reg) {
+ case 0:
+ seq_printf(s, "no test\n");
+ break;
+ case TEST_J:
+ seq_printf(s, "test_j\n");
+ break;
+ case TEST_K:
+ seq_printf(s, "test_k\n");
+ break;
+ case TEST_SE0_NAK:
+ seq_printf(s, "test_se0_nak\n");
+ break;
+ case TEST_PACKET:
+ seq_printf(s, "test_packet\n");
+ break;
+ case TEST_FORCE_EN:
+ seq_printf(s, "test_force_enable\n");
+ break;
+ default:
+ seq_printf(s, "UNKNOWN %d\n", reg);
+ }
+
+ return 0;
+}
+
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_testmode_show, inode->i_private);
+}
+
+static ssize_t dwc3_testmode_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;
+ u32 testmode = 0;
+ char buf[32];
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "test_j", 6))
+ testmode = TEST_J;
+ else if (!strncmp(buf, "test_k", 6))
+ testmode = TEST_K;
+ else if (!strncmp(buf, "test_se0_nak", 13))
+ testmode = TEST_SE0_NAK;
+ else if (!strncmp(buf, "test_packet", 12))
+ testmode = TEST_PACKET;
+ else if (!strncmp(buf, "test_force_enable", 18))
+ testmode = TEST_FORCE_EN;
+ else
+ testmode = 0;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_set_test_mode(dwc, testmode);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return count;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+ .open = dwc3_testmode_open,
+ .write = dwc3_testmode_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
@@ -492,6 +577,13 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
goto err1;
}
+ file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_testmode_fops);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto err1;
+ }
+
return 0;
err1: