]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/usb/dwc3/core.c
Merge remote-tracking branch 'usb/usb-next'
[karo-tx-linux.git] / drivers / usb / dwc3 / core.c
index 358375e0b291098d8be40d65bdfbbff7f97f0826..474162e9d01d2e03bfaf52402a8cfc1b4461c304 100644 (file)
@@ -6,34 +6,17 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *         Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
 
-#include <linux/usb/otg.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
 
+#include "platform_data.h"
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
 #include "debug.h"
 
-static char *maximum_speed = "super";
-module_param(maximum_speed, charp, 0);
-MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
-
 /* -------------------------------------------------------------------------- */
 
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@@ -236,7 +217,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
                dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
                                upper_32_bits(evt->dma));
                dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
-                               evt->length & 0xffff);
+                               DWC3_GEVNTSIZ_SIZE(evt->length));
                dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
        }
 
@@ -255,7 +236,8 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 
                dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
                dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
-               dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+               dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
+                               | DWC3_GEVNTSIZ_SIZE(0));
                dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
        }
 }
@@ -367,18 +349,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 
 static int dwc3_probe(struct platform_device *pdev)
 {
-       struct device_node      *node = pdev->dev.of_node;
+       struct device           *dev = &pdev->dev;
+       struct dwc3_platform_data *pdata = dev_get_platdata(dev);
+       struct device_node      *node = dev->of_node;
        struct resource         *res;
        struct dwc3             *dwc;
-       struct device           *dev = &pdev->dev;
 
        int                     ret = -ENOMEM;
 
        void __iomem            *regs;
        void                    *mem;
 
-       u8                      mode;
-
        mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
        if (!mem) {
                dev_err(dev, "not enough memory\n");
@@ -402,38 +383,32 @@ static int dwc3_probe(struct platform_device *pdev)
                dev_err(dev, "missing memory resource\n");
                return -ENODEV;
        }
-       dwc->xhci_resources[0].start = res->start;
-       dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
-                                       DWC3_XHCI_REGS_END;
-       dwc->xhci_resources[0].flags = res->flags;
-       dwc->xhci_resources[0].name = res->name;
-
-        /*
-         * Request memory region but exclude xHCI regs,
-         * since it will be requested by the xhci-plat driver.
-         */
-       res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
-                       resource_size(res) - DWC3_GLOBALS_REGS_START,
-                       dev_name(dev));
-       if (!res) {
-               dev_err(dev, "can't request mem region\n");
-               return -ENOMEM;
-       }
-
-       regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (!regs) {
-               dev_err(dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
 
        if (node) {
+               dwc->maximum_speed = of_usb_get_maximum_speed(node);
+
                dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
                dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+
+               dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+               dwc->dr_mode = of_usb_get_dr_mode(node);
+       } else if (pdata) {
+               dwc->maximum_speed = pdata->maximum_speed;
+
+               dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+               dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+
+               dwc->needs_fifo_resize = pdata->tx_fifo_resize;
+               dwc->dr_mode = pdata->dr_mode;
        } else {
                dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
                dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
        }
 
+       /* default to superspeed if no maximum_speed passed */
+       if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
+               dwc->maximum_speed = USB_SPEED_SUPER;
+
        if (IS_ERR(dwc->usb2_phy)) {
                ret = PTR_ERR(dwc->usb2_phy);
 
@@ -464,6 +439,22 @@ static int dwc3_probe(struct platform_device *pdev)
                return -EPROBE_DEFER;
        }
 
+       dwc->xhci_resources[0].start = res->start;
+       dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+                                       DWC3_XHCI_REGS_END;
+       dwc->xhci_resources[0].flags = res->flags;
+       dwc->xhci_resources[0].name = res->name;
+
+       res->start += DWC3_GLOBALS_REGS_START;
+
+       /*
+        * Request memory region but exclude xHCI regs,
+        * since it will be requested by the xhci-plat driver.
+        */
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
        usb_phy_set_suspend(dwc->usb2_phy, 0);
        usb_phy_set_suspend(dwc->usb3_phy, 0);
 
@@ -478,19 +469,6 @@ static int dwc3_probe(struct platform_device *pdev)
        dev->dma_parms  = dev->parent->dma_parms;
        dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
 
-       if (!strncmp("super", maximum_speed, 5))
-               dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-       else if (!strncmp("high", maximum_speed, 4))
-               dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
-       else if (!strncmp("full", maximum_speed, 4))
-               dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
-       else if (!strncmp("low", maximum_speed, 3))
-               dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
-       else
-               dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-
-       dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
-
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
        pm_runtime_forbid(dev);
@@ -517,14 +495,15 @@ static int dwc3_probe(struct platform_device *pdev)
        }
 
        if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
-               mode = DWC3_MODE_HOST;
+               dwc->dr_mode = USB_DR_MODE_HOST;
        else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
-               mode = DWC3_MODE_DEVICE;
-       else
-               mode = DWC3_MODE_DRD;
+               dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+               dwc->dr_mode = USB_DR_MODE_OTG;
 
-       switch (mode) {
-       case DWC3_MODE_DEVICE:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
@@ -532,7 +511,7 @@ static int dwc3_probe(struct platform_device *pdev)
                        goto err2;
                }
                break;
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
@@ -540,7 +519,7 @@ static int dwc3_probe(struct platform_device *pdev)
                        goto err2;
                }
                break;
