From 5c33f8f4c30dcc571675f45a131fce5eba8ee25f Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 4 Aug 2017 10:32:46 +0800 Subject: usb: mtu3: add a vbus debugfs interface Provides a new vbus debugfs interface used to turn on/off vbus regulator, it also can be used to get/put reference count of vbus, due to sometimes we need keep it alive when manually switch mtu3 to device mode. Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/mtu3/mtu3_dr.c | 58 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 8 deletions(-) (limited to 'drivers/usb/mtu3') diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 11a0d3b..5602561 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c @@ -322,23 +322,65 @@ static const struct file_operations ssusb_mode_fops = { .release = single_release, }; +static int ssusb_vbus_show(struct seq_file *sf, void *unused) +{ + struct ssusb_mtk *ssusb = sf->private; + struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; + + seq_printf(sf, "vbus state: %s\n(echo on/off)\n", + regulator_is_enabled(otg_sx->vbus) ? "on" : "off"); + + return 0; +} + +static int ssusb_vbus_open(struct inode *inode, struct file *file) +{ + return single_open(file, ssusb_vbus_show, inode->i_private); +} + +static ssize_t ssusb_vbus_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct seq_file *sf = file->private_data; + struct ssusb_mtk *ssusb = sf->private; + struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; + char buf[16]; + bool enable; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (kstrtobool(buf, &enable)) { + dev_err(ssusb->dev, "wrong setting\n"); + return -EINVAL; + } + + ssusb_set_vbus(otg_sx, enable); + + return count; +} + +static const struct file_operations ssusb_vbus_fops = { + .open = ssusb_vbus_open, + .write = ssusb_vbus_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void ssusb_debugfs_init(struct ssusb_mtk *ssusb) { struct dentry *root; - struct dentry *file; root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); - if (IS_ERR_OR_NULL(root)) { - if (!root) - dev_err(ssusb->dev, "create debugfs root failed\n"); + if (!root) { + dev_err(ssusb->dev, "create debugfs root failed\n"); return; } ssusb->dbgfs_root = root; - file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, - ssusb, &ssusb_mode_fops); - if (!file) - dev_dbg(ssusb->dev, "create debugfs mode failed\n"); + debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); + debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops); } static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb) -- cgit v1.1 From 8ba4ad488eebeae4d5f1b03524062aa0d70b3fdb Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 25 Jul 2017 16:10:22 +0800 Subject: usb: mtu3: handle delayed status of the control transfer Add the delayed status handling. This is used by mass storage etc to gain some extra time to setup its internal status before it can proceed further requests, and once the gadget is ready, it will enqueue an empty packet which is used for synchronization. The issue may happen on some FGPA platform with very low cpu frequency. Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/mtu3/mtu3.h | 2 ++ drivers/usb/mtu3/mtu3_gadget.c | 2 ++ drivers/usb/mtu3/mtu3_gadget_ep0.c | 23 ++++++++++++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/usb/mtu3') diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 7b6dc23..b26fffc 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -288,6 +288,7 @@ static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev) * MTU3_U3_IP_SLOT_DEFAULT for U3 IP * @may_wakeup: means device's remote wakeup is enabled * @is_self_powered: is reported in device status and the config descriptor + * @delayed_status: true when function drivers ask for delayed status * @ep0_req: dummy request used while handling standard USB requests * for GET_STATUS and SET_SEL * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests @@ -327,6 +328,7 @@ struct mtu3 { unsigned u1_enable:1; unsigned u2_enable:1; unsigned is_u3_ip:1; + unsigned delayed_status:1; u8 address; u8 test_mode_nr; diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 9dd2441..a4ad67c 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -663,6 +663,7 @@ int mtu3_gadget_setup(struct mtu3 *mtu) mtu->g.sg_supported = 0; mtu->g.name = MTU3_DRIVER_NAME; mtu->is_active = 0; + mtu->delayed_status = false; mtu3_gadget_init_eps(mtu); @@ -727,4 +728,5 @@ void mtu3_gadget_reset(struct mtu3 *mtu) mtu->address = 0; mtu->ep0_state = MU3D_EP0_STATE_SETUP; mtu->may_wakeup = 0; + mtu->delayed_status = false; } diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 2d7427b..958d74d 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -16,6 +16,8 @@ * */ +#include + #include "mtu3.h" /* ep0 is always mtu3->in_eps[0] */ @@ -150,6 +152,7 @@ static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy) csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL; mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); + mtu->delayed_status = false; mtu->ep0_state = MU3D_EP0_STATE_SETUP; dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", @@ -656,6 +659,9 @@ stall: finish: if (mtu->test_mode) { ; /* nothing to do */ + } else if (handled == USB_GADGET_DELAYED_STATUS) { + /* handle the delay STATUS phase till receive ep_queue on ep0 */ + mtu->delayed_status = true; } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */ mtu3_writel(mbase, U3D_EP0CSR, @@ -775,9 +781,6 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__, mep->name, decode_ep0_state(mtu), mreq->request.length); - if (!list_empty(&mep->req_list)) - return -EBUSY; - switch (mtu->ep0_state) { case MU3D_EP0_STATE_SETUP: case MU3D_EP0_STATE_RX: /* control-OUT data */ @@ -789,6 +792,20 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) return -EINVAL; } + if (mtu->delayed_status) { + u32 csr; + + mtu->delayed_status = false; + csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; + csr |= EP0_SETUPPKTRDY | EP0_DATAEND; + mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); + /* needn't giveback the request for handling delay STATUS */ + return 0; + } + + if (!list_empty(&mep->req_list)) + return -EBUSY; + list_add_tail(&mreq->list, &mep->req_list); /* sequence #1, IN ... start writing the data */ -- cgit v1.1 From d1e4a4076cce37af47f16badeb079019c16ed79c Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 25 Jul 2017 16:10:23 +0800 Subject: usb: mtu3: clear u1/u2_enable to 0 in mtu3_gadget_reset when the device is reset by host, the status of u1_enable and u2_enable should also be restored to default value. Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/mtu3/mtu3_gadget.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/mtu3') diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index a4ad67c..434fca5 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -728,5 +728,7 @@ void mtu3_gadget_reset(struct mtu3 *mtu) mtu->address = 0; mtu->ep0_state = MU3D_EP0_STATE_SETUP; mtu->may_wakeup = 0; + mtu->u1_enable = 0; + mtu->u2_enable = 0; mtu->delayed_status = false; } -- cgit v1.1 From 4a10a937ed20cb55066c4ac9bad4b5b7bbf8ccb5 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 25 Jul 2017 16:10:24 +0800 Subject: usb: mtu3: fix ip sleep auto-exit issue when enable DRD mode Ip sleep will auto exit if vbus comparison circuit of u2 phy is disabled when system tries to enter suspend mode, so get vbus-valid status from mac but not from u2 phy when enable DRD mode to fix the issue. Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/mtu3/mtu3_hw_regs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb/mtu3') diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 2123672..06b2966 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -462,10 +462,12 @@ #define SSUSB_U3_PORT_DIS BIT(0) /* U3D_SSUSB_U2_CTRL_0P */ +#define SSUSB_U2_PORT_VBUSVALID BIT(9) #define SSUSB_U2_PORT_OTG_SEL BIT(7) -#define SSUSB_U2_PORT_HOST_SEL BIT(2) +#define SSUSB_U2_PORT_HOST BIT(2) #define SSUSB_U2_PORT_PDN BIT(1) #define SSUSB_U2_PORT_DIS BIT(0) +#define SSUSB_U2_PORT_HOST_SEL (SSUSB_U2_PORT_VBUSVALID | SSUSB_U2_PORT_HOST) /* U3D_SSUSB_DEV_RST_CTRL */ #define SSUSB_DEV_SW_RST BIT(0) -- cgit v1.1 From dfcdcba9e30d23db0cbaae4828b0566a927e2489 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Aug 2017 13:42:49 +0800 Subject: usb: mtu3: add generic compatible string The mtu3 driver is a generic driver for MediaTek usb3 DRD IP, add a generic compatible to avoid confusion when support new SoCs but use a compatible with specific SoC's name "mt8173". Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- drivers/usb/mtu3/mtu3_plat.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/mtu3') diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 0d3ebb3..088e3e6 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -500,6 +500,7 @@ static const struct dev_pm_ops mtu3_pm_ops = { static const struct of_device_id mtu3_of_match[] = { {.compatible = "mediatek,mt8173-mtu3",}, + {.compatible = "mediatek,mtu3",}, {}, }; -- cgit v1.1