diff options
author | Felipe Balbi <balbi@ti.com> | 2012-01-02 18:38:30 +0200 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-02-06 11:48:22 +0200 |
commit | 080d921fe7a8d27c07eba7723fe53a3bea100327 (patch) | |
tree | e0841e4deed5284473d39d3203e846afd14a6353 /drivers | |
parent | 04a9bfcd50dd568a8f1a10194a7f336f6b3ad81c (diff) | |
download | linux-3.10-080d921fe7a8d27c07eba7723fe53a3bea100327.tar.gz linux-3.10-080d921fe7a8d27c07eba7723fe53a3bea100327.tar.bz2 linux-3.10-080d921fe7a8d27c07eba7723fe53a3bea100327.zip |
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')
-rw-r--r-- | drivers/usb/dwc3/debugfs.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 433c97c15fc..c7e85024fda 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: |