-       case DWC3_MODE_DRD:
+       case USB_DR_MODE_OTG:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
@@ -555,10 +534,9 @@ static int dwc3_probe(struct platform_device *pdev)
                }
                break;
        default:
-               dev_err(dev, "Unsupported mode of operation %d\n", mode);
+               dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
                goto err2;
        }
-       dwc->mode = mode;
 
        ret = dwc3_debugfs_init(dwc);
        if (ret) {
@@ -571,14 +549,14 @@ static int dwc3_probe(struct platform_device *pdev)
        return 0;
 
 err3:
-       switch (mode) {
-       case DWC3_MODE_DEVICE:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
                dwc3_gadget_exit(dwc);
                break;
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
                dwc3_host_exit(dwc);
                break;
-       case DWC3_MODE_DRD:
+       case USB_DR_MODE_OTG:
                dwc3_host_exit(dwc);
                dwc3_gadget_exit(dwc);
                break;
@@ -611,14 +589,14 @@ static int dwc3_remove(struct platform_device *pdev)
 
        dwc3_debugfs_exit(dwc);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
                dwc3_gadget_exit(dwc);
                break;
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
                dwc3_host_exit(dwc);
                break;
-       case DWC3_MODE_DRD:
+       case USB_DR_MODE_OTG:
                dwc3_host_exit(dwc);
                dwc3_gadget_exit(dwc);
                break;
@@ -642,12 +620,12 @@ static int dwc3_prepare(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_prepare(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                dwc3_event_buffers_cleanup(dwc);
                break;
@@ -665,12 +643,12 @@ static void dwc3_complete(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_complete(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                dwc3_event_buffers_setup(dwc);
                break;
@@ -686,12 +664,12 @@ static int dwc3_suspend(struct device *dev)
 
        spin_lock_irqsave(&dwc->lock, flags);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_suspend(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                /* do nothing */
                break;
@@ -719,12 +697,12 @@ static int dwc3_resume(struct device *dev)
 
        dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
 
-       switch (dwc->mode) {
-       case DWC3_MODE_DEVICE:
-       case DWC3_MODE_DRD:
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
                dwc3_gadget_resume(dwc);
                /* FALLTHROUGH */
-       case DWC3_MODE_HOST:
+       case USB_DR_MODE_HOST:
        default:
                /* do nothing */
                break;
@@ -753,6 +731,9 @@ static const struct dev_pm_ops dwc3_dev_pm_ops = {
 
 #ifdef CONFIG_OF
 static const struct of_device_id of_dwc3_match[] = {
+       {
+               .compatible = "snps,dwc3"
+       },
        {
                .compatible = "synopsys,dwc3"
        },
@@ -775,5 +756,5 @@ module_platform_driver(dwc3_driver);
 
 MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");