Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b9fe32d authored by Felipe Balbi's avatar Felipe Balbi
Browse files

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: default avatarFelipe Balbi <balbi@ti.com>
parent f96a6ec1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+82 −0
Original line number Diff line number Diff line
@@ -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: