From 7c3e4505f325a6ca5a3f4dc8466e0134bbd01da2 Mon Sep 17 00:00:00 2001 From: Ronak Vijay Raheja Date: Wed, 10 Feb 2021 14:30:21 -0800 Subject: [PATCH] usb: dwc3: Add debugfs entry to toggle compliance pattern USB 3.x transmitter electrical compliance testing requires measurements of different compliance patterns that the PHY is able to output. Changing to different patterns normally requires triggering an external signal to the receiver to cause the controller to advance to the next pattern. It is often useful to be able to toggle the patterns from the DUT itself. This patch adds a debugfs entry to invoke the dwc3 controller to change patterns when it is in compliance mode. Change-Id: If5f7ac793b0c3f0c8ab1775cf7cbe7b48176c325 Signed-off-by: Ronak Vijay Raheja --- drivers/usb/dwc3/core.h | 1 + drivers/usb/dwc3/debugfs.c | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5c1fec2f3934..b9a8146bcbc8 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -321,6 +321,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST BIT(31) +#define DWC3_GUSB3PIPECTL_HSTPRTCMPL BIT(30) #define DWC3_GUSB3PIPECTL_U2SSINP3OK BIT(29) #define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28) #define DWC3_GUSB3PIPECTL_UX_EXIT_PX BIT(27) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 9cb17a0a1496..8ade9012f559 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -689,6 +689,49 @@ static const struct file_operations dwc3_link_state_fops = { .release = single_release, }; +static int dwc3_cp_toggle_open(struct inode *inode, struct file *file) +{ + int (*show)(struct seq_file *, void *) = inode->i_private; + + return single_open(file, show, inode->i_private); +} + +static ssize_t dwc3_cp_toggle_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; + u32 reg; + + if (atomic_read(&dwc->in_lpm)) { + pr_err("%s: USB device is powered off\n", __func__); + return 0; + } + + if (dwc3_gadget_get_link_state(dwc) != DWC3_LINK_STATE_CMPLY) { + pr_err("%s: USB Device is not in compliance mode\n", __func__); + return -EINVAL; + } + + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + reg |= DWC3_GUSB3PIPECTL_HSTPRTCMPL; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + msleep(200); + reg &= ~DWC3_GUSB3PIPECTL_HSTPRTCMPL; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + msleep(200); + + return count; +} + +static const struct file_operations dwc3_cp_toggle_fops = { + .write = dwc3_cp_toggle_write, + .open = dwc3_cp_toggle_open, + .read = NULL, + .llseek = seq_lseek, + .release = single_release, +}; + struct dwc3_ep_file_map { const char name[25]; const struct file_operations *const fops; @@ -1224,6 +1267,8 @@ void dwc3_debugfs_init(struct dwc3 *dwc) &dwc3_testmode_fops); debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, dwc, &dwc3_link_state_fops); + debugfs_create_file("cp_toggle", 0200, root, dwc, + &dwc3_cp_toggle_fops); dwc3_debugfs_create_endpoint_dirs(dwc, root); file = debugfs_create_file("int_events", 0644, root, dwc,