From b765ff181ef64c56fad5cba31c1856fe8ef92d3c Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 9 Aug 2017 13:16:51 +0530 Subject: [PATCH 01/49] usb: gadget: f_uac2: constify snd_pcm_ops structures snd_pcm_ops are not supposed to change at runtime. All functions working with snd_pcm_ops provided by work with const snd_pcm_ops. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 5dd73b9e5172..d4caa212e666 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -354,7 +354,7 @@ static int uac_pcm_null(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops uac_pcm_ops = { +static const struct snd_pcm_ops uac_pcm_ops = { .open = uac_pcm_open, .close = uac_pcm_null, .ioctl = snd_pcm_lib_ioctl, From 8e374f0add2dc153d270757a71de45a0ba7d7004 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Aug 2017 17:34:45 -0500 Subject: [PATCH 02/49] usb: gadget: udc: renesas_usb3: fix error return code in renesas_usb3_probe() platform_get_irq() returns an error code, but the renesas_usb3 driver ignores it and always returns -ENODEV. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Also, notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print error message and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 62dc9c7798e7..6110dfcbaa26 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2457,8 +2457,10 @@ static int renesas_usb3_probe(struct platform_device *pdev) priv = match->data; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); + return irq; + } usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL); if (!usb3) From 8bcd9889721fea82e4de370b0d87e09950efb183 Mon Sep 17 00:00:00 2001 From: Doug Wilson Date: Tue, 8 Aug 2017 16:50:16 +0530 Subject: [PATCH 03/49] usb: dwc3: pci: constify dev_pm_ops dev_pm_ops is not supposed to change at runtime. Marking it constant. Signed-off-by: Doug Wilson Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 7e995df7a797..54343fbd85ee 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -345,7 +345,7 @@ static int dwc3_pci_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static struct dev_pm_ops dwc3_pci_dev_pm_ops = { +static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume, NULL) From 0ae99ecba7928c7bc66cf14d8a88f0b6ec9fc78e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Aug 2017 23:25:34 -0500 Subject: [PATCH 04/49] usb: dwc3: omap: fix error return code in dwc3_omap_probe() platform_get_irq() returns an error code, but the dwc3-omap driver ignores it and always returns -EINVAL. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index f5aaa0cf3873..3530795bbb8f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -478,8 +478,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "missing IRQ resource\n"); - return -EINVAL; + dev_err(dev, "missing IRQ resource: %d\n", irq); + return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); From c14af973ed863ac82e78259f188f2bc73d69851d Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Wed, 2 Aug 2017 15:17:22 -0500 Subject: [PATCH 05/49] usb: dwc3: keystone: Add PM_RUNTIME Support to DWC3 Keystone USB driver For 66AK2Gx there is a requirement to use PM Runtime to properly manage clocks and the power domains. Therefore, add PM runtime support. Remove legacy clock api's calls since other users of this driver worked without these clock apis calls. Signed-off-by: Franklin S Cooper Jr Signed-off-by: Sekhar Nori Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-keystone.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 12ee23f53cdd..d2ed9523e77c 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -15,7 +15,6 @@ * GNU General Public License for more details. */ -#include #include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include /* USBSS register offsets */ #define USBSS_REVISION 0x0000 @@ -41,7 +41,6 @@ struct dwc3_keystone { struct device *dev; - struct clk *clk; void __iomem *usbss; }; @@ -106,17 +105,13 @@ static int kdwc3_probe(struct platform_device *pdev) if (IS_ERR(kdwc->usbss)) return PTR_ERR(kdwc->usbss); - kdwc->clk = devm_clk_get(kdwc->dev, "usb"); - if (IS_ERR(kdwc->clk)) { - dev_err(kdwc->dev, "unable to get usb clock\n"); - return PTR_ERR(kdwc->clk); - } + pm_runtime_enable(kdwc->dev); - error = clk_prepare_enable(kdwc->clk); + error = pm_runtime_get_sync(kdwc->dev); if (error < 0) { - dev_err(kdwc->dev, "unable to enable usb clock, error %d\n", + dev_err(kdwc->dev, "pm_runtime_get_sync failed, error %d\n", error); - return error; + goto err_irq; } irq = platform_get_irq(pdev, 0); @@ -147,7 +142,8 @@ static int kdwc3_probe(struct platform_device *pdev) err_core: kdwc3_disable_irqs(kdwc); err_irq: - clk_disable_unprepare(kdwc->clk); + pm_runtime_put_sync(kdwc->dev); + pm_runtime_disable(kdwc->dev); return error; } @@ -167,7 +163,9 @@ static int kdwc3_remove(struct platform_device *pdev) kdwc3_disable_irqs(kdwc); device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); - clk_disable_unprepare(kdwc->clk); + pm_runtime_put_sync(kdwc->dev); + pm_runtime_disable(kdwc->dev); + platform_set_drvdata(pdev, NULL); return 0; From 5c33f8f4c30dcc571675f45a131fce5eba8ee25f Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 4 Aug 2017 10:32:46 +0800 Subject: [PATCH 06/49] 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(-) diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 11a0d3b84c5e..560256115b23 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) From 7d343a6a88d40b12f882ffd99aa79ef70a3849d2 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 4 Aug 2017 10:32:47 +0800 Subject: [PATCH 07/49] MAINTAINERS: add entry for mediatek usb3 DRD IP driver Add myself as maintainer of MediaTek USB3 DRD IP driver Signed-off-by: Chunfeng Yun Signed-off-by: Felipe Balbi --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 44cb004c765d..88e3553e09f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8465,6 +8465,14 @@ M: Sean Wang S: Maintained F: drivers/char/hw_random/mtk-rng.c +MEDIATEK USB3 DRD IP DRIVER +M: Chunfeng Yun +L: linux-usb@vger.kernel.org (moderated for non-subscribers) +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: drivers/usb/mtu3/ + MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES M: Peter Senna Tschudin M: Martin Donnelly From 43ba968b00ea4d0876f4074e190ad98aefaba25d Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 4 Aug 2017 11:16:56 +0900 Subject: [PATCH 08/49] usb: gadget: udc: renesas_usb3: add debugfs to set the b-device mode This patch adds debugfs to set the "b-device" mode for using a board which is not connected to the ID pin (e.g. CN11 on Salvator-X). If we want to use peripheral mode on such a board, we have to disable VBUS output first. So, this patch can set such a mode as the following: # mount -t debugfs none /sys/kernel/debug # modprobe renesas_usb3 # modprobe g_mass_storage file=/dev/shm/test.bin # echo 1 > /sys/kernel/debug/ee020000.usb/b_device Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 78 ++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 6110dfcbaa26..298d9924e2e1 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -8,6 +8,7 @@ * the Free Software Foundation; version 2 of the License. */ +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -347,6 +349,7 @@ struct renesas_usb3 { bool workaround_for_vbus; bool extcon_host; /* check id and set EXTCON_USB_HOST */ bool extcon_usb; /* check vbus and set EXTCON_USB */ + bool forced_b_device; }; #define gadget_to_renesas_usb3(_gadget) \ @@ -663,7 +666,9 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev) spin_lock_irqsave(&usb3->lock, flags); usb3_set_mode(usb3, host); usb3_vbus_out(usb3, a_dev); - if (!host && a_dev) /* for A-Peripheral */ + /* for A-Peripheral or forced B-device mode */ + if ((!host && a_dev) || + (usb3->workaround_for_vbus && usb3->forced_b_device)) usb3_connect(usb3); spin_unlock_irqrestore(&usb3->lock, flags); } @@ -677,7 +682,7 @@ static void usb3_check_id(struct renesas_usb3 *usb3) { usb3->extcon_host = usb3_is_a_device(usb3); - if (usb3->extcon_host) + if (usb3->extcon_host && !usb3->forced_b_device) usb3_mode_config(usb3, true, true); else usb3_mode_config(usb3, false, false); @@ -2272,6 +2277,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, if (!usb3->driver) return -ENODEV; + if (usb3->forced_b_device) + return -EBUSY; + if (!strncmp(buf, "host", strlen("host"))) new_mode_is_host = true; else if (!strncmp(buf, "peripheral", strlen("peripheral"))) @@ -2299,6 +2307,70 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(role); +static int renesas_usb3_b_device_show(struct seq_file *s, void *unused) +{ + struct renesas_usb3 *usb3 = s->private; + + seq_printf(s, "%d\n", usb3->forced_b_device); + + return 0; +} + +static int renesas_usb3_b_device_open(struct inode *inode, struct file *file) +{ + return single_open(file, renesas_usb3_b_device_show, inode->i_private); +} + +static ssize_t renesas_usb3_b_device_write(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct renesas_usb3 *usb3 = s->private; + char buf[32]; + + if (!usb3->driver) + return -ENODEV; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "1", 1)) + usb3->forced_b_device = true; + else + usb3->forced_b_device = false; + + /* Let this driver call usb3_connect() anyway */ + usb3_check_id(usb3); + + return count; +} + +static const struct file_operations renesas_usb3_b_device_fops = { + .open = renesas_usb3_b_device_open, + .write = renesas_usb3_b_device_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, + struct device *dev) +{ + struct dentry *root, *file; + + root = debugfs_create_dir(dev_name(dev), NULL); + if (IS_ERR_OR_NULL(root)) { + dev_info(dev, "%s: Can't create the root\n", __func__); + return; + } + + file = debugfs_create_file("b_device", 0644, root, usb3, + &renesas_usb3_b_device_fops); + if (!file) + dev_info(dev, "%s: Can't create debugfs mode\n", __func__); +} + /*------- platform_driver ------------------------------------------------*/ static int renesas_usb3_remove(struct platform_device *pdev) { @@ -2518,6 +2590,8 @@ static int renesas_usb3_probe(struct platform_device *pdev) usb3->workaround_for_vbus = priv->workaround_for_vbus; + renesas_usb3_debugfs_init(usb3, &pdev->dev); + dev_info(&pdev->dev, "probed\n"); return 0; From 974203c0b9811aeee77ffcbe37835d5873bd0f88 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 4 Aug 2017 11:16:57 +0900 Subject: [PATCH 09/49] usb: gadget: udc: renesas_usb3: add support for R-Car H3 ES2.0 This patch adds support for R-Car H3 ES2.0. Since this SoC revision doesn't need workaround for vbus detection and number of ramif is increased. So, this driver uses soc_device_match() to detect it. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 298d9924e2e1..ff69f4645b7c 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2493,22 +2494,36 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev, } } -static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795 = { +static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = { .ramsize_per_ramif = SZ_16K, .num_ramif = 2, .ramsize_per_pipe = SZ_4K, .workaround_for_vbus = true, }; +static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { + .ramsize_per_ramif = SZ_16K, + .num_ramif = 4, + .ramsize_per_pipe = SZ_4K, +}; + static const struct of_device_id usb3_of_match[] = { { .compatible = "renesas,r8a7795-usb3-peri", - .data = &renesas_usb3_priv_r8a7795, + .data = &renesas_usb3_priv_gen3, }, { }, }; MODULE_DEVICE_TABLE(of, usb3_of_match); +static const struct soc_device_attribute renesas_usb3_quirks_match[] = { + { + .soc_id = "r8a7795", .revision = "ES1.*", + .data = &renesas_usb3_priv_r8a7795_es1, + }, + { /* sentinel */ }, +}; + static const unsigned int renesas_usb3_cable[] = { EXTCON_USB, EXTCON_USB_HOST, @@ -2522,11 +2537,17 @@ static int renesas_usb3_probe(struct platform_device *pdev) const struct of_device_id *match; int irq, ret; const struct renesas_usb3_priv *priv; + const struct soc_device_attribute *attr; match = of_match_node(usb3_of_match, pdev->dev.of_node); if (!match) return -ENODEV; - priv = match->data; + + attr = soc_device_match(renesas_usb3_quirks_match); + if (attr) + priv = attr->data; + else + priv = match->data; irq = platform_get_irq(pdev, 0); if (irq < 0) { From b744a2e00367a477e9c4a3e8293ab3e1c29d302e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 4 Aug 2017 11:16:58 +0900 Subject: [PATCH 10/49] usb: gadget: udc: renesas_usb3: add support for R-Car M3-W This patch adds support for R-Car M3-W. This patch also adds R-Car Gen3 generic version's compatible and changes ".compatible" in the usb3_of_match from "renesas,r8a7796-usb3-peri" to "renesas,rcar-gen3-usb3-peri". Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/renesas_usb3.txt | 16 +++++++++++++--- drivers/usb/gadget/udc/renesas_usb3.c | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt index 8d52766f07b9..e28025883b79 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usb3.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt @@ -3,20 +3,30 @@ Renesas Electronics USB3.0 Peripheral driver Required properties: - compatible: Must contain one of the following: - "renesas,r8a7795-usb3-peri" + - "renesas,r8a7796-usb3-peri" + - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible + device + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + - reg: Base address and length of the register for the USB3.0 Peripheral - interrupts: Interrupt specifier for the USB3.0 Peripheral - clocks: clock phandle and specifier pair -Example: +Example of R-Car H3 ES1.x: usb3_peri0: usb@ee020000 { - compatible = "renesas,r8a7795-usb3-peri"; + compatible = "renesas,r8a7795-usb3-peri", + "renesas,rcar-gen3-usb3-peri"; reg = <0 0xee020000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 328>; }; usb3_peri1: usb@ee060000 { - compatible = "renesas,r8a7795-usb3-peri"; + compatible = "renesas,r8a7795-usb3-peri", + "renesas,rcar-gen3-usb3-peri"; reg = <0 0xee060000 0 0x400>; interrupts = ; clocks = <&cpg CPG_MOD 327>; diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index ff69f4645b7c..16ceb445bee8 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2512,6 +2512,10 @@ static const struct of_device_id usb3_of_match[] = { .compatible = "renesas,r8a7795-usb3-peri", .data = &renesas_usb3_priv_gen3, }, + { + .compatible = "renesas,rcar-gen3-usb3-peri", + .data = &renesas_usb3_priv_gen3, + }, { }, }; MODULE_DEVICE_TABLE(of, usb3_of_match); From 89c996820629a36553b5dbb975f4f47597951d8a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 2 Aug 2017 17:29:27 +0200 Subject: [PATCH 11/49] usb: gadget: fsl_qe_udc: constify qe_ep0_desc qe_ep0_desc is only passed as the second argument to qe_ep_init, which is const, so qe_ep0_desc can be const too. Done with the help of Coccinelle. Acked-by: Li Yang Signed-off-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_qe_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 303328ce59ee..a3e72d690eef 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -62,7 +62,7 @@ static const char *const ep_name[] = { "ep3", }; -static struct usb_endpoint_descriptor qe_ep0_desc = { +static const struct usb_endpoint_descriptor qe_ep0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, From c7733dc117fe0a8b0095cc3c3b4c22c67a4b5155 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 29 Jul 2017 21:58:56 -0300 Subject: [PATCH 12/49] usb: phy: qcom: Use devm_ioremap_resource() Using devm_ioremap_resource() can make the code simpler, as it already does the resource NULL check. Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-qcom-8x16-usb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index b6a83a5cbad3..679afeaaa9a8 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -270,12 +270,9 @@ static int phy_8x16_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qphy); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!qphy->regs) - return -ENOMEM; + qphy->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(qphy->regs)) + return PTR_ERR(qphy->regs); phy = &qphy->phy; phy->dev = &pdev->dev; From 8ba4ad488eebeae4d5f1b03524062aa0d70b3fdb Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 25 Jul 2017 16:10:22 +0800 Subject: [PATCH 13/49] 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(-) diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 7b6dc23d77e9..b26fffc58446 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 9dd2441b4fa1..a4ad67cf0c52 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 2d7427b48775..958d74dd2b78 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 */ From d1e4a4076cce37af47f16badeb079019c16ed79c Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 25 Jul 2017 16:10:23 +0800 Subject: [PATCH 14/49] 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(+) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index a4ad67cf0c52..434fca58143c 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; } From 4a10a937ed20cb55066c4ac9bad4b5b7bbf8ccb5 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 25 Jul 2017 16:10:24 +0800 Subject: [PATCH 15/49] 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(-) diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 212367295276..06b29664470f 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) From b3c4ec71ec413c2e5bfb028bdf1737af07f1fde0 Mon Sep 17 00:00:00 2001 From: Abdulhadi Mohamed Date: Wed, 19 Jul 2017 16:31:10 +0100 Subject: [PATCH 16/49] usb: gadget: f_hid: {GET,SET} PROTOCOL Support The current f_hid driver doesn't handle GET_PROCOTOL and SET_PROCOTOL requests, which are required to operate HID gadgets in BOOT mode. This patch implements this feature for devices that have the same implementation for REPORT and BOOT mode so that these devices are recognized by older BIOSes. Signed-off-by: Abdulhadi Mohamed Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_hid.c | 17 ++++++++++++++++- include/linux/hid.h | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 5eea44823ca0..d8e359ef6eb1 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -44,6 +44,7 @@ struct f_hidg { /* configuration */ unsigned char bInterfaceSubClass; unsigned char bInterfaceProtocol; + unsigned char protocol; unsigned short report_desc_length; char *report_desc; unsigned short report_length; @@ -527,7 +528,9 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_GET_PROTOCOL): VDBG(cdev, "get_protocol\n"); - goto stall; + length = min_t(unsigned int, length, 1); + ((u8 *) req->buf)[0] = hidg->protocol; + goto respond; break; case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 @@ -539,6 +542,17 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_SET_PROTOCOL): VDBG(cdev, "set_protocol\n"); + if (value > HID_REPORT_PROTOCOL) + goto stall; + length = 0; + /* + * We assume that programs implementing the Boot protocol + * are also compatible with the Report Protocol + */ + if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { + hidg->protocol = value; + goto respond; + } goto stall; break; @@ -768,6 +782,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; + hidg->protocol = HID_REPORT_PROTOCOL; hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); hidg_ss_in_comp_desc.wBytesPerInterval = cpu_to_le16(hidg->report_length); diff --git a/include/linux/hid.h b/include/linux/hid.h index 5006f9b5d837..6519cdc4c7d3 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -362,6 +362,12 @@ struct hid_item { #define HID_GROUP_WACOM 0x0101 #define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102 +/* + * HID protocol status + */ +#define HID_REPORT_PROTOCOL 1 +#define HID_BOOT_PROTOCOL 0 + /* * This is the global environment of the parser. This information is * persistent for main-items. The global environment can be saved and From dfcdcba9e30d23db0cbaae4828b0566a927e2489 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 8 Aug 2017 13:42:49 +0800 Subject: [PATCH 17/49] 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(+) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 0d3ebb353e08..088e3e685c4f 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",}, {}, }; From c05429005ba906bb88d6e50898d1f64604751dc2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 15 Aug 2017 10:09:52 +0200 Subject: [PATCH 18/49] usb: gadget: f_midi: constify snd_rawmidi_ops structures These snd_rawmidi_ops structures are only passed as the third argument of snd_rawmidi_set_ops. This argument is const, so the snd_rawmidi_ops structures can be const too. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a5719f271bf0..71ca86c0d772 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -755,13 +755,13 @@ static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) clear_bit(substream->number, &midi->out_triggered); } -static struct snd_rawmidi_ops gmidi_in_ops = { +static const struct snd_rawmidi_ops gmidi_in_ops = { .open = f_midi_in_open, .close = f_midi_in_close, .trigger = f_midi_in_trigger, }; -static struct snd_rawmidi_ops gmidi_out_ops = { +static const struct snd_rawmidi_ops gmidi_out_ops = { .open = f_midi_out_open, .close = f_midi_out_close, .trigger = f_midi_out_trigger From a79741fdb0605d75323872035d858556c8388e77 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Aug 2017 08:38:45 +0100 Subject: [PATCH 19/49] usb: gadget: dummy: fix infinite loop because of missing loop decrement The while loop never terminates because the loop counter i is never decremented. Fix this by decrementing i. Detected by CoverityScan, CID#751073 ("Infinite Loop") Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 3c3760315910..a030d7923d7d 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2776,7 +2776,7 @@ static int __init init(void) if (retval < 0) { i--; while (i >= 0) - platform_device_del(the_udc_pdev[i]); + platform_device_del(the_udc_pdev[i--]); goto err_add_udc; } } From 24cf34595d560de0d8eccd6617b7ca5b4ef93d3e Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Mon, 14 Aug 2017 18:15:14 -0700 Subject: [PATCH 20/49] usb: gadget: f_midi: add super speed support Add super speed descriptors for f_midi. Signed-off-by: Badhri Jagan Sridharan Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 42 ++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 71ca86c0d772..94a2012b78f8 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -163,6 +163,13 @@ static struct usb_endpoint_descriptor bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_ss_ep_comp_descriptor bulk_out_ss_comp_desc = { + .bLength = sizeof(bulk_out_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + /* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ static struct usb_ms_endpoint_descriptor_16 ms_out_desc = { /* .bLength = DYNAMIC */ @@ -180,6 +187,13 @@ static struct usb_endpoint_descriptor bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_ss_ep_comp_descriptor bulk_in_ss_comp_desc = { + .bLength = sizeof(bulk_in_ss_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + /* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ static struct usb_ms_endpoint_descriptor_16 ms_in_desc = { /* .bLength = DYNAMIC */ @@ -853,7 +867,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_midi *midi = func_to_midi(f); struct usb_string *us; - int status, n, jack = 1, i = 0; + int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); @@ -895,7 +909,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail; /* allocate temporary function list */ - midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function), + midi_function = kcalloc((MAX_PORTS * 4) + 11, sizeof(*midi_function), GFP_KERNEL); if (!midi_function) { status = -ENOMEM; @@ -985,6 +999,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) ms_in_desc.bNumEmbMIDIJack = midi->out_ports; /* ... and add them to the list */ + endpoint_descriptor_index = i; midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc; midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; @@ -1009,13 +1024,34 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail_f_midi; } + if (gadget_is_superspeed(c->cdev->gadget)) { + bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024); + bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024); + i = endpoint_descriptor_index; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_out_ss_comp_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &ms_out_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_in_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &bulk_in_ss_comp_desc; + midi_function[i++] = (struct usb_descriptor_header *) + &ms_in_desc; + f->ss_descriptors = usb_copy_descriptors(midi_function); + if (!f->ss_descriptors) + goto fail_f_midi; + } + kfree(midi_function); return 0; fail_f_midi: kfree(midi_function); - usb_free_descriptors(f->hs_descriptors); + usb_free_all_descriptors(f); fail: f_midi_unregister_card(midi); fail_register: From 2d19cdc1cb7ab00003fccb951d6199b8d8c9ac67 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Mon, 14 Aug 2017 14:14:51 -0700 Subject: [PATCH 21/49] usb: gadget: f_midi: Use snd_card_free_when_closed with refcount Currenly, f_midi_free uses snd_card_free, which will wait until the user has released the sound card before returning. However, if the user doesn't release the sound card, then f_midi_free can block for an arbitrary amount of time, which also blocks any gadget operations on that thread. Instead, we can use snd_card_free_when_closed which returns before all handles are released. Since f_midi can be accessed through rmidi if usb_put_function is called before release_card_device, add refcounting to f_midi_free and have rawmidi's private free call it. The f_midi memory is only kfreed when usb_put_function and release_card_device have both been called. Signed-off-by: Jerry Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 94a2012b78f8..5d3d7941d2c2 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -98,6 +98,7 @@ struct f_midi { DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); spinlock_t transmit_lock; unsigned int in_last_port; + unsigned char free_ref; struct gmidi_in_port in_ports_array[/* in_ports */]; }; @@ -108,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f) } static void f_midi_transmit(struct f_midi *midi); +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); @@ -832,6 +834,8 @@ static int f_midi_register_card(struct f_midi *midi) SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = midi; + rmidi->private_free = f_midi_rmidi_free; + midi->free_ref++; /* * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. @@ -1233,14 +1237,21 @@ static void f_midi_free(struct usb_function *f) midi = func_to_midi(f); opts = container_of(f->fi, struct f_midi_opts, func_inst); - kfree(midi->id); mutex_lock(&opts->lock); - kfifo_free(&midi->in_req_fifo); - kfree(midi); - --opts->refcnt; + if (!--midi->free_ref) { + kfree(midi->id); + kfifo_free(&midi->in_req_fifo); + kfree(midi); + --opts->refcnt; + } mutex_unlock(&opts->lock); } +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi) +{ + f_midi_free(rmidi->private_data); +} + static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = f->config->cdev; @@ -1255,7 +1266,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) card = midi->card; midi->card = NULL; if (card) - snd_card_free(card); + snd_card_free_when_closed(card); usb_free_all_descriptors(f); } @@ -1299,6 +1310,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) midi->buflen = opts->buflen; midi->qlen = opts->qlen; midi->in_last_port = 0; + midi->free_ref = 1; status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL); if (status) From e7059ef82a228ba9df21f5e43b06353385b098f1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 13 Aug 2017 22:21:11 +0800 Subject: [PATCH 22/49] usb: dwc3: of-simple: remove include of clk-provider.h The header clk-provider.h is there for clock drivers (providers) to include, not client drivers (consumers). That said, of_clk_get_parent_count() is a helper function for clock providers, not a clk API for consumers. Let's replace of_clk_get_parent_count() with of_count_phandle_with_args() call, so that we can remove the include of clk-provider.h. Signed-off-by: Shawn Guo Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-of-simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index fe414e7a9c78..4cef7d4f9cd0 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -96,7 +95,8 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) platform_set_drvdata(pdev, simple); simple->dev = dev; - ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np)); + ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np, + "clocks", "#clock-cells")); if (ret) return ret; From 7fc461378cad592e8e606cce2b05b917982539fc Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 12 Aug 2017 17:34:53 +0530 Subject: [PATCH 23/49] usb: renesas_usbhs: gadget: make usb_ep_ops const Make the structure const as it is only stored in the ops field of a usb_ep structure, which is of type const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 93fba9033b00..b45b9f1e3d9d 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -767,7 +767,7 @@ static int usbhsg_ep_set_wedge(struct usb_ep *ep) return __usbhsg_ep_set_halt_wedge(ep, 1, 1); } -static struct usb_ep_ops usbhsg_ep_ops = { +static const struct usb_ep_ops usbhsg_ep_ops = { .enable = usbhsg_ep_enable, .disable = usbhsg_ep_disable, From 64b59f11dd52071a800090ca14212b5c22aaa683 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 12 Aug 2017 17:34:54 +0530 Subject: [PATCH 24/49] usb: gadget: udc: renesas_usb3: make usb_ep_ops const Make the structure const as it is only stored in the ops field of a usb_ep structure, which is of type const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/renesas_usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 16ceb445bee8..2e55ccc28d1c 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2187,7 +2187,7 @@ static void renesas_usb3_ep_fifo_flush(struct usb_ep *_ep) } } -static struct usb_ep_ops renesas_usb3_ep_ops = { +static const struct usb_ep_ops renesas_usb3_ep_ops = { .enable = renesas_usb3_ep_enable, .disable = renesas_usb3_ep_disable, From ebce561a0d140aab63ceb7703aeb6ae7627fd320 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 12 Aug 2017 17:34:55 +0530 Subject: [PATCH 25/49] usb: dwc2: gadget: make usb_ep_ops const Make the structure const as it is only stored in the ops field of a usb_ep structure, which is of type const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index c4066cd77e47..0d8e09ccb59c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4179,7 +4179,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) return ret; } -static struct usb_ep_ops dwc2_hsotg_ep_ops = { +static const struct usb_ep_ops dwc2_hsotg_ep_ops = { .enable = dwc2_hsotg_ep_enable, .disable = dwc2_hsotg_ep_disable, .alloc_request = dwc2_hsotg_ep_alloc_request, From f8faa3bf5fc988e504766b8d1bb7b3d5fb09f6f8 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Fri, 11 Aug 2017 08:33:23 -0300 Subject: [PATCH 26/49] usb: gadget: allow serial gadget console on other configs USB gadget serial console works on functions other than the legacy configurations. Let the user enable it when using any function that uses the serial utilities. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 35cc641d9f31..31cce7805eb2 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -130,7 +130,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS config U_SERIAL_CONSOLE bool "Serial gadget console support" - depends on USB_G_SERIAL + depends on USB_U_SERIAL help It supports the serial gadget can be used as a console. From 31fe084ffaaf8abece14f8ca28e5e3b4e2bf97b6 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 1 Aug 2017 02:00:56 -0700 Subject: [PATCH 27/49] usb: gadget: core: unmap request from DMA only if previously mapped In the SG case this is already handled since a non-zero request->num_mapped_sgs is a clear indicator that dma_map_sg() had been called. While it would be nice to do the same for the singly mapped case by simply checking for non-zero request->dma, it's conceivable that 0 is a valid dma_addr_t handle. Hence add a flag 'dma_mapped' to struct usb_request and use this to determine the need to call dma_unmap_single(). Otherwise, if a request is not DMA mapped then the result of calling usb_request_unmap_request() would safely be a no-op. Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/core.c | 5 ++++- include/linux/usb/gadget.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index e6f04eee95c4..c1cef6a11ecb 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -812,6 +812,8 @@ int usb_gadget_map_request_by_dev(struct device *dev, dev_err(dev, "failed to map buffer\n"); return -EFAULT; } + + req->dma_mapped = 1; } return 0; @@ -836,9 +838,10 @@ void usb_gadget_unmap_request_by_dev(struct device *dev, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->num_mapped_sgs = 0; - } else { + } else if (req->dma_mapped) { dma_unmap_single(dev, req->dma, req->length, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->dma_mapped = 0; } } EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 1a4a4bacfae6..21468a722c4a 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -48,6 +48,7 @@ struct usb_ep; * by adding a zero length packet as needed; * @short_not_ok: When reading data, makes short packets be * treated as errors (queue stops advancing till cleanup). + * @dma_mapped: Indicates if request has been mapped to DMA (internal) * @complete: Function called when request completes, so this request and * its buffer may be re-used. The function will always be called with * interrupts disabled, and it must not sleep. @@ -103,6 +104,7 @@ struct usb_request { unsigned no_interrupt:1; unsigned zero:1; unsigned short_not_ok:1; + unsigned dma_mapped:1; void (*complete)(struct usb_ep *ep, struct usb_request *req); From 14a8d4bfc2102f85ce097563d151370c91c1898a Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 9 Aug 2017 19:55:24 +0900 Subject: [PATCH 28/49] usb: renesas_usbhs: gadget: fix spin_lock_init() for &uep->lock This patch fixes an issue that the spin_lock_init() is not called for almost all pipes. Otherwise, the lockdep output the following message when we connect a usb cable using g_ncm: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. Reported-by: Kazuya Mizuguchi Fixes: b8b9c974afee ("usb: renesas_usbhs: gadget: disable all eps when the driver stops") Signed-off-by: Yoshihiro Shimoda Tested-by: Kazuya Mizuguchi Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index b45b9f1e3d9d..ea9c5451d3f8 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1085,7 +1085,6 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; } - spin_lock_init(&uep->lock); gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); dev_info(dev, "%stransceiver found\n", @@ -1135,6 +1134,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) uep->ep.name = uep->ep_name; uep->ep.ops = &usbhsg_ep_ops; INIT_LIST_HEAD(&uep->ep.ep_list); + spin_lock_init(&uep->lock); /* init DCP */ if (usbhsg_is_dcp(uep)) { From f367b72c4e08aafacc5267c73299a62ca79635ec Mon Sep 17 00:00:00 2001 From: Meng Dongyang Date: Wed, 9 Aug 2017 10:34:09 +0800 Subject: [PATCH 29/49] usb: dwc2: skip L2 state of hcd if controller work in device mode In the case hcd autosuspend is enabled, the hcd will enter L2 state if no device connected. But if the controller works in otg mode, the gadget driver still works in L0 state if connected with host. This may result in transfer fail when gadget enqueue new request but the hcd driver has set the global state into L2. This patch prevent the hcd enter L2 state if the controller work in device mode. Signed-off-by: Meng Dongyang Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 740c7e86d31b..c2631145f404 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4388,6 +4388,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&hsotg->lock, flags); + if (dwc2_is_device_mode(hsotg)) + goto unlock; + if (hsotg->lx_state != DWC2_L0) goto unlock; @@ -4446,6 +4449,9 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) spin_lock_irqsave(&hsotg->lock, flags); + if (dwc2_is_device_mode(hsotg)) + goto unlock; + if (hsotg->lx_state != DWC2_L2) goto unlock; From 2edb048090ccc70d316fe914f3c039b01d3217b3 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 4 Aug 2017 17:36:43 +0530 Subject: [PATCH 30/49] usb: phy-mv-usb: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mv-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 697a741a0cb1..d17cc92c282e 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -650,7 +650,7 @@ static struct attribute *inputs_attrs[] = { NULL, }; -static struct attribute_group inputs_attr_group = { +static const struct attribute_group inputs_attr_group = { .name = "inputs", .attrs = inputs_attrs, }; From 6cea1449f6926162432e7d62c02ab7a4166c8c25 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 4 Aug 2017 17:36:44 +0530 Subject: [PATCH 31/49] usb: phy-tahvo: constify attribute_group structures. attribute_group are not supposed to change at runtime. All functions working with attribute_group provided by work with const attribute_group. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tahvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index a31c8682e998..8babd318c0ed 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -326,7 +326,7 @@ static struct attribute *tahvo_attributes[] = { NULL }; -static struct attribute_group tahvo_attr_group = { +static const struct attribute_group tahvo_attr_group = { .attrs = tahvo_attributes, }; From 73517cf49bd449122b615d2b7a6bb835f02252e5 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 29 Jul 2017 20:12:57 -0500 Subject: [PATCH 32/49] usb: gadget: add RNDIS configfs options for class/subclass/protocol This adds 3 new options to the RNDIS gadget function configs. It allows overriding the default USB interface class/subclass/protocol. The motivation for this is that if you set the values to "ef" (Misc), "04" (RNDIS), "01" (Ethernet) respectively, then the device will be recognized by the rndiscmp.inf file in Windows Vista and newer and will cause Windows to load the correct RNDIS driver without the need for a custom (signed) .inf file. Signed-off-by: David Lechner Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-rndis | 3 ++ drivers/usb/gadget/function/f_rndis.c | 20 +++++++++++ .../usb/gadget/function/u_ether_configfs.h | 35 +++++++++++++++++++ drivers/usb/gadget/function/u_rndis.h | 4 +++ 4 files changed, 62 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis index e32879b84b4d..137399095d74 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-rndis +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis @@ -12,3 +12,6 @@ Description: Ethernet over USB link dev_addr - MAC address of device's end of this Ethernet over USB link + class - USB interface class, default is 02 (hex) + subclass - USB interface subclass, default is 06 (hex) + protocol - USB interface protocol, default is 00 (hex) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 16562e461121..e1d5853ef1e4 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -691,6 +691,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; } + rndis_iad_descriptor.bFunctionClass = rndis_opts->class; + rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; + rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; + /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, @@ -866,11 +870,23 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); /* f_rndis_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); +/* f_rndis_opts_class */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, class); + +/* f_rndis_opts_subclass */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); + +/* f_rndis_opts_protocol */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); + static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, &rndis_opts_attr_qmult, &rndis_opts_attr_ifname, + &rndis_opts_attr_class, + &rndis_opts_attr_subclass, + &rndis_opts_attr_protocol, NULL, }; @@ -916,6 +932,10 @@ static struct usb_function_instance *rndis_alloc_inst(void) } INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); + opts->class = rndis_iad_descriptor.bFunctionClass; + opts->subclass = rndis_iad_descriptor.bFunctionSubClass; + opts->protocol = rndis_iad_descriptor.bFunctionProtocol; + descs[0] = &opts->rndis_os_desc; names[0] = "rndis"; config_group_init_type_name(&opts->func_inst.group, "", diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index c71133de17e7..e4c3f84af4c3 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -153,4 +153,39 @@ out: \ \ CONFIGFS_ATTR_RO(_f_##_opts_, ifname) +#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ + static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ + char *page) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret; \ + \ + mutex_lock(&opts->lock); \ + ret = sprintf(page, "%02x\n", opts->_n_); \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\ + const char *page, \ + size_t len) \ + { \ + struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ + int ret; \ + u8 val; \ + \ + mutex_lock(&opts->lock); \ + ret = sscanf(page, "%02hhx", &val); \ + if (ret > 0) { \ + opts->_n_ = val; \ + ret = len; \ + } \ + mutex_unlock(&opts->lock); \ + \ + return ret; \ + } \ + \ + CONFIGFS_ATTR(_f_##_opts_, _n_) + #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 4eafd5050545..a35ee3c2545d 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -29,6 +29,10 @@ struct f_rndis_opts { struct usb_os_desc rndis_os_desc; char rndis_ext_compat_id[16]; + u8 class; + u8 subclass; + u8 protocol; + /* * Read/write access to configfs attributes is handled by configfs. * From 5916733e9b689ea1e713bee87b445d2accfef0ea Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:40 -0400 Subject: [PATCH 33/49] usb: bdc: Fix misleading register names The BDC endpoint status registers 0-7 were originally each going to be an array of regsiters. This was later changed to being a single register. The register definitions are being changed from: "#define BDC_EPSTS0(n) (0x60 + (n * 0x10))" to "#define BDC_EPSTS0 0x60" to reflect this change and to avoid future coding mistakes. Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc.h | 16 ++++++++-------- drivers/usb/gadget/udc/bdc/bdc_dbg.c | 16 ++++++++-------- drivers/usb/gadget/udc/bdc/bdc_ep.c | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index 916d47135cac..36648087b54a 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -83,14 +83,14 @@ #define BDC_DVCSA 0x50 #define BDC_DVCSB 0x54 -#define BDC_EPSTS0(n) (0x60 + (n * 0x10)) -#define BDC_EPSTS1(n) (0x64 + (n * 0x10)) -#define BDC_EPSTS2(n) (0x68 + (n * 0x10)) -#define BDC_EPSTS3(n) (0x6c + (n * 0x10)) -#define BDC_EPSTS4(n) (0x70 + (n * 0x10)) -#define BDC_EPSTS5(n) (0x74 + (n * 0x10)) -#define BDC_EPSTS6(n) (0x78 + (n * 0x10)) -#define BDC_EPSTS7(n) (0x7c + (n * 0x10)) +#define BDC_EPSTS0 0x60 +#define BDC_EPSTS1 0x64 +#define BDC_EPSTS2 0x68 +#define BDC_EPSTS3 0x6c +#define BDC_EPSTS4 0x70 +#define BDC_EPSTS5 0x74 +#define BDC_EPSTS6 0x78 +#define BDC_EPSTS7 0x7c #define BDC_SRRBAL(n) (0x200 + (n * 0x10)) #define BDC_SRRBAH(n) (0x204 + (n * 0x10)) #define BDC_SRRINT(n) (0x208 + (n * 0x10)) diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c index 5945dbc47825..ac98f6f681b7 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_dbg.c +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c @@ -40,28 +40,28 @@ void bdc_dump_epsts(struct bdc *bdc) { u32 temp; - temp = bdc_readl(bdc->regs, BDC_EPSTS0(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS0); dev_vdbg(bdc->dev, "BDC_EPSTS0:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS1(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS1); dev_vdbg(bdc->dev, "BDC_EPSTS1:0x%x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS2(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS2); dev_vdbg(bdc->dev, "BDC_EPSTS2:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS3(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS3); dev_vdbg(bdc->dev, "BDC_EPSTS3:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS4(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS4); dev_vdbg(bdc->dev, "BDC_EPSTS4:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS5(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS5); dev_vdbg(bdc->dev, "BDC_EPSTS5:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS6(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS6); dev_vdbg(bdc->dev, "BDC_EPSTS6:0x%08x\n", temp); - temp = bdc_readl(bdc->regs, BDC_EPSTS7(0)); + temp = bdc_readl(bdc->regs, BDC_EPSTS7); dev_vdbg(bdc->dev, "BDC_EPSTS7:0x%08x\n", temp); } diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index ff1ef24d1777..bfd8f7ade935 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -777,9 +777,9 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) */ /* The current hw dequeue pointer */ - tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0)); + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0); deq_ptr_64 = tmp_32; - tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0)); + tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1); deq_ptr_64 |= ((u64)tmp_32 << 32); /* we have the dma addr of next bd that will be fetched by hardware */ From 7890b16a999f53be4235bd0f1f8329773bd12237 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:41 -0400 Subject: [PATCH 34/49] dt-bindings: usb: bdc: Add Device Tree binding for Broadcom UDC driver Add Device Tree binding document for Broadcom USB Device Controller (BDC). Acked-by: Rob Herring Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/brcm,bdc.txt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/brcm,bdc.txt diff --git a/Documentation/devicetree/bindings/usb/brcm,bdc.txt b/Documentation/devicetree/bindings/usb/brcm,bdc.txt new file mode 100644 index 000000000000..63e63af3bf59 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/brcm,bdc.txt @@ -0,0 +1,29 @@ +Broadcom USB Device Controller (BDC) +==================================== + +Required properties: + +- compatible: must be one of: + "brcm,bdc-v0.16" + "brcm,bdc" +- reg: the base register address and length +- interrupts: the interrupt line for this controller + +Optional properties: + +On Broadcom STB platforms, these properties are required: + +- phys: phandle to one or two USB PHY blocks + NOTE: Some SoC's have a single phy and some have + USB 2.0 and USB 3.0 phys +- clocks: phandle to the functional clock of this block + +Example: + + bdc@f0b02000 { + compatible = "brcm,bdc-v0.16"; + reg = <0xf0b02000 0xfc4>; + interrupts = <0x0 0x60 0x0>; + phys = <&usbphy_0 0x0>; + clocks = <&sw_usbd>; + }; From c87dca047849b0fd75c48a7e0375afb93047446c Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:42 -0400 Subject: [PATCH 35/49] usb: bdc: Add clock enable for new chips with a separate BDC clock Newer SoC's have added a BDC clock to the Device Tree, so get and enable it. Signed-off-by: Al Cooper Signed-off-by: Florian Fainelli Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc_core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index e9bd8d4abca0..dda7b438ada8 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "bdc.h" #include "bdc_dbg.h" @@ -452,8 +453,22 @@ static int bdc_probe(struct platform_device *pdev) int irq; u32 temp; struct device *dev = &pdev->dev; + struct clk *clk; dev_dbg(dev, "%s()\n", __func__); + + clk = devm_clk_get(dev, "sw_usbd"); + if (IS_ERR(clk)) { + dev_info(dev, "Clock not found in Device Tree\n"); + clk = NULL; + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "could not enable clock\n"); + return ret; + } + bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL); if (!bdc) return -ENOMEM; From 10fbb06f4251fb464acb3a94943da051ff5cb3d3 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:43 -0400 Subject: [PATCH 36/49] usb: bdc: Small code cleanup Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc_core.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index dda7b438ada8..c2bfae2347c3 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -488,28 +488,29 @@ static int bdc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bdc); bdc->irq = irq; bdc->dev = dev; - dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); + dev_dbg(dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); temp = bdc_readl(bdc->regs, BDC_BDCCAP1); if ((temp & BDC_P64) && !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { - dev_dbg(bdc->dev, "Using 64-bit address\n"); + dev_dbg(dev, "Using 64-bit address\n"); } else { - ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) { - dev_err(bdc->dev, "No suitable DMA config available, abort\n"); + dev_err(dev, + "No suitable DMA config available, abort\n"); return -ENOTSUPP; } - dev_dbg(bdc->dev, "Using 32-bit address\n"); + dev_dbg(dev, "Using 32-bit address\n"); } ret = bdc_hw_init(bdc); if (ret) { - dev_err(bdc->dev, "BDC init failure:%d\n", ret); + dev_err(dev, "BDC init failure:%d\n", ret); return ret; } ret = bdc_udc_init(bdc); if (ret) { - dev_err(bdc->dev, "BDC Gadget init failure:%d\n", ret); + dev_err(dev, "BDC Gadget init failure:%d\n", ret); goto cleanup; } return 0; From 8ac1685bf911f70aea6de67b3db5674c3ea112f1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 19 Jul 2017 15:11:44 -0400 Subject: [PATCH 37/49] usb: bdc: hook a quick Device Tree compatible string Allows Device Tree probing Signed-off-by: Florian Fainelli Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc.h | 4 ++-- drivers/usb/gadget/udc/bdc/bdc_core.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index 36648087b54a..f657a4e81d05 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -27,8 +27,8 @@ #include #include -#define BRCM_BDC_NAME "bdc_usb3" -#define BRCM_BDC_DESC "BDC device controller driver" +#define BRCM_BDC_NAME "bdc" +#define BRCM_BDC_DESC "Broadcom USB Device Controller driver" #define DMA_ADDR_INVALID (~(dma_addr_t)0) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index c2bfae2347c3..bc0729b84948 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -533,9 +533,17 @@ static int bdc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id bdc_of_match[] = { + { .compatible = "brcm,bdc-v0.16" }, + { .compatible = "brcm,bdc" }, + { /* sentinel */ } +}; + static struct platform_driver bdc_driver = { .driver = { .name = BRCM_BDC_NAME, + .owner = THIS_MODULE, + .of_match_table = bdc_of_match, }, .probe = bdc_probe, .remove = bdc_remove, From 0de9742514a05e5d9a06479bd98b9f894f85328e Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:45 -0400 Subject: [PATCH 38/49] usb: bdc: Add support for suspend/resume Based on a previous commit by Danesh Petigara that added resume to solve the following problem: "The BDC driver will fail after resuming from S3 suspend and this will cause any upper layer gadget driver to fail." This commit also adds support for suspend and manages the clock during suspend/resume. Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc.h | 1 + drivers/usb/gadget/udc/bdc/bdc_core.c | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index f657a4e81d05..67c5f23a2720 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -454,6 +454,7 @@ struct bdc { * Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4 */ struct delayed_work func_wake_notify; + struct clk *clk; }; static inline u32 bdc_readl(void __iomem *base, u32 offset) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index bc0729b84948..2690b6fc4f6f 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -473,6 +473,8 @@ static int bdc_probe(struct platform_device *pdev) if (!bdc) return -ENOMEM; + bdc->clk = clk; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bdc->regs = devm_ioremap_resource(dev, res); if (IS_ERR(bdc->regs)) { @@ -529,10 +531,43 @@ static int bdc_remove(struct platform_device *pdev) dev_dbg(bdc->dev, "%s ()\n", __func__); bdc_udc_exit(bdc); bdc_hw_exit(bdc); + clk_disable_unprepare(bdc->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bdc_suspend(struct device *dev) +{ + struct bdc *bdc = dev_get_drvdata(dev); + + clk_disable_unprepare(bdc->clk); + return 0; +} + +static int bdc_resume(struct device *dev) +{ + struct bdc *bdc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(bdc->clk); + if (ret) { + dev_err(bdc->dev, "err enabling the clock\n"); + return ret; + } + ret = bdc_reinit(bdc); + if (ret) { + dev_err(bdc->dev, "err in bdc reinit\n"); + return ret; + } return 0; } +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend, + bdc_resume); + static const struct of_device_id bdc_of_match[] = { { .compatible = "brcm,bdc-v0.16" }, { .compatible = "brcm,bdc" }, @@ -543,6 +578,7 @@ static struct platform_driver bdc_driver = { .driver = { .name = BRCM_BDC_NAME, .owner = THIS_MODULE, + .pm = &bdc_pm_ops, .of_match_table = bdc_of_match, }, .probe = bdc_probe, From cff97f3353b6bae09c8c5419f4294fb7fdecd656 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:46 -0400 Subject: [PATCH 39/49] usb: bdc: fix "xsf for ep not enabled" errror This patch essentially clears the port status change bits at the correct times. It is necessary because the driver was not handling the change bits correctly for events during device connection/disconnection and bus enumeration. So, one of them (PCC) was left stuck sometimes causing the "xsf for ep not enabled" error we get on first connection. This was found by the Android team. This was debugged and fixed by Sasi Kumar. Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc_udc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c index aae7458d8986..c84346146456 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_udc.c +++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c @@ -249,6 +249,7 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport) disconn = true; else if ((uspc & BDC_PCS) && !BDC_PST(uspc)) connected = true; + clear_flags |= BDC_PCC; } /* Change in VBus and VBus is present */ @@ -259,16 +260,16 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport) bdc_softconn(bdc); usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED); } - clear_flags = BDC_VBC; + clear_flags |= BDC_VBC; } else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) { /* Hot reset, warm reset, 2.0 bus reset or disconn */ dev_dbg(bdc->dev, "Port reset or disconn\n"); bdc_uspc_disconnected(bdc, disconn); - clear_flags = BDC_PCC|BDC_PCS|BDC_PRS|BDC_PRC; + clear_flags |= BDC_PRC; } else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) { /* Change in Link state */ handle_link_state_change(bdc, uspc); - clear_flags = BDC_PSC|BDC_PCS; + clear_flags |= BDC_PSC; } /* From 3f8b12194224992bf4b64ea00bd74e1b0a45835c Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:47 -0400 Subject: [PATCH 40/49] usb: bdc: Enable in Kconfig for ARCH_BRCMSTB systems Many ARM based Broadcom STB SoC's have a USB BDC controller so enable this driver for these systems. Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig index eb8b55392360..c74ac25dddcd 100644 --- a/drivers/usb/gadget/udc/bdc/Kconfig +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -1,6 +1,7 @@ config USB_BDC_UDC tristate "Broadcom USB3.0 device controller IP driver(BDC)" depends on USB_GADGET && HAS_DMA + default ARCH_BRCMSTB help BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP From cc29d4f67757f2bce7fca1a0eab8e40d748b0ead Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 19 Jul 2017 15:11:48 -0400 Subject: [PATCH 41/49] usb: bdc: Add support for USB phy If a phy is specified in the device tree node, get it and use it. This was based on a patch by: "Srinath Mannam " Signed-off-by: Al Cooper Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc.h | 3 ++ drivers/usb/gadget/udc/bdc/bdc_core.c | 74 ++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index 67c5f23a2720..6df0352cdc50 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -413,6 +413,9 @@ struct bdc { /* device lock */ spinlock_t lock; + /* generic phy */ + struct phy **phys; + int num_phys; /* num of endpoints for a particular instantiation of IP */ unsigned int num_eps; /* diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 2690b6fc4f6f..7a8af4b916cf 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +446,43 @@ static int bdc_hw_init(struct bdc *bdc) return 0; } +static int bdc_phy_init(struct bdc *bdc) +{ + int phy_num; + int ret; + + for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { + ret = phy_init(bdc->phys[phy_num]); + if (ret) + goto err_exit_phy; + ret = phy_power_on(bdc->phys[phy_num]); + if (ret) { + phy_exit(bdc->phys[phy_num]); + goto err_exit_phy; + } + } + + return 0; + +err_exit_phy: + while (--phy_num >= 0) { + phy_power_off(bdc->phys[phy_num]); + phy_exit(bdc->phys[phy_num]); + } + + return ret; +} + +static void bdc_phy_exit(struct bdc *bdc) +{ + int phy_num; + + for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { + phy_power_off(bdc->phys[phy_num]); + phy_exit(bdc->phys[phy_num]); + } +} + static int bdc_probe(struct platform_device *pdev) { struct bdc *bdc; @@ -454,6 +492,7 @@ static int bdc_probe(struct platform_device *pdev) u32 temp; struct device *dev = &pdev->dev; struct clk *clk; + int phy_num; dev_dbg(dev, "%s()\n", __func__); @@ -492,6 +531,35 @@ static int bdc_probe(struct platform_device *pdev) bdc->dev = dev; dev_dbg(dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); + bdc->num_phys = of_count_phandle_with_args(dev->of_node, + "phys", "#phy-cells"); + if (bdc->num_phys > 0) { + bdc->phys = devm_kcalloc(dev, bdc->num_phys, + sizeof(struct phy *), GFP_KERNEL); + if (!bdc->phys) + return -ENOMEM; + } else { + bdc->num_phys = 0; + } + dev_info(dev, "Using %d phy(s)\n", bdc->num_phys); + + for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { + bdc->phys[phy_num] = devm_of_phy_get_by_index( + dev, dev->of_node, phy_num); + if (IS_ERR(bdc->phys[phy_num])) { + ret = PTR_ERR(bdc->phys[phy_num]); + dev_err(bdc->dev, + "BDC phy specified but not found:%d\n", ret); + return ret; + } + } + + ret = bdc_phy_init(bdc); + if (ret) { + dev_err(bdc->dev, "BDC phy init failure:%d\n", ret); + return ret; + } + temp = bdc_readl(bdc->regs, BDC_BDCCAP1); if ((temp & BDC_P64) && !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { @@ -508,7 +576,7 @@ static int bdc_probe(struct platform_device *pdev) ret = bdc_hw_init(bdc); if (ret) { dev_err(dev, "BDC init failure:%d\n", ret); - return ret; + goto phycleanup; } ret = bdc_udc_init(bdc); if (ret) { @@ -519,7 +587,8 @@ static int bdc_probe(struct platform_device *pdev) cleanup: bdc_hw_exit(bdc); - +phycleanup: + bdc_phy_exit(bdc); return ret; } @@ -531,6 +600,7 @@ static int bdc_remove(struct platform_device *pdev) dev_dbg(bdc->dev, "%s ()\n", __func__); bdc_udc_exit(bdc); bdc_hw_exit(bdc); + bdc_phy_exit(bdc); clk_disable_unprepare(bdc->clk); return 0; } From cdff9f8ee1688f79351518ef03780bf11b5283be Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Fri, 11 Aug 2017 15:46:08 -0700 Subject: [PATCH 42/49] usb: gadget: f_fs: Pass along set_halt errors. Users can apply i/o in the wrong direction on an endpoint to stall it. In case there is an error that does not allow the endpoint to be stalled, we want the user to know. An operation to stall the endpoint will return EBADMSG if successful, EAGAIN if there are still queued requests, and other errors depending on the underlying implementation. Also remove the conditional since it is always true. Acked-by: Michal Nazarewicz Signed-off-by: Jerry Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d21874b35cf6..9990944a7245 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -961,10 +961,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) /* In the meantime, endpoint got disabled or changed. */ ret = -ESHUTDOWN; } else if (halt) { - /* Halt */ - if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) - usb_ep_set_halt(ep->ep); - ret = -EBADMSG; + ret = usb_ep_set_halt(ep->ep); + if (!ret) + ret = -EBADMSG; } else if (unlikely(data_len == -EINVAL)) { /* * Sanity Check: even though data_len can't be used From 44dd8a989c787e9077745417140aa132bfe45bf5 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 15 Aug 2017 19:07:53 +0800 Subject: [PATCH 43/49] include: uapi: usb: Introduce USB charger type and state definition Introducing USB charger type and state definition can help to support USB charging which will be added in USB phy core. Signed-off-by: Baolin Wang Signed-off-by: Felipe Balbi --- include/uapi/linux/usb/charger.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 include/uapi/linux/usb/charger.h diff --git a/include/uapi/linux/usb/charger.h b/include/uapi/linux/usb/charger.h new file mode 100644 index 000000000000..5f72af35b3ed --- /dev/null +++ b/include/uapi/linux/usb/charger.h @@ -0,0 +1,31 @@ +/* + * This file defines the USB charger type and state that are needed for + * USB device APIs. + */ + +#ifndef _UAPI__LINUX_USB_CHARGER_H +#define _UAPI__LINUX_USB_CHARGER_H + +/* + * USB charger type: + * SDP (Standard Downstream Port) + * DCP (Dedicated Charging Port) + * CDP (Charging Downstream Port) + * ACA (Accessory Charger Adapters) + */ +enum usb_charger_type { + UNKNOWN_TYPE, + SDP_TYPE, + DCP_TYPE, + CDP_TYPE, + ACA_TYPE, +}; + +/* USB charger state */ +enum usb_charger_state { + USB_CHARGER_DEFAULT, + USB_CHARGER_PRESENT, + USB_CHARGER_ABSENT, +}; + +#endif /* _UAPI__LINUX_USB_CHARGER_H */ From a9081a008f84819ab2f3da596bf89afa16beea94 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 15 Aug 2017 19:07:54 +0800 Subject: [PATCH 44/49] usb: phy: Add USB charger support This patch introduces the usb charger support based on usb phy that makes an enhancement to a power driver. The basic conception of the usb charger is that, when one usb charger is added or removed by reporting from the extcon device state change, the usb charger will report to power user to set the current limitation. Power user can register a notifiee on the usb phy by issuing usb_register_notifier() to get notified by charger status changes or charger current changes. we can notify what current to be drawn to power user according to different charger type, and now we have 2 methods to get charger type. One is get charger type from extcon subsystem, which also means the charger state changes. Another is we can get the charger type from USB controller detecting or PMIC detecting, and the charger state changes should be told by issuing usb_phy_set_charger_state(). Signed-off-by: Baolin Wang Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy.c | 272 ++++++++++++++++++++++++++++++++++++++++ include/linux/usb/phy.h | 49 ++++++++ 2 files changed, 321 insertions(+) diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 032f5afaad4b..2dc48bb2553c 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -18,6 +18,18 @@ #include +/* Default current range by charger type. */ +#define DEFAULT_SDP_CUR_MIN 2 +#define DEFAULT_SDP_CUR_MAX 500 +#define DEFAULT_SDP_CUR_MIN_SS 150 +#define DEFAULT_SDP_CUR_MAX_SS 900 +#define DEFAULT_DCP_CUR_MIN 500 +#define DEFAULT_DCP_CUR_MAX 5000 +#define DEFAULT_CDP_CUR_MIN 1500 +#define DEFAULT_CDP_CUR_MAX 5000 +#define DEFAULT_ACA_CUR_MIN 1500 +#define DEFAULT_ACA_CUR_MAX 5000 + static LIST_HEAD(phy_list); static LIST_HEAD(phy_bind_list); static DEFINE_SPINLOCK(phy_lock); @@ -77,6 +89,221 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node) return ERR_PTR(-EPROBE_DEFER); } +static void usb_phy_set_default_current(struct usb_phy *usb_phy) +{ + usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN; + usb_phy->chg_cur.sdp_max = DEFAULT_SDP_CUR_MAX; + usb_phy->chg_cur.dcp_min = DEFAULT_DCP_CUR_MIN; + usb_phy->chg_cur.dcp_max = DEFAULT_DCP_CUR_MAX; + usb_phy->chg_cur.cdp_min = DEFAULT_CDP_CUR_MIN; + usb_phy->chg_cur.cdp_max = DEFAULT_CDP_CUR_MAX; + usb_phy->chg_cur.aca_min = DEFAULT_ACA_CUR_MIN; + usb_phy->chg_cur.aca_max = DEFAULT_ACA_CUR_MAX; +} + +/** + * usb_phy_notify_charger_work - notify the USB charger state + * @work - the charger work to notify the USB charger state + * + * This work can be issued when USB charger state has been changed or + * USB charger current has been changed, then we can notify the current + * what can be drawn to power user and the charger state to userspace. + * + * If we get the charger type from extcon subsystem, we can notify the + * charger state to power user automatically by usb_phy_get_charger_type() + * issuing from extcon subsystem. + * + * If we get the charger type from ->charger_detect() instead of extcon + * subsystem, the usb phy driver should issue usb_phy_set_charger_state() + * to set charger state when the charger state has been changed. + */ +static void usb_phy_notify_charger_work(struct work_struct *work) +{ + struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work); + char uchger_state[50] = { 0 }; + char *envp[] = { uchger_state, NULL }; + unsigned int min, max; + + switch (usb_phy->chg_state) { + case USB_CHARGER_PRESENT: + usb_phy_get_charger_current(usb_phy, &min, &max); + + atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); + snprintf(uchger_state, ARRAY_SIZE(uchger_state), + "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT"); + break; + case USB_CHARGER_ABSENT: + usb_phy_set_default_current(usb_phy); + + atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); + snprintf(uchger_state, ARRAY_SIZE(uchger_state), + "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT"); + break; + default: + dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", + usb_phy->chg_state); + return; + } + + kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp); +} + +static void __usb_phy_get_charger_type(struct usb_phy *usb_phy) +{ + if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_SDP) > 0) { + usb_phy->chg_type = SDP_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_CDP) > 0) { + usb_phy->chg_type = CDP_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_DCP) > 0) { + usb_phy->chg_type = DCP_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_ACA) > 0) { + usb_phy->chg_type = ACA_TYPE; + usb_phy->chg_state = USB_CHARGER_PRESENT; + } else { + usb_phy->chg_type = UNKNOWN_TYPE; + usb_phy->chg_state = USB_CHARGER_ABSENT; + } + + schedule_work(&usb_phy->chg_work); +} + +/** + * usb_phy_get_charger_type - get charger type from extcon subsystem + * @nb -the notifier block to determine charger type + * @state - the cable state + * @data - private data + * + * Determin the charger type from extcon subsystem which also means the + * charger state has been chaned, then we should notify this event. + */ +static int usb_phy_get_charger_type(struct notifier_block *nb, + unsigned long state, void *data) +{ + struct usb_phy *usb_phy = container_of(nb, struct usb_phy, type_nb); + + __usb_phy_get_charger_type(usb_phy); + return NOTIFY_OK; +} + +/** + * usb_phy_set_charger_current - set the USB charger current + * @usb_phy - the USB phy to be used + * @mA - the current need to be set + * + * Usually we only change the charger default current when USB finished the + * enumeration as one SDP charger. As one SDP charger, usb_phy_set_power() + * will issue this function to change charger current when after setting USB + * configuration, or suspend/resume USB. For other type charger, we should + * use the default charger current and we do not suggest to issue this function + * to change the charger current. + * + * When USB charger current has been changed, we need to notify the power users. + */ +void usb_phy_set_charger_current(struct usb_phy *usb_phy, unsigned int mA) +{ + switch (usb_phy->chg_type) { + case SDP_TYPE: + if (usb_phy->chg_cur.sdp_max == mA) + return; + + usb_phy->chg_cur.sdp_max = (mA > DEFAULT_SDP_CUR_MAX_SS) ? + DEFAULT_SDP_CUR_MAX_SS : mA; + break; + case DCP_TYPE: + if (usb_phy->chg_cur.dcp_max == mA) + return; + + usb_phy->chg_cur.dcp_max = (mA > DEFAULT_DCP_CUR_MAX) ? + DEFAULT_DCP_CUR_MAX : mA; + break; + case CDP_TYPE: + if (usb_phy->chg_cur.cdp_max == mA) + return; + + usb_phy->chg_cur.cdp_max = (mA > DEFAULT_CDP_CUR_MAX) ? + DEFAULT_CDP_CUR_MAX : mA; + break; + case ACA_TYPE: + if (usb_phy->chg_cur.aca_max == mA) + return; + + usb_phy->chg_cur.aca_max = (mA > DEFAULT_ACA_CUR_MAX) ? + DEFAULT_ACA_CUR_MAX : mA; + break; + default: + return; + } + + schedule_work(&usb_phy->chg_work); +} +EXPORT_SYMBOL_GPL(usb_phy_set_charger_current); + +/** + * usb_phy_get_charger_current - get the USB charger current + * @usb_phy - the USB phy to be used + * @min - the minimum current + * @max - the maximum current + * + * Usually we will notify the maximum current to power user, but for some + * special case, power user also need the minimum current value. Then the + * power user can issue this function to get the suitable current. + */ +void usb_phy_get_charger_current(struct usb_phy *usb_phy, + unsigned int *min, unsigned int *max) +{ + switch (usb_phy->chg_type) { + case SDP_TYPE: + *min = usb_phy->chg_cur.sdp_min; + *max = usb_phy->chg_cur.sdp_max; + break; + case DCP_TYPE: + *min = usb_phy->chg_cur.dcp_min; + *max = usb_phy->chg_cur.dcp_max; + break; + case CDP_TYPE: + *min = usb_phy->chg_cur.cdp_min; + *max = usb_phy->chg_cur.cdp_max; + break; + case ACA_TYPE: + *min = usb_phy->chg_cur.aca_min; + *max = usb_phy->chg_cur.aca_max; + break; + default: + *min = 0; + *max = 0; + break; + } +} +EXPORT_SYMBOL_GPL(usb_phy_get_charger_current); + +/** + * usb_phy_set_charger_state - set the USB charger state + * @usb_phy - the USB phy to be used + * @state - the new state need to be set for charger + * + * The usb phy driver can issue this function when the usb phy driver + * detected the charger state has been changed, in this case the charger + * type should be get from ->charger_detect(). + */ +void usb_phy_set_charger_state(struct usb_phy *usb_phy, + enum usb_charger_state state) +{ + if (usb_phy->chg_state == state || !usb_phy->charger_detect) + return; + + usb_phy->chg_state = state; + if (usb_phy->chg_state == USB_CHARGER_PRESENT) + usb_phy->chg_type = usb_phy->charger_detect(usb_phy); + else + usb_phy->chg_type = UNKNOWN_TYPE; + + schedule_work(&usb_phy->chg_work); +} +EXPORT_SYMBOL_GPL(usb_phy_set_charger_state); + static void devm_usb_phy_release(struct device *dev, void *res) { struct usb_phy *phy = *(struct usb_phy **)res; @@ -124,6 +351,44 @@ static int usb_add_extcon(struct usb_phy *x) "register VBUS notifier failed\n"); return ret; } + } else { + x->type_nb.notifier_call = usb_phy_get_charger_type; + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_SDP, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB SDP failed.\n"); + return ret; + } + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_CDP, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB CDP failed.\n"); + return ret; + } + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_DCP, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB DCP failed.\n"); + return ret; + } + + ret = devm_extcon_register_notifier(x->dev, x->edev, + EXTCON_CHG_USB_ACA, + &x->type_nb); + if (ret) { + dev_err(x->dev, + "register extcon USB ACA failed.\n"); + return ret; + } } if (x->id_nb.notifier_call) { @@ -145,6 +410,13 @@ static int usb_add_extcon(struct usb_phy *x) } } + usb_phy_set_default_current(x); + INIT_WORK(&x->chg_work, usb_phy_notify_charger_work); + x->chg_type = UNKNOWN_TYPE; + x->chg_state = USB_CHARGER_DEFAULT; + if (x->type_nb.notifier_call) + __usb_phy_get_charger_type(x); + return 0; } diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 299245105610..de881b171ba9 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -12,6 +12,7 @@ #include #include #include +#include enum usb_phy_interface { USBPHY_INTERFACE_MODE_UNKNOWN, @@ -72,6 +73,17 @@ struct usb_phy_io_ops { int (*write)(struct usb_phy *x, u32 val, u32 reg); }; +struct usb_charger_current { + unsigned int sdp_min; + unsigned int sdp_max; + unsigned int dcp_min; + unsigned int dcp_max; + unsigned int cdp_min; + unsigned int cdp_max; + unsigned int aca_min; + unsigned int aca_max; +}; + struct usb_phy { struct device *dev; const char *label; @@ -91,6 +103,13 @@ struct usb_phy { struct extcon_dev *id_edev; struct notifier_block vbus_nb; struct notifier_block id_nb; + struct notifier_block type_nb; + + /* Support USB charger */ + enum usb_charger_type chg_type; + enum usb_charger_state chg_state; + struct usb_charger_current chg_cur; + struct work_struct chg_work; /* for notification of usb_phy_events */ struct atomic_notifier_head notifier; @@ -129,6 +148,12 @@ struct usb_phy { enum usb_device_speed speed); int (*notify_disconnect)(struct usb_phy *x, enum usb_device_speed speed); + + /* + * Charger detection method can be implemented if you need to + * manually detect the charger type. + */ + enum usb_charger_type (*charger_detect)(struct usb_phy *x); }; /** @@ -219,6 +244,12 @@ extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern int usb_bind_phy(const char *dev_name, u8 index, const char *phy_dev_name); extern void usb_phy_set_event(struct usb_phy *x, unsigned long event); +extern void usb_phy_set_charger_current(struct usb_phy *usb_phy, + unsigned int mA); +extern void usb_phy_get_charger_current(struct usb_phy *usb_phy, + unsigned int *min, unsigned int *max); +extern void usb_phy_set_charger_state(struct usb_phy *usb_phy, + enum usb_charger_state state); #else static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) { @@ -270,11 +301,29 @@ static inline int usb_bind_phy(const char *dev_name, u8 index, static inline void usb_phy_set_event(struct usb_phy *x, unsigned long event) { } + +static inline void usb_phy_set_charger_current(struct usb_phy *usb_phy, + unsigned int mA) +{ +} + +static inline void usb_phy_get_charger_current(struct usb_phy *usb_phy, + unsigned int *min, + unsigned int *max) +{ +} + +static inline void usb_phy_set_charger_state(struct usb_phy *usb_phy, + enum usb_charger_state state) +{ +} #endif static inline int usb_phy_set_power(struct usb_phy *x, unsigned mA) { + usb_phy_set_charger_current(x, mA); + if (x && x->set_power) return x->set_power(x, mA); return 0; From 626b6cd5f52e83f208e3fb6d499bde4d6134e39d Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 15 Aug 2017 19:07:55 +0800 Subject: [PATCH 45/49] power: wm831x_power: Support USB charger current limit management Integrate with the newly added USB charger interface to limit the current we draw from the USB input based on the input device configuration identified by the USB stack, allowing us to charge more quickly from high current inputs without drawing more current than specified from others. Signed-off-by: Mark Brown Signed-off-by: Baolin Wang Acked-by: Lee Jones Acked-by: Charles Keepax Acked-by: Sebastian Reichel Signed-off-by: Felipe Balbi --- .../devicetree/bindings/mfd/wm831x.txt | 1 + drivers/power/supply/wm831x_power.c | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/wm831x.txt b/Documentation/devicetree/bindings/mfd/wm831x.txt index 9f8b7430673c..505709403d3f 100644 --- a/Documentation/devicetree/bindings/mfd/wm831x.txt +++ b/Documentation/devicetree/bindings/mfd/wm831x.txt @@ -31,6 +31,7 @@ Required properties: ../interrupt-controller/interrupts.txt Optional sub-nodes: + - phys : Contains a phandle to the USB PHY. - regulators : Contains sub-nodes for each of the regulators supplied by the device. The regulators are bound using their names listed below: diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index 7082301da945..927050d4444d 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,8 @@ struct wm831x_power { char usb_name[20]; char battery_name[20]; bool have_battery; + struct usb_phy *usb_phy; + struct notifier_block usb_notify; }; static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, }; +/* In milliamps */ +static const unsigned int wm831x_usb_limits[] = { + 0, + 2, + 100, + 500, + 900, + 1500, + 1800, + 550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, + unsigned long limit, void *data) +{ + struct wm831x_power *wm831x_power = container_of(nb, + struct wm831x_power, + usb_notify); + unsigned int i, best; + + /* Find the highest supported limit */ + best = 0; + for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { + if (limit >= wm831x_usb_limits[i] && + wm831x_usb_limits[best] < wm831x_usb_limits[i]) + best = i; + } + + dev_dbg(wm831x_power->wm831x->dev, + "Limiting USB current to %umA", wm831x_usb_limits[best]); + + wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, + WM831X_USB_ILIM_MASK, best); + + return 0; +} + /********************************************************************* * Battery properties *********************************************************************/ @@ -607,6 +647,33 @@ static int wm831x_power_probe(struct platform_device *pdev) } } + power->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0); + ret = PTR_ERR_OR_ZERO(power->usb_phy); + + switch (ret) { + case 0: + power->usb_notify.notifier_call = wm831x_usb_limit_change; + ret = usb_register_notifier(power->usb_phy, &power->usb_notify); + if (ret) { + dev_err(&pdev->dev, "Failed to register notifier: %d\n", + ret); + goto err_bat_irq; + } + break; + case -EINVAL: + case -ENODEV: + /* ignore missing usb-phy, it's optional */ + power->usb_phy = NULL; + ret = 0; + break; + default: + dev_err(&pdev->dev, "Failed to find USB phy: %d\n", ret); + /* fall-through */ + case -EPROBE_DEFER: + goto err_bat_irq; + break; + } + return ret; err_bat_irq: @@ -637,6 +704,11 @@ static int wm831x_power_remove(struct platform_device *pdev) struct wm831x *wm831x = wm831x_power->wm831x; int irq, i; + if (wm831x_power->usb_phy) { + usb_unregister_notifier(wm831x_power->usb_phy, + &wm831x_power->usb_notify); + } + for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) { irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, From c37a9cd51dfa85ee59427c51b49dee74cec124c5 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Wed, 16 Aug 2017 16:54:08 -0500 Subject: [PATCH 46/49] dt-bindings: usb: keystone-usb: Update bindings pm and clocks properties Update various properties to properly indicate their requirement depending on the SoC. Signed-off-by: Franklin S Cooper Jr Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/keystone-usb.txt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/keystone-usb.txt b/Documentation/devicetree/bindings/usb/keystone-usb.txt index 60527d335b58..2d1bef16f149 100644 --- a/Documentation/devicetree/bindings/usb/keystone-usb.txt +++ b/Documentation/devicetree/bindings/usb/keystone-usb.txt @@ -12,8 +12,21 @@ Required properties: MPU. - ranges: allows valid 1:1 translation between child's address space and parent's address space. - - clocks: Clock IDs array as required by the controller. - - clock-names: names of clocks correseponding to IDs in the clock property. + +SoC-specific Required Properties: +The following are mandatory properties for Keystone 2 66AK2HK, 66AK2L and 66AK2E +SoCs only: + +- clocks: Clock ID for USB functional clock. +- clock-names: Must be "usb". + + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the USB device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt Sub-nodes: The dwc3 core should be added as subnode to Keystone DWC3 glue. From afd7fd81f22bf90474216515dbd6088f9bd70343 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Aug 2017 14:49:55 -0400 Subject: [PATCH 47/49] USB: Gadget core: fix inconsistency in the interface tousb_add_gadget_udc_release() The usb_add_gadget_udc_release() routine in the USB gadget core will sometimes but not always call the gadget's release function when an error occurs. More specifically, if the struct usb_udc allocation fails then the release function is not called, and for other errors it is. As a result, users of this routine cannot know whether they need to deallocate the memory containing the gadget structure following an error. This leads to unavoidable memory leaks or double frees. This patch fixes the problem by splitting the existing device_register() call into device_initialize() and device_add(), and doing the udc allocation in between. That way, even if the allocation fails it is still possible to call device_del(), and so the release function will be always called following an error. Signed-off-by: Alan Stern Reported-by: Alexey Khoroshilov Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/core.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index c1cef6a11ecb..75c51ca4ee0f 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1133,6 +1133,7 @@ static int check_pending_gadget_drivers(struct usb_udc *udc) * @release: a gadget release function. * * Returns zero on success, negative errno otherwise. + * Calls the gadget release function in the latter case. */ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) @@ -1140,10 +1141,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, struct usb_udc *udc; int ret = -ENOMEM; - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - goto err1; - dev_set_name(&gadget->dev, "gadget"); INIT_WORK(&gadget->work, usb_gadget_state_work); gadget->dev.parent = parent; @@ -1153,7 +1150,13 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, else gadget->dev.release = usb_udc_nop_release; - ret = device_register(&gadget->dev); + device_initialize(&gadget->dev); + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto err1; + + ret = device_add(&gadget->dev); if (ret) goto err2; @@ -1200,10 +1203,10 @@ err3: device_del(&gadget->dev); err2: - put_device(&gadget->dev); kfree(udc); err1: + put_device(&gadget->dev); return ret; } EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); From daa35bd95634a2a2d72d1049c93576a02711cb1a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 16 Aug 2017 14:30:10 -0600 Subject: [PATCH 48/49] usb: gadget: serial: fix oops when data rx'd after close When the gadget serial device has no associated TTY, do not pass any received data into the TTY layer for processing; simply drop it instead. This prevents the TTY layer from calling back into the gadget serial driver, which will then crash in e.g. gs_write_room() due to lack of gadget serial device to TTY association (i.e. a NULL pointer dereference). Signed-off-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 9b0805f55ad7..4176216d54be 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -537,7 +537,7 @@ static void gs_rx_push(unsigned long _port) } /* push data to (open) tty */ - if (req->actual) { + if (req->actual && tty) { char *packet = req->buf; unsigned size = req->actual; unsigned n; From 0852659ef071ccd84e85e37195e7c2f3e7c64d1f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 16 Aug 2017 13:32:38 +0300 Subject: [PATCH 49/49] usb: gadget: f_ncm/u_ether: Move 'SKB reserve' quirk setup to u_ether That quirk is required to make USB Ethernet gadget working on HW that can't cope with unaligned DMA. For some reason only f_ncm sets up that quirk, let's setup it directly in u_ether so other network models would have that quirk applied as well. All network models have been tested with ChipIdea UDC driver on NVIDIA Tegra20 SoC that require DMA to be aligned. Signed-off-by: Dmitry Osipenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_ncm.c | 2 -- drivers/usb/gadget/function/u_ether.c | 2 +- drivers/usb/gadget/function/u_ether.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 24e34cfcb4bd..45b334ceaf2e 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -925,8 +925,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) */ ncm->port.is_zlp_ok = gadget_is_zlp_supported(cdev->gadget); - ncm->port.no_skb_reserve = - gadget_avoids_skb_reserve(cdev->gadget); ncm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ncm\n"); net = gether_connect(&ncm->port); diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index a8b40d07e927..bdbc3fdc7c4f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1073,7 +1073,7 @@ struct net_device *gether_connect(struct gether *link) if (result == 0) { dev->zlp = link->is_zlp_ok; - dev->no_skb_reserve = link->no_skb_reserve; + dev->no_skb_reserve = gadget_avoids_skb_reserve(dev->gadget); DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult)); dev->header_len = link->header_len; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 81d94a7ae4b4..c77145bd6b5b 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -64,7 +64,6 @@ struct gether { struct usb_ep *out_ep; bool is_zlp_ok; - bool no_skb_reserve; u16 cdc_filter;