* [PATCH v3 0/9] usb: dwc3: add dual-role support
@ 2015-07-08 10:31 Roger Quadros
2015-07-08 10:31 ` [PATCH v3 1/9] " Roger Quadros
` (8 more replies)
0 siblings, 9 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:31 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
Hi,
Adds dual role support to dwc3 controller driver.
Series depends on [1] for core OTG/dual-role support.
Patches are based on v4.2-rc1.
Tested on am437x-gp-evm and dra7-evm after platform related patches are
applied. Those are sent seprately.
You will also need the fixes mentioned in [2]
[1] core OTG/DRD support - http://thread.gmane.org/gmane.linux.kernel/1991413
[2] fixes needed for dwc3 to work on dra7
- https://patchwork.kernel.org/patch/6732611/
- https://patchwork.kernel.org/patch/6725291/
- http://article.gmane.org/gmane.linux.usb.general/127693
cheers,
-roger
Felipe Balbi (1):
usb: dwc3: core: Adapt to named interrupts
George Cherian (1):
usb: dwc3: dwc3-omap: Make the wrapper interrupt shared
Roger Quadros (7):
usb: dwc3: add dual-role support
usb: dwc3: core.h: add some register definitions
usb: dwc3: core: make dual-role work with OTG irq
usb: dwc3: save/restore OTG registers during suspend/resume
usb: dwc3: gadget: Fix suspend/resume during dual-role mode
usb: dwc3: core: Prevent otg events from disabling themselves
usb: dwc3: core: don't break during suspend/resume while we're
dual-role
drivers/usb/dwc3/core.c | 409 +++++++++++++++++++++++++++++++++++++--
drivers/usb/dwc3/core.h | 113 +++++++++++
drivers/usb/dwc3/dwc3-omap.c | 4 +-
drivers/usb/dwc3/gadget.c | 8 +-
drivers/usb/dwc3/platform_data.h | 1 +
5 files changed, 513 insertions(+), 22 deletions(-)
--
2.1.4
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/9] usb: dwc3: add dual-role support
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
@ 2015-07-08 10:31 ` Roger Quadros
2015-07-08 10:31 ` [PATCH v3 2/9] usb: dwc3: core.h: add some register definitions Roger Quadros
` (7 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:31 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
Register with the USB OTG core. Since we don't support
OTG yet we just work as a dual-role device even
if device tree says "otg".
Use extcon framework to get VBUS/ID cable events and
kick the OTG state machine.
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.c | 155 ++++++++++++++++++++++++++++++++++++++-
drivers/usb/dwc3/core.h | 6 ++
drivers/usb/dwc3/platform_data.h | 1 +
3 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index ff5773c..a7498e0 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -706,6 +706,133 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
return 0;
}
+/* --------------------- Dual-Role management ------------------------------- */
+
+static void dwc3_drd_fsm_sync(struct dwc3 *dwc)
+{
+ int id, vbus;
+
+ /* get ID */
+ id = extcon_get_cable_state(dwc->edev, "USB-HOST");
+ /* Host means ID == 0 */
+ id = !id;
+
+ /* get VBUS */
+ vbus = extcon_get_cable_state(dwc->edev, "USB");
+ dev_dbg(dwc->dev, "id %d vbus %d\n", id, vbus);
+
+ dwc->fsm->id = id;
+ dwc->fsm->vbus = vbus;
+ usb_otg_sync_inputs(dwc->fsm);
+}
+
+static int dwc3_drd_start_host(struct otg_fsm *fsm, int on)
+{
+ struct device *dev = usb_otg_fsm_to_dev(fsm);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+
+ dev_dbg(dwc->dev, "%s: %d\n", __func__, on);
+ if (on)
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+
+ return 0;
+}
+
+static int dwc3_drd_start_gadget(struct otg_fsm *fsm, int on)
+{
+ struct device *dev = usb_otg_fsm_to_dev(fsm);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+
+ dev_dbg(dwc->dev, "%s: %d\n", __func__, on);
+ if (on) {
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ dwc3_event_buffers_setup(dwc);
+ }
+
+ return 0;
+}
+
+static struct otg_fsm_ops dwc3_drd_ops = {
+ .start_host = dwc3_drd_start_host,
+ .start_gadget = dwc3_drd_start_gadget,
+};
+
+static int dwc3_drd_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3 *dwc = container_of(nb, struct dwc3, otg_nb);
+
+ dwc3_drd_fsm_sync(dwc);
+
+ return NOTIFY_DONE;
+}
+
+static int dwc3_drd_init(struct dwc3 *dwc)
+{
+ int ret, id, vbus;
+
+ if (!dwc->edev) {
+ dev_err(dwc->dev, "No extcon device found for OTG mode\n");
+ return -ENODEV;
+ }
+
+ dwc->otg_nb.notifier_call = dwc3_drd_notifier;
+ ret = extcon_register_notifier(dwc->edev, EXTCON_USB, &dwc->otg_nb);
+ if (ret < 0) {
+ dev_err(dwc->dev, "Couldn't register USB cable notifier\n");
+ return -ENODEV;
+ }
+
+ ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+ &dwc->otg_nb);
+ if (ret < 0) {
+ dev_err(dwc->dev, "Couldn't register USB-HOST cable notifier\n");
+ ret = -ENODEV;
+ goto extcon_fail;
+ }
+
+ /* sanity check id & vbus states */
+ id = extcon_get_cable_state(dwc->edev, "USB-HOST");
+ vbus = extcon_get_cable_state(dwc->edev, "USB");
+ if (id < 0 || vbus < 0) {
+ dev_err(dwc->dev, "Invalid USB cable state. id %d, vbus %d\n",
+ id, vbus);
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ /* register parent as DRD device with OTG core */
+ dwc->fsm = usb_otg_register(dwc->dev, &dwc3_drd_ops, true);
+ if (IS_ERR(dwc->fsm)) {
+ ret = PTR_ERR(dwc->fsm);
+ if (ret == -ENOSYS)
+ dev_err(dwc->dev, "CONFIG_USB_OTG needed for dual-role\n");
+ else
+ dev_err(dwc->dev, "Failed to register with OTG core\n");
+
+ goto fail;
+ }
+
+ dwc3_drd_fsm_sync(dwc);
+
+ return 0;
+fail:
+ extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, &dwc->otg_nb);
+extcon_fail:
+ extcon_unregister_notifier(dwc->edev, EXTCON_USB, &dwc->otg_nb);
+
+ return ret;
+}
+
+static void dwc3_drd_exit(struct dwc3 *dwc)
+{
+ usb_otg_unregister(dwc->dev);
+ extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, &dwc->otg_nb);
+ extcon_unregister_notifier(dwc->edev, EXTCON_USB,&dwc->otg_nb);
+}
+
+/* -------------------------------------------------------------------------- */
+
static int dwc3_core_init_mode(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
@@ -729,13 +856,21 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_OTG:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+ ret = dwc3_drd_init(dwc);
+ if (ret) {
+ dev_err(dev, "limiting to peripheral only\n");
+ dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ goto gadget_init;
+ }
+
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
+gadget_init:
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
@@ -762,6 +897,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
+ dwc3_drd_exit(dwc);
break;
default:
/* do nothing */
@@ -845,6 +981,16 @@ static int dwc3_probe(struct platform_device *pdev)
hird_threshold = 12;
if (node) {
+ if (of_property_read_bool(node, "extcon"))
+ dwc->edev = extcon_get_edev_by_phandle(dev, 0);
+ else if (of_property_read_bool(dev->parent->of_node, "extcon"))
+ dwc->edev = extcon_get_edev_by_phandle(dev->parent, 0);
+
+ if (IS_ERR(dwc->edev)) {
+ dev_vdbg(dev, "couldn't get extcon device\n");
+ return -EPROBE_DEFER;
+ }
+
dwc->maximum_speed = of_usb_get_maximum_speed(node);
dwc->has_lpm_erratum = of_property_read_bool(node,
"snps,has-lpm-erratum");
@@ -889,6 +1035,13 @@ static int dwc3_probe(struct platform_device *pdev)
of_property_read_string(node, "snps,hsphy_interface",
&dwc->hsphy_interface);
} else if (pdata) {
+ if (pdata->extcon) {
+ dwc->edev = extcon_get_extcon_dev(pdata->extcon);
+ if (!dwc->edev) {
+ dev_vdbg(dev, "couldn't get extcon device\n");
+ return -EPROBE_DEFER;
+ }
+ }
dwc->maximum_speed = pdata->maximum_speed;
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
if (pdata->lpm_nyet_threshold)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 0447788..d0fda04 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -31,8 +31,10 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/ulpi/interface.h>
+#include <linux/usb/otg-fsm.h>
#include <linux/phy/phy.h>
+#include <linux/extcon.h>
#define DWC3_MSG_MAX 500
@@ -753,6 +755,10 @@ struct dwc3 {
struct ulpi *ulpi;
+ struct extcon_dev *edev; /* USB cable events ID & VBUS */
+ struct notifier_block otg_nb; /* notifier for USB cable events */
+ struct otg_fsm *fsm;
+
void __iomem *regs;
size_t regs_size;
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index d3614ec..b3b245c 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -47,4 +47,5 @@ struct dwc3_platform_data {
unsigned tx_de_emphasis:2;
const char *hsphy_interface;
+ const char *extcon; /* extcon name for USB cable events ID/VBUS */
};
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 2/9] usb: dwc3: core.h: add some register definitions
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
2015-07-08 10:31 ` [PATCH v3 1/9] " Roger Quadros
@ 2015-07-08 10:31 ` Roger Quadros
2015-07-08 10:36 ` [PATCH v3 3/9] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared Roger Quadros
` (6 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:31 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
Add OTG and GHWPARAMS6 register definitions
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index d0fda04..9c1c094 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -173,6 +173,15 @@
#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
+/* Global Status Register */
+#define DWC3_GSTS_OTG_IP (1 << 10)
+#define DWC3_GSTS_BC_IP (1 << 9)
+#define DWC3_GSTS_ADP_IP (1 << 8)
+#define DWC3_GSTS_HOST_IP (1 << 7)
+#define DWC3_GSTS_DEVICE_IP (1 << 6)
+#define DWC3_GSTS_CSR_TIMEOUT (1 << 5)
+#define DWC3_GSTS_BUS_ERR_ADDR_VLD (1 << 4)
+
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
@@ -234,6 +243,11 @@
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_BCSUPPORT (1 << 14)
+#define DWC3_GHWPARAMS6_OTG3SUPPORT (1 << 13)
+#define DWC3_GHWPARAMS6_ADPSUPPORT (1 << 12)
+#define DWC3_GHWPARAMS6_HNPSUPPORT (1 << 11)
+#define DWC3_GHWPARAMS6_SRPSUPPORT (1 << 10)
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
/* Device Configuration Register */
@@ -393,6 +407,74 @@
#define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3
+/* OTG Configuration Register */
+#define DWC3_OCFG_DISPWRCUTTOFF (1 << 5)
+#define DWC3_OCFG_HIBDISMASK (1 << 4)
+#define DWC3_OCFG_SFTRSTMASK (1 << 3)
+#define DWC3_OCFG_OTGVERSION (1 << 2)
+#define DWC3_OCFG_HNPCAP (1 << 1)
+#define DWC3_OCFG_SRPCAP (1 << 0)
+
+/* OTG CTL Register */
+#define DWC3_OCTL_OTG3GOERR (1 << 7)
+#define DWC3_OCTL_PERIMODE (1 << 6)
+#define DWC3_OCTL_PRTPWRCTL (1 << 5)
+#define DWC3_OCTL_HNPREQ (1 << 4)
+#define DWC3_OCTL_SESREQ (1 << 3)
+#define DWC3_OCTL_TERMSELIDPULSE (1 << 2)
+#define DWC3_OCTL_DEVSETHNPEN (1 << 1)
+#define DWC3_OCTL_HSTSETHNPEN (1 << 0)
+
+/* OTG Event Register */
+#define DWC3_OEVT_DEVICEMODE (1 << 31)
+#define DWC3_OEVT_XHCIRUNSTPSET (1 << 27)
+#define DWC3_OEVT_DEVRUNSTPSET (1 << 26)
+#define DWC3_OEVT_HIBENTRY (1 << 25)
+#define DWC3_OEVT_CONIDSTSCHNG (1 << 24)
+#define DWC3_OEVT_HRRCONFNOTIF (1 << 23)
+#define DWC3_OEVT_HRRINITNOTIF (1 << 22)
+#define DWC3_OEVT_ADEVIDLE (1 << 21)
+#define DWC3_OEVT_ADEVBHOSTEND (1 << 20)
+#define DWC3_OEVT_ADEVHOST (1 << 19)
+#define DWC3_OEVT_ADEVHNPCHNG (1 << 18)
+#define DWC3_OEVT_ADEVSRPDET (1 << 17)
+#define DWC3_OEVT_ADEVSESSENDDET (1 << 16)
+#define DWC3_OEVT_BDEVBHOSTEND (1 << 11)
+#define DWC3_OEVT_BDEVHNPCHNG (1 << 10)
+#define DWC3_OEVT_BDEVSESSVLDDET (1 << 9)
+#define DWC3_OEVT_BDEVVBUSCHNG (1 << 8)
+#define DWC3_OEVT_BSESSVLD (1 << 3)
+#define DWC3_OEVT_HSTNEGSTS (1 << 2)
+#define DWC3_OEVT_SESREQSTS (1 << 1)
+#define DWC3_OEVT_ERROR (1 << 0)
+
+/* OTG Event Enable Register */
+#define DWC3_OEVTEN_XHCIRUNSTPSETEN (1 << 27)
+#define DWC3_OEVTEN_DEVRUNSTPSETEN (1 << 26)
+#define DWC3_OEVTEN_HIBENTRYEN (1 << 25)
+#define DWC3_OEVTEN_CONIDSTSCHNGEN (1 << 24)
+#define DWC3_OEVTEN_HRRCONFNOTIFEN (1 << 23)
+#define DWC3_OEVTEN_HRRINITNOTIFEN (1 << 22)
+#define DWC3_OEVTEN_ADEVIDLEEN (1 << 21)
+#define DWC3_OEVTEN_ADEVBHOSTENDEN (1 << 20)
+#define DWC3_OEVTEN_ADEVHOSTEN (1 << 19)
+#define DWC3_OEVTEN_ADEVHNPCHNGEN (1 << 18)
+#define DWC3_OEVTEN_ADEVSRPDETEN (1 << 17)
+#define DWC3_OEVTEN_ADEVSESSENDDETEN (1 << 16)
+#define DWC3_OEVTEN_BDEVHOSTENDEN (1 << 11)
+#define DWC3_OEVTEN_BDEVHNPCHNGEN (1 << 10)
+#define DWC3_OEVTEN_BDEVSESSVLDDETEN (1 << 9)
+#define DWC3_OEVTEN_BDEVVBUSCHNGE (1 << 8)
+
+/* OTG Status Register */
+#define DWC3_OSTS_DEVRUNSTP (1 << 13)
+#define DWC3_OSTS_XHCIRUNSTP (1 << 12)
+#define DWC3_OSTS_PERIPHERALSTATE (1 << 4)
+#define DWC3_OSTS_XHCIPRTPOWER (1 << 3)
+#define DWC3_OSTS_BSESVLD (1 << 2)
+#define DWC3_OSTS_VBUSVLD (1 << 1)
+#define DWC3_OSTS_CONIDSTS (1 << 0)
+
/* Structures */
struct dwc3_trb;
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 3/9] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
2015-07-08 10:31 ` [PATCH v3 1/9] " Roger Quadros
2015-07-08 10:31 ` [PATCH v3 2/9] usb: dwc3: core.h: add some register definitions Roger Quadros
@ 2015-07-08 10:36 ` Roger Quadros
2015-07-08 10:36 ` [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts Roger Quadros
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:36 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
The wrapper interrupt is shared with OTG core so mark it IRQF_SHARED.
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
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 6b486a3..1bc1766 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -542,8 +542,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
- ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
- "dwc3-omap", omap);
+ ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, IRQF_SHARED,
+ "dwc3-omap", omap);
if (ret) {
dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
` (2 preceding siblings ...)
2015-07-08 10:36 ` [PATCH v3 3/9] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared Roger Quadros
@ 2015-07-08 10:36 ` Roger Quadros
2015-07-08 13:06 ` Sergei Shtylyov
2015-07-08 10:36 ` [PATCH v3 5/9] usb: dwc3: core: make dual-role work with OTG irq Roger Quadros
` (4 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:36 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
From: Felipe Balbi <balbi@ti.com>
Add support to use interrupt names,
Following are the interrupt names
Peripheral Interrupt - peripheral
HOST Interrupt - host
OTG Interrupt - otg
[Roger Q]
- If any of these are missing we use the
first available IRQ resource so that we don't
break with older DTBs.
- Use gadget_irq in gadget driver.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.c | 12 ++++++++++++
drivers/usb/dwc3/core.h | 7 +++++++
drivers/usb/dwc3/gadget.c | 2 +-
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a7498e0..7b33d7b 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -941,6 +941,18 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->xhci_resources[1].flags = res->flags;
dwc->xhci_resources[1].name = res->name;
+ dwc->otg_irq = platform_get_irq_byname(pdev, "otg");
+ if (!dwc->otg_irq)
+ dwc->otg_irq = res->start;
+
+ dwc->gadget_irq = platform_get_irq_byname(pdev, "peripheral");
+ if (!dwc->gadget_irq)
+ dwc->gadget_irq = res->start;
+
+ dwc->xhci_irq = platform_get_irq_byname(pdev, "host");
+ if (!dwc->xhci_irq)
+ dwc->xhci_irq = res->start;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 9c1c094..c3431b2 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -742,6 +742,9 @@ struct dwc3_scratchpad_array {
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @dr_mode: requested mode of operation
+ * @xhci_irq: IRQ number for XHCI IRQs
+ * @gadget_irq: IRQ number for Peripheral IRQs
+ * @otg_irq: IRQ number for OTG IRQs
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY
@@ -846,6 +849,10 @@ struct dwc3 {
enum usb_dr_mode dr_mode;
+ int gadget_irq;
+ int xhci_irq;
+ int otg_irq;
+
/* used for suspend/resume */
u32 dcfg;
u32 gctl;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 333a7c0..cf6b945 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1531,7 +1531,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
int irq;
u32 reg;
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ irq = dwc->gadget_irq;
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
IRQF_SHARED, "dwc3", dwc);
if (ret) {
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 5/9] usb: dwc3: core: make dual-role work with OTG irq
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
` (3 preceding siblings ...)
2015-07-08 10:36 ` [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts Roger Quadros
@ 2015-07-08 10:36 ` Roger Quadros
2015-07-08 10:36 ` [PATCH v3 6/9] usb: dwc3: save/restore OTG registers during suspend/resume Roger Quadros
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:36 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
If the ID pin event is not available over extcon
then we rely on the OTG controller to provide us ID and VBUS
information.
We still don't support any OTG features but just
dual-role operation.
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.c | 225 ++++++++++++++++++++++++++++++++++++++++++++----
drivers/usb/dwc3/core.h | 14 +++
2 files changed, 223 insertions(+), 16 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 7b33d7b..138847f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -706,6 +706,63 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
return 0;
}
+/* Get OTG events and sync it to OTG fsm */
+static void dwc3_otg_fsm_sync(struct dwc3 *dwc)
+{
+ u32 reg;
+ int id, vbus;
+
+ reg = dwc3_readl(dwc->regs, DWC3_OSTS);
+ dev_dbg(dwc->dev, "otgstatus 0x%x\n", reg);
+
+ id = !!(reg & DWC3_OSTS_CONIDSTS);
+ vbus = !!(reg & DWC3_OSTS_BSESVLD);
+
+ if (id != dwc->fsm->id || vbus != dwc->fsm->vbus) {
+ dev_dbg(dwc->dev, "id %d vbus %d\n", id, vbus);
+ dwc->fsm->id = id;
+ dwc->fsm->vbus = vbus;
+ usb_otg_sync_inputs(dwc->fsm);
+ }
+}
+
+static irqreturn_t dwc3_otg_thread_irq(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_otg_fsm_sync(dwc);
+ /* unmask interrupts */
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, dwc->oevten);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static irqreturn_t dwc3_otg_irq(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ irqreturn_t ret = IRQ_NONE;
+ u32 reg;
+
+ spin_lock(&dwc->lock);
+
+ reg = dwc3_readl(dwc->regs, DWC3_OEVT);
+ if (reg) {
+ dwc3_writel(dwc->regs, DWC3_OEVT, reg);
+ /* mask interrupts till processed */
+ dwc->oevten = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, 0);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ spin_unlock(&dwc->lock);
+
+ return ret;
+}
+
/* --------------------- Dual-Role management ------------------------------- */
static void dwc3_drd_fsm_sync(struct dwc3 *dwc)
@@ -730,10 +787,35 @@ static int dwc3_drd_start_host(struct otg_fsm *fsm, int on)
{
struct device *dev = usb_otg_fsm_to_dev(fsm);
struct dwc3 *dwc = dev_get_drvdata(dev);
+ u32 reg;
dev_dbg(dwc->dev, "%s: %d\n", __func__, on);
- if (on)
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+ if (dwc->edev) {
+ if (on)
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+
+ return 0;
+ }
+
+ /* switch OTG core */
+ if (on) {
+ /* OCTL.PeriMode = 0 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg &= ~DWC3_OCTL_PERIMODE;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+ /* unconditionally turn on VBUS */
+ reg |= DWC3_OCTL_PRTPWRCTL;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+ } else {
+ /* turn off VBUS */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg &= ~DWC3_OCTL_PRTPWRCTL;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+ /* OCTL.PeriMode = 1 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg |= DWC3_OCTL_PERIMODE;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+ }
return 0;
}
@@ -742,11 +824,42 @@ static int dwc3_drd_start_gadget(struct otg_fsm *fsm, int on)
{
struct device *dev = usb_otg_fsm_to_dev(fsm);
struct dwc3 *dwc = dev_get_drvdata(dev);
+ u32 reg;
dev_dbg(dwc->dev, "%s: %d\n", __func__, on);
- if (on) {
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ if (on)
dwc3_event_buffers_setup(dwc);
+
+ if (dwc->edev) {
+ if (on)
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+
+ return 0;
+ }
+
+ /* switch OTG core */
+ if (on) {
+ /* OCTL.PeriMode = 1 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg |= DWC3_OCTL_PERIMODE;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
+ /* GUSB2PHYCFG0.SusPHY = 1 */
+ if (!dwc->dis_u2_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+ } else {
+ /* GUSB2PHYCFG0.SusPHY=0 */
+ if (!dwc->dis_u2_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+ /* OCTL.PeriMode = 1 */
+ reg = dwc3_readl(dwc->regs, DWC3_OCTL);
+ reg |= DWC3_OCTL_PERIMODE;
+ dwc3_writel(dwc->regs, DWC3_OCTL, reg);
}
return 0;
@@ -767,13 +880,35 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
+static int dwc3_drd_register(struct dwc3 *dwc)
+{
+ int ret;
+
+ /* register parent as DRD device with OTG core */
+ dwc->fsm = usb_otg_register(dwc->dev, &dwc3_drd_ops, true);
+ if (IS_ERR(dwc->fsm)) {
+ ret = PTR_ERR(dwc->fsm);
+ if (ret == -ENOSYS)
+ dev_err(dwc->dev, "CONFIG_USB_OTG needed for dual-role\n");
+ else
+ dev_err(dwc->dev, "Failed to register with OTG core\n");
+
+ return ret;
+ }
+
+ return 0;
+}
+
static int dwc3_drd_init(struct dwc3 *dwc)
{
int ret, id, vbus;
+ u32 reg;
+ struct dwc3_hwparams *parms = &dwc->hwparams;
+ /* If extcon device is not present we rely on OTG core for ID event */
if (!dwc->edev) {
- dev_err(dwc->dev, "No extcon device found for OTG mode\n");
- return -ENODEV;
+ dev_dbg(dwc->dev, "No extcon device found for OTG mode\n");
+ goto try_otg_core;
}
dwc->otg_nb.notifier_call = dwc3_drd_notifier;
@@ -801,17 +936,9 @@ static int dwc3_drd_init(struct dwc3 *dwc)
goto fail;
}
- /* register parent as DRD device with OTG core */
- dwc->fsm = usb_otg_register(dwc->dev, &dwc3_drd_ops, true);
- if (IS_ERR(dwc->fsm)) {
- ret = PTR_ERR(dwc->fsm);
- if (ret == -ENOSYS)
- dev_err(dwc->dev, "CONFIG_USB_OTG needed for dual-role\n");
- else
- dev_err(dwc->dev, "Failed to register with OTG core\n");
-
+ ret = dwc3_drd_register(dwc);
+ if (ret)
goto fail;
- }
dwc3_drd_fsm_sync(dwc);
@@ -822,6 +949,72 @@ extcon_fail:
extcon_unregister_notifier(dwc->edev, EXTCON_USB, &dwc->otg_nb);
return ret;
+
+try_otg_core:
+ /* get OTG capabilities */
+ dwc->otg_has_hnp_rsp = !!(parms->hwparams6 & DWC3_GHWPARAMS6_HNPSUPPORT);
+ dwc->otg_has_srp = !!(parms->hwparams6 & DWC3_GHWPARAMS6_SRPSUPPORT);
+ dwc->otg_has_adp = !!(parms->hwparams6 & DWC3_GHWPARAMS6_ADPSUPPORT);
+ dwc->otg_has_bc = !!(parms->hwparams6 & DWC3_GHWPARAMS6_BCSUPPORT);
+ dwc->otg_has_otg3 = !!(parms->hwparams6 & DWC3_GHWPARAMS6_OTG3SUPPORT);
+
+ dev_dbg(dwc->dev, "otg v%s - srp: %d, hnp/rsp:%d, adp:%d, bc:%d\n",
+ dwc->otg_has_otg3 ? "3.0":"2.0",
+ dwc->otg_has_srp, dwc->otg_has_hnp_rsp,
+ dwc->otg_has_adp, dwc->otg_has_bc);
+
+ ret = dwc3_drd_register(dwc);
+ if (ret)
+ return ret;
+
+ /* disable all irqs */
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, 0);
+ /* clear all events */
+ dwc3_writel(dwc->regs, DWC3_OEVT, ~0);
+
+ ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq, dwc3_otg_thread_irq,
+ IRQF_SHARED, "dwc3-otg", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ dwc->otg_irq, ret);
+ ret = -ENODEV;
+ goto error;
+ }
+
+ /* we need to set OTG to get events from OTG core */
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+ /* GUSB2PHYCFG0.SusPHY=0 */
+ if (!dwc->dis_u2_susphy_quirk) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+
+ /* Initialize OTG registers */
+ /*
+ * Prevent host/device reset from resetting OTG core.
+ * If we don't do this then xhci_reset (USBCMD.HCRST) will reset
+ * the signal outputs sent to the PHY, the OTG FSM logic of the
+ * core and also the resets to the VBUS filters inside the core.
+ */
+ reg = DWC3_OCFG_SFTRSTMASK;
+ dwc3_writel(dwc->regs, DWC3_OCFG, reg);
+ /* Enable ID event interrupt */
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, DWC3_OEVTEN_CONIDSTSCHNGEN |
+ DWC3_OEVTEN_BDEVVBUSCHNGE |
+ DWC3_OEVTEN_BDEVSESSVLDDETEN);
+ /* OCTL.PeriMode = 1 */
+ dwc3_writel(dwc->regs, DWC3_OCTL, DWC3_OCTL_PERIMODE);
+
+ dwc3_otg_fsm_sync(dwc);
+ usb_otg_sync_inputs(dwc->fsm);
+
+ return 0;
+
+error:
+ usb_otg_unregister(dwc->dev);
+
+ return ret;
}
static void dwc3_drd_exit(struct dwc3 *dwc)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index c3431b2..744a5ff 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -736,6 +736,7 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
+ * @oevten: otg interrupt enable mask copy
* @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
@@ -805,6 +806,11 @@ struct dwc3_scratchpad_array {
* 1 - -3.5dB de-emphasis
* 2 - No de-emphasis
* 3 - Reserved
+ * @otg_has_srp: set if otg core supports SRP
+ * @otg_has_hnp_rsp: set if otg core supports HNP/RSP
+ * @otg_has_adp: set if otg core supports ADP
+ * @otg_has_bc: set if otg core supports BC
+ * @otg_has_otg3: set if otg core supports OTG v3.0
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -857,6 +863,8 @@ struct dwc3 {
u32 dcfg;
u32 gctl;
+ u32 oevten;
+
u32 nr_scratch;
u32 num_event_buffers;
u32 u1u2;
@@ -939,6 +947,12 @@ struct dwc3 {
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
+
+ unsigned otg_has_srp:1;
+ unsigned otg_has_hnp_rsp:1;
+ unsigned otg_has_adp:1;
+ unsigned otg_has_bc:1;
+ unsigned otg_has_otg3:1;
};
/* -------------------------------------------------------------------------- */
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 6/9] usb: dwc3: save/restore OTG registers during suspend/resume
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
` (4 preceding siblings ...)
2015-07-08 10:36 ` [PATCH v3 5/9] usb: dwc3: core: make dual-role work with OTG irq Roger Quadros
@ 2015-07-08 10:36 ` Roger Quadros
2015-07-08 10:37 ` [PATCH v3 7/9] usb: dwc3: gadget: Fix suspend/resume during dual-role mode Roger Quadros
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:36 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
Without this we loose OTG controller register context and malfunction
after a system suspend-resume.
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.c | 17 +++++++++++++++++
drivers/usb/dwc3/core.h | 6 +++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 138847f..d050e0e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -56,6 +56,7 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode);
+ dwc->current_mode = mode;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
@@ -1432,6 +1433,14 @@ static int dwc3_suspend(struct device *dev)
spin_lock_irqsave(&dwc->lock, flags);
+ /* Save OTG state only if we're really using it */
+ if (dwc->current_mode == DWC3_GCTL_PRTCAP_OTG) {
+ dwc->ocfg = dwc3_readl(dwc->regs, DWC3_OCFG);
+ dwc->octl = dwc3_readl(dwc->regs, DWC3_OCTL);
+ dwc->oevt = dwc3_readl(dwc->regs, DWC3_OEVT);
+ dwc->oevten = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+ }
+
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
@@ -1475,6 +1484,14 @@ static int dwc3_resume(struct device *dev)
dwc3_event_buffers_setup(dwc);
dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
+ /* Restore OTG state only if we're really using it */
+ if (dwc->current_mode == DWC3_GCTL_PRTCAP_OTG) {
+ dwc3_writel(dwc->regs, DWC3_OCFG, dwc->ocfg);
+ dwc3_writel(dwc->regs, DWC3_OCTL, dwc->octl);
+ dwc3_writel(dwc->regs, DWC3_OEVT, dwc->oevt);
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, dwc->oevten);
+ }
+
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 744a5ff..c9c64c9 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -737,6 +737,7 @@ struct dwc3_scratchpad_array {
* @regs: base address for our registers
* @regs_size: address space size
* @oevten: otg interrupt enable mask copy
+ * @current_mode: current mode of operation written to PRTCAPDIR
* @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
@@ -862,9 +863,12 @@ struct dwc3 {
/* used for suspend/resume */
u32 dcfg;
u32 gctl;
-
+ u32 ocfg;
+ u32 octl;
+ u32 oevt;
u32 oevten;
+ u32 current_mode;
u32 nr_scratch;
u32 num_event_buffers;
u32 u1u2;
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 7/9] usb: dwc3: gadget: Fix suspend/resume during dual-role mode
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
` (5 preceding siblings ...)
2015-07-08 10:36 ` [PATCH v3 6/9] usb: dwc3: save/restore OTG registers during suspend/resume Roger Quadros
@ 2015-07-08 10:37 ` Roger Quadros
2015-07-08 10:37 ` [PATCH v3 8/9] usb: dwc3: core: Prevent otg events from disabling themselves Roger Quadros
2015-07-08 10:37 ` [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role Roger Quadros
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:37 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
Gdget controller might not be always active during suspend/
resume when we are operating in dual-role/otg mode.
Check if we're active and only if we are then perform
necessary actions during suspend/resume.
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/gadget.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index cf6b945..3cc8c18 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2779,6 +2779,9 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
+ if (!dwc->gadget_driver)
+ return 0;
+
if (dwc->pullups_connected) {
dwc3_gadget_disable_irq(dwc);
dwc3_gadget_run_stop(dwc, true, true);
@@ -2797,6 +2800,9 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
struct dwc3_ep *dep;
int ret;
+ if (!dwc->gadget_driver)
+ return 0;
+
/* Start with SuperSpeed Default */
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 8/9] usb: dwc3: core: Prevent otg events from disabling themselves
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
` (6 preceding siblings ...)
2015-07-08 10:37 ` [PATCH v3 7/9] usb: dwc3: gadget: Fix suspend/resume during dual-role mode Roger Quadros
@ 2015-07-08 10:37 ` Roger Quadros
2015-07-08 10:37 ` [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role Roger Quadros
8 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:37 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
There is a race happening during dwc3_drd_init() that causes
otg events to get disabled. This is what happens.
dwc3_otg_irq() happens immediately when PRTCAP is set to OTG,
even though OEVTEN is 0. This is because BIT 31 IRQ of
OEVT can't be disabled by OEVTEN.
We configure OEVTEN in dwc3_otg_init() but dwc3_otg_irq() has
already saved OEVTEN as 0 into dwc->oevten. So finally when
dwc3_irq_thread_irq() is called we save 0 into OEVTEN
thus disabling OTG irqs forever.
We fix this by disabling IRQs when configuring OEVTEN in
dwc3_otg_init().
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index d050e0e..e3c094d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -905,6 +905,7 @@ static int dwc3_drd_init(struct dwc3 *dwc)
int ret, id, vbus;
u32 reg;
struct dwc3_hwparams *parms = &dwc->hwparams;
+ unsigned long flags;
/* If extcon device is not present we rely on OTG core for ID event */
if (!dwc->edev) {
@@ -982,6 +983,8 @@ try_otg_core:
goto error;
}
+ spin_lock_irqsave(&dwc->lock, flags);
+
/* we need to set OTG to get events from OTG core */
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
/* GUSB2PHYCFG0.SusPHY=0 */
@@ -1007,6 +1010,8 @@ try_otg_core:
/* OCTL.PeriMode = 1 */
dwc3_writel(dwc->regs, DWC3_OCTL, DWC3_OCTL_PERIMODE);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
dwc3_otg_fsm_sync(dwc);
usb_otg_sync_inputs(dwc->fsm);
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
` (7 preceding siblings ...)
2015-07-08 10:37 ` [PATCH v3 8/9] usb: dwc3: core: Prevent otg events from disabling themselves Roger Quadros
@ 2015-07-08 10:37 ` Roger Quadros
2015-07-08 13:11 ` Sergei Shtylyov
8 siblings, 1 reply; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 10:37 UTC (permalink / raw)
To: balbi; +Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap,
Roger Quadros
We can't rely just on dr_mode to decide if we're in host or gadget
mode when we're configured as otg/dual-role. So while dr_mode is
OTG, we find out from the otg state machine if we're in host
or gadget mode and take the necessary actions during suspend/resume.
Also make sure that we disable OTG irq and events during system suspend
so that we don't lockup the system during system suspend/resume.
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
drivers/usb/dwc3/core.c | 27 +++++++++------------------
1 file changed, 9 insertions(+), 18 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index e3c094d..3784287 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1444,18 +1444,15 @@ static int dwc3_suspend(struct device *dev)
dwc->octl = dwc3_readl(dwc->regs, DWC3_OCTL);
dwc->oevt = dwc3_readl(dwc->regs, DWC3_OEVT);
dwc->oevten = dwc3_readl(dwc->regs, DWC3_OEVTEN);
+ dwc3_writel(dwc->regs, DWC3_OEVTEN, 0);
+ disable_irq(dwc->otg_irq);
}
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
+ if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL ||
+ ((dwc->dr_mode == USB_DR_MODE_OTG) && dwc->fsm->protocol == PROTO_GADGET))
dwc3_gadget_suspend(dwc);
- /* FALLTHROUGH */
- case USB_DR_MODE_HOST:
- default:
- dwc3_event_buffers_cleanup(dwc);
- break;
- }
+
+ dwc3_event_buffers_cleanup(dwc);
dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1495,18 +1492,12 @@ static int dwc3_resume(struct device *dev)
dwc3_writel(dwc->regs, DWC3_OCTL, dwc->octl);
dwc3_writel(dwc->regs, DWC3_OEVT, dwc->oevt);
dwc3_writel(dwc->regs, DWC3_OEVTEN, dwc->oevten);
+ enable_irq(dwc->otg_irq);
}
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
+ if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL ||
+ ((dwc->dr_mode == USB_DR_MODE_OTG) && dwc->fsm->protocol == PROTO_GADGET))
dwc3_gadget_resume(dwc);
- /* FALLTHROUGH */
- case USB_DR_MODE_HOST:
- default:
- /* do nothing */
- break;
- }
spin_unlock_irqrestore(&dwc->lock, flags);
--
2.1.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts
2015-07-08 10:36 ` [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts Roger Quadros
@ 2015-07-08 13:06 ` Sergei Shtylyov
2015-07-08 14:43 ` Roger Quadros
0 siblings, 1 reply; 14+ messages in thread
From: Sergei Shtylyov @ 2015-07-08 13:06 UTC (permalink / raw)
To: Roger Quadros, balbi
Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap
Hello.
On 7/8/2015 1:36 PM, Roger Quadros wrote:
> From: Felipe Balbi <balbi@ti.com>
> Add support to use interrupt names,
> Following are the interrupt names
> Peripheral Interrupt - peripheral
> HOST Interrupt - host
> OTG Interrupt - otg
> [Roger Q]
> - If any of these are missing we use the
> first available IRQ resource so that we don't
> break with older DTBs.
> - Use gadget_irq in gadget driver.
> Signed-off-by: Felipe Balbi <balbi@ti.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
> drivers/usb/dwc3/core.c | 12 ++++++++++++
> drivers/usb/dwc3/core.h | 7 +++++++
> drivers/usb/dwc3/gadget.c | 2 +-
> 3 files changed, 20 insertions(+), 1 deletion(-)
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index a7498e0..7b33d7b 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -941,6 +941,18 @@ static int dwc3_probe(struct platform_device *pdev)
> dwc->xhci_resources[1].flags = res->flags;
> dwc->xhci_resources[1].name = res->name;
>
> + dwc->otg_irq = platform_get_irq_byname(pdev, "otg");
> + if (!dwc->otg_irq)
The usual mistake repeated again: that function reutrns error # on
failure, not 0.
> + dwc->otg_irq = res->start;
> +
> + dwc->gadget_irq = platform_get_irq_byname(pdev, "peripheral");
> + if (!dwc->gadget_irq)
> + dwc->gadget_irq = res->start;
Likewise.
> +
> + dwc->xhci_irq = platform_get_irq_byname(pdev, "host");
> + if (!dwc->xhci_irq)
Likewise.
[...]
WBR, Sergei
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role
2015-07-08 10:37 ` [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role Roger Quadros
@ 2015-07-08 13:11 ` Sergei Shtylyov
2015-07-08 14:44 ` Roger Quadros
0 siblings, 1 reply; 14+ messages in thread
From: Sergei Shtylyov @ 2015-07-08 13:11 UTC (permalink / raw)
To: Roger Quadros, balbi
Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap
Hello.
On 7/8/2015 1:37 PM, Roger Quadros wrote:
> We can't rely just on dr_mode to decide if we're in host or gadget
> mode when we're configured as otg/dual-role. So while dr_mode is
> OTG, we find out from the otg state machine if we're in host
> or gadget mode and take the necessary actions during suspend/resume.
> Also make sure that we disable OTG irq and events during system suspend
> so that we don't lockup the system during system suspend/resume.
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> ---
> drivers/usb/dwc3/core.c | 27 +++++++++------------------
> 1 file changed, 9 insertions(+), 18 deletions(-)
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index e3c094d..3784287 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -1444,18 +1444,15 @@ static int dwc3_suspend(struct device *dev)
> dwc->octl = dwc3_readl(dwc->regs, DWC3_OCTL);
> dwc->oevt = dwc3_readl(dwc->regs, DWC3_OEVT);
> dwc->oevten = dwc3_readl(dwc->regs, DWC3_OEVTEN);
> + dwc3_writel(dwc->regs, DWC3_OEVTEN, 0);
> + disable_irq(dwc->otg_irq);
> }
>
> - switch (dwc->dr_mode) {
> - case USB_DR_MODE_PERIPHERAL:
> - case USB_DR_MODE_OTG:
> + if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL ||
> + ((dwc->dr_mode == USB_DR_MODE_OTG) && dwc->fsm->protocol == PROTO_GADGET))
Hum, enclosing the first == op into parens and not doing it to the second
== op doesn't look very consistent... :-)
[...]
> @@ -1495,18 +1492,12 @@ static int dwc3_resume(struct device *dev)
> dwc3_writel(dwc->regs, DWC3_OCTL, dwc->octl);
> dwc3_writel(dwc->regs, DWC3_OEVT, dwc->oevt);
> dwc3_writel(dwc->regs, DWC3_OEVTEN, dwc->oevten);
> + enable_irq(dwc->otg_irq);
> }
>
> - switch (dwc->dr_mode) {
> - case USB_DR_MODE_PERIPHERAL:
> - case USB_DR_MODE_OTG:
> + if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL ||
> + ((dwc->dr_mode == USB_DR_MODE_OTG) && dwc->fsm->protocol == PROTO_GADGET))
Same here...
[...]
WBR, Sergei
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts
2015-07-08 13:06 ` Sergei Shtylyov
@ 2015-07-08 14:43 ` Roger Quadros
0 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 14:43 UTC (permalink / raw)
To: Sergei Shtylyov, balbi
Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap
Hi,
On 08/07/15 16:06, Sergei Shtylyov wrote:
> Hello.
>
> On 7/8/2015 1:36 PM, Roger Quadros wrote:
>
>> From: Felipe Balbi <balbi@ti.com>
>
>> Add support to use interrupt names,
>
>> Following are the interrupt names
>
>> Peripheral Interrupt - peripheral
>> HOST Interrupt - host
>> OTG Interrupt - otg
>
>> [Roger Q]
>> - If any of these are missing we use the
>> first available IRQ resource so that we don't
>> break with older DTBs.
>
>> - Use gadget_irq in gadget driver.
>
>> Signed-off-by: Felipe Balbi <balbi@ti.com>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>> drivers/usb/dwc3/core.c | 12 ++++++++++++
>> drivers/usb/dwc3/core.h | 7 +++++++
>> drivers/usb/dwc3/gadget.c | 2 +-
>> 3 files changed, 20 insertions(+), 1 deletion(-)
>
>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>> index a7498e0..7b33d7b 100644
>> --- a/drivers/usb/dwc3/core.c
>> +++ b/drivers/usb/dwc3/core.c
>> @@ -941,6 +941,18 @@ static int dwc3_probe(struct platform_device *pdev)
>> dwc->xhci_resources[1].flags = res->flags;
>> dwc->xhci_resources[1].name = res->name;
>>
>> + dwc->otg_irq = platform_get_irq_byname(pdev, "otg");
>> + if (!dwc->otg_irq)
>
> The usual mistake repeated again: that function reutrns error # on failure, not 0.
>
>> + dwc->otg_irq = res->start;
>> +
>> + dwc->gadget_irq = platform_get_irq_byname(pdev, "peripheral");
>> + if (!dwc->gadget_irq)
>> + dwc->gadget_irq = res->start;
>
> Likewise.
>
>> +
>> + dwc->xhci_irq = platform_get_irq_byname(pdev, "host");
>> + if (!dwc->xhci_irq)
>
> Likewise.
Right. I'll fix it up. Thanks.
cheers,
-roger
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role
2015-07-08 13:11 ` Sergei Shtylyov
@ 2015-07-08 14:44 ` Roger Quadros
0 siblings, 0 replies; 14+ messages in thread
From: Roger Quadros @ 2015-07-08 14:44 UTC (permalink / raw)
To: Sergei Shtylyov, balbi
Cc: tony, Joao.Pinto, linux-usb, linux-kernel, linux-omap
On 08/07/15 16:11, Sergei Shtylyov wrote:
> Hello.
>
> On 7/8/2015 1:37 PM, Roger Quadros wrote:
>
>> We can't rely just on dr_mode to decide if we're in host or gadget
>> mode when we're configured as otg/dual-role. So while dr_mode is
>> OTG, we find out from the otg state machine if we're in host
>> or gadget mode and take the necessary actions during suspend/resume.
>
>> Also make sure that we disable OTG irq and events during system suspend
>> so that we don't lockup the system during system suspend/resume.
>
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> ---
>> drivers/usb/dwc3/core.c | 27 +++++++++------------------
>> 1 file changed, 9 insertions(+), 18 deletions(-)
>
>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>> index e3c094d..3784287 100644
>> --- a/drivers/usb/dwc3/core.c
>> +++ b/drivers/usb/dwc3/core.c
>> @@ -1444,18 +1444,15 @@ static int dwc3_suspend(struct device *dev)
>> dwc->octl = dwc3_readl(dwc->regs, DWC3_OCTL);
>> dwc->oevt = dwc3_readl(dwc->regs, DWC3_OEVT);
>> dwc->oevten = dwc3_readl(dwc->regs, DWC3_OEVTEN);
>> + dwc3_writel(dwc->regs, DWC3_OEVTEN, 0);
>> + disable_irq(dwc->otg_irq);
>> }
>>
>> - switch (dwc->dr_mode) {
>> - case USB_DR_MODE_PERIPHERAL:
>> - case USB_DR_MODE_OTG:
>> + if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL ||
>> + ((dwc->dr_mode == USB_DR_MODE_OTG) && dwc->fsm->protocol == PROTO_GADGET))
>
> Hum, enclosing the first == op into parens and not doing it to the second == op doesn't look very consistent... :-)
Agreed :). Will fix it. Thanks.
>
> [...]
>> @@ -1495,18 +1492,12 @@ static int dwc3_resume(struct device *dev)
>> dwc3_writel(dwc->regs, DWC3_OCTL, dwc->octl);
>> dwc3_writel(dwc->regs, DWC3_OEVT, dwc->oevt);
>> dwc3_writel(dwc->regs, DWC3_OEVTEN, dwc->oevten);
>> + enable_irq(dwc->otg_irq);
>> }
>>
>> - switch (dwc->dr_mode) {
>> - case USB_DR_MODE_PERIPHERAL:
>> - case USB_DR_MODE_OTG:
>> + if (dwc->dr_mode == USB_DR_MODE_PERIPHERAL ||
>> + ((dwc->dr_mode == USB_DR_MODE_OTG) && dwc->fsm->protocol == PROTO_GADGET))
>
> Same here...
OK.
>
> [...]
>
cheers,
-roger
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2015-07-08 14:45 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-08 10:31 [PATCH v3 0/9] usb: dwc3: add dual-role support Roger Quadros
2015-07-08 10:31 ` [PATCH v3 1/9] " Roger Quadros
2015-07-08 10:31 ` [PATCH v3 2/9] usb: dwc3: core.h: add some register definitions Roger Quadros
2015-07-08 10:36 ` [PATCH v3 3/9] usb: dwc3: dwc3-omap: Make the wrapper interrupt shared Roger Quadros
2015-07-08 10:36 ` [PATCH v3 4/9] usb: dwc3: core: Adapt to named interrupts Roger Quadros
2015-07-08 13:06 ` Sergei Shtylyov
2015-07-08 14:43 ` Roger Quadros
2015-07-08 10:36 ` [PATCH v3 5/9] usb: dwc3: core: make dual-role work with OTG irq Roger Quadros
2015-07-08 10:36 ` [PATCH v3 6/9] usb: dwc3: save/restore OTG registers during suspend/resume Roger Quadros
2015-07-08 10:37 ` [PATCH v3 7/9] usb: dwc3: gadget: Fix suspend/resume during dual-role mode Roger Quadros
2015-07-08 10:37 ` [PATCH v3 8/9] usb: dwc3: core: Prevent otg events from disabling themselves Roger Quadros
2015-07-08 10:37 ` [PATCH v3 9/9] usb: dwc3: core: don't break during suspend/resume while we're dual-role Roger Quadros
2015-07-08 13:11 ` Sergei Shtylyov
2015-07-08 14:44 ` Roger Quadros
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox