summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c199
1 files changed, 90 insertions, 109 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c35d49d39b76..474162e9d01d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -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>
@@ -50,20 +33,18 @@
#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);
@@ -450,7 +425,7 @@ static int dwc3_probe(struct platform_device *pdev)
}
if (IS_ERR(dwc->usb3_phy)) {
- ret = PTR_ERR(dwc->usb2_phy);
+ ret = PTR_ERR(dwc->usb3_phy);
/*
* if -ENXIO is returned, it means PHY layer wasn't
@@ -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;
@@ -754,6 +732,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");