From 0b9fe32deece53c9bc6d1e6d17a85ef1eb2e294b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 17 Oct 2011 08:50:39 +0300 Subject: [PATCH] usb: dwc3: debugfs: add support for changing port mode This makes testing a lot easier when trying to switch between host and device modes. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 1 + drivers/usb/dwc3/debugfs.c | 82 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 513a7391099f..6f1e8c98d78d 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -154,6 +154,7 @@ #define DWC3_GCTL_CLK_PIPEHALF (2) #define DWC3_GCTL_CLK_MASK (3) +#define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12) #define DWC3_GCTL_PRTCAPDIR(n) (n << 12) #define DWC3_GCTL_PRTCAP_HOST 1 #define DWC3_GCTL_PRTCAP_DEVICE 2 diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index da1ad77d8d51..fc49334a01cf 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -405,6 +405,80 @@ static const struct file_operations dwc3_regdump_fops = { .release = single_release, }; +static int dwc3_mode_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_GCTL); + spin_unlock_irqrestore(&dwc->lock, flags); + + switch (DWC3_GCTL_PRTCAP(reg)) { + case DWC3_GCTL_PRTCAP_HOST: + seq_printf(s, "host\n"); + break; + case DWC3_GCTL_PRTCAP_DEVICE: + seq_printf(s, "device\n"); + break; + case DWC3_GCTL_PRTCAP_OTG: + seq_printf(s, "OTG\n"); + break; + default: + seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); + } + + return 0; +} + +static int dwc3_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, dwc3_mode_show, inode->i_private); +} + +static ssize_t dwc3_mode_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 reg; + char buf[32]; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + spin_lock_irqsave(&dwc->lock, flags); + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + spin_unlock_irqrestore(&dwc->lock, flags); + + reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); + + if (!strncmp(buf, "host", 4)) + reg |= DWC3_GCTL_PRTCAP(DWC3_GCTL_PRTCAP_HOST); + + if (!strncmp(buf, "device", 6)) + reg |= DWC3_GCTL_PRTCAP(DWC3_GCTL_PRTCAP_DEVICE); + + if (!strncmp(buf, "otg", 3)) + reg |= DWC3_GCTL_PRTCAP(DWC3_GCTL_PRTCAP_OTG); + + spin_lock_irqsave(&dwc->lock, flags); + dwc3_writel(dwc->regs, DWC3_GCTL, reg); + spin_unlock_irqrestore(&dwc->lock, flags); + + return count; +} + +static const struct file_operations dwc3_mode_fops = { + .open = dwc3_mode_open, + .write = dwc3_mode_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + int __devinit dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; @@ -425,6 +499,14 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc) ret = PTR_ERR(file); goto err1; } + + file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, + dwc, &dwc3_mode_fops); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto err1; + } + return 0; err1: