267 lines
9.0 KiB
Diff
267 lines
9.0 KiB
Diff
From fc74bada7f6940619f8930556b7c61fe618f2a64 Mon Sep 17 00:00:00 2001
|
|
From: Romuald JEANNE <romuald.jeanne@st.com>
|
|
Date: Fri, 21 Dec 2018 16:56:27 +0100
|
|
Subject: [PATCH 50/52] ARM: stm32mp1-r0-rc4: USB
|
|
|
|
---
|
|
Documentation/devicetree/bindings/usb/dwc2.txt | 2 +
|
|
drivers/usb/dwc2/core.h | 11 ++++
|
|
drivers/usb/dwc2/core_intr.c | 4 +-
|
|
drivers/usb/dwc2/hw.h | 2 +
|
|
drivers/usb/dwc2/params.c | 7 ++-
|
|
drivers/usb/dwc2/platform.c | 74 +++++++++++++++++++++++---
|
|
6 files changed, 90 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt
|
|
index 32b245c..03c62de 100644
|
|
--- a/Documentation/devicetree/bindings/usb/dwc2.txt
|
|
+++ b/Documentation/devicetree/bindings/usb/dwc2.txt
|
|
@@ -43,6 +43,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
|
|
doesn't drive it.
|
|
- usb33d-supply: external VBUS and ID sensing comparators supply, in order to
|
|
perform OTG operation, used on STM32MP1 SoCs.
|
|
+- force-b-session-valid: force B-peripheral session instead of relying on
|
|
+ VBUS sensing (only valid when dr_mode = "peripheral").
|
|
|
|
Deprecated properties:
|
|
- g-use-dma: gadget DMA mode is automatically detected
|
|
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
|
|
index 4c689d1..4c1736f 100644
|
|
--- a/drivers/usb/dwc2/core.h
|
|
+++ b/drivers/usb/dwc2/core.h
|
|
@@ -415,6 +415,12 @@ enum dwc2_ep0_state {
|
|
* in DWORDS with possible values from from
|
|
* 16-32768 (default: 256, 256, 256, 256, 768,
|
|
* 768, 768, 768, 0, 0, 0, 0, 0, 0, 0).
|
|
+ * @force_b_session_valid: force B-peripheral session instead of relying on
|
|
+ * VBUS sensing (only valid when dr_mode = "peripheral").
|
|
+ * @suspend_ignore_power_down: prevent the controller to enter low power mode
|
|
+ * upon suspend interrupt. This may help in device mode,
|
|
+ * when suspend (3ms idle bus) gets detected before
|
|
+ * device session end (VBUS discharge > 3ms).
|
|
* @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL
|
|
* while full&low speed device connect. And change speed
|
|
* back to DWC2_SPEED_PARAM_HIGH while device is gone.
|
|
@@ -492,6 +498,8 @@ struct dwc2_core_params {
|
|
u32 g_rx_fifo_size;
|
|
u32 g_np_tx_fifo_size;
|
|
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
|
|
+ bool force_b_session_valid;
|
|
+ bool suspend_ignore_power_down;
|
|
|
|
bool change_speed_quirk;
|
|
};
|
|
@@ -849,6 +857,8 @@ struct dwc2_hregs_backup {
|
|
* removed once all SoCs support usb transceiver.
|
|
* @supplies: Definition of USB power supplies
|
|
* @vbus_supply: Regulator supplying vbus.
|
|
+ * @usb33d: Optional 3.3v regulator used on some stm32 devices to
|
|
+ * supply ID and VBUS detection hardware.
|
|
* @phyif: PHY interface width
|
|
* @lock: Spinlock that protects all the driver data structures
|
|
* @priv: Stores a pointer to the struct usb_hcd
|
|
@@ -1032,6 +1042,7 @@ struct dwc2_hsotg {
|
|
struct dwc2_hsotg_plat *plat;
|
|
struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
|
|
struct regulator *vbus_supply;
|
|
+ struct regulator *usb33d;
|
|
u32 phyif;
|
|
|
|
spinlock_t lock;
|
|
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
|
|
index 19ae259..7b4162c 100644
|
|
--- a/drivers/usb/dwc2/core_intr.c
|
|
+++ b/drivers/usb/dwc2/core_intr.c
|
|
@@ -492,7 +492,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|
hsotg->hw_params.hibernation);
|
|
|
|
/* Ignore suspend request before enumeration */
|
|
- if (!dwc2_is_device_connected(hsotg)) {
|
|
+ if (!dwc2_is_device_connected(hsotg) ||
|
|
+ hsotg->params.force_b_session_valid ||
|
|
+ hsotg->params.suspend_ignore_power_down) {
|
|
dev_dbg(hsotg->dev,
|
|
"ignore suspend request before enumeration\n");
|
|
return;
|
|
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
|
|
index afde335..31f8c60 100644
|
|
--- a/drivers/usb/dwc2/hw.h
|
|
+++ b/drivers/usb/dwc2/hw.h
|
|
@@ -54,6 +54,8 @@
|
|
#define GOTGCTL_HSTSETHNPEN BIT(10)
|
|
#define GOTGCTL_HNPREQ BIT(9)
|
|
#define GOTGCTL_HSTNEGSCS BIT(8)
|
|
+#define GOTGCTL_BVALOVAL BIT(7)
|
|
+#define GOTGCTL_BVALOEN BIT(6)
|
|
#define GOTGCTL_SESREQ BIT(1)
|
|
#define GOTGCTL_SESREQSCS BIT(0)
|
|
|
|
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
|
|
index 63ccfc9..7fef905 100644
|
|
--- a/drivers/usb/dwc2/params.c
|
|
+++ b/drivers/usb/dwc2/params.c
|
|
@@ -167,7 +167,7 @@ static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg)
|
|
p->host_rx_fifo_size = 440;
|
|
p->host_nperio_tx_fifo_size = 256;
|
|
p->host_perio_tx_fifo_size = 256;
|
|
- p->power_down = false;
|
|
+ p->suspend_ignore_power_down = true;
|
|
}
|
|
|
|
const struct of_device_id dwc2_of_match_table[] = {
|
|
@@ -404,6 +404,11 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
|
|
|
|
if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
|
|
p->oc_disable = true;
|
|
+
|
|
+ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
|
|
+ p->force_b_session_valid =
|
|
+ of_property_read_bool(hsotg->dev->of_node,
|
|
+ "force-b-session-valid");
|
|
}
|
|
|
|
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
|
|
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
|
|
index 2061254..b2e5ddc 100644
|
|
--- a/drivers/usb/dwc2/platform.c
|
|
+++ b/drivers/usb/dwc2/platform.c
|
|
@@ -324,6 +324,10 @@ static int dwc2_driver_remove(struct platform_device *dev)
|
|
if (hsotg->gadget_enabled)
|
|
dwc2_hsotg_remove(hsotg);
|
|
|
|
+ if (hsotg->params.activate_stm_id_vb_detection &&
|
|
+ !hsotg->params.force_b_session_valid)
|
|
+ regulator_disable(hsotg->usb33d);
|
|
+
|
|
if (hsotg->ll_hw_enabled)
|
|
dwc2_lowlevel_hw_disable(hsotg);
|
|
|
|
@@ -474,18 +478,18 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
if (retval)
|
|
goto error;
|
|
|
|
- if (hsotg->params.activate_stm_id_vb_detection) {
|
|
- struct regulator *usb33d;
|
|
+ if (hsotg->params.activate_stm_id_vb_detection &&
|
|
+ !hsotg->params.force_b_session_valid) {
|
|
u32 ggpio;
|
|
|
|
- usb33d = devm_regulator_get(hsotg->dev, "usb33d");
|
|
- if (IS_ERR(usb33d)) {
|
|
- retval = PTR_ERR(usb33d);
|
|
+ hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
|
|
+ if (IS_ERR(hsotg->usb33d)) {
|
|
+ retval = PTR_ERR(hsotg->usb33d);
|
|
dev_err(hsotg->dev,
|
|
"can't get voltage level detector supply\n");
|
|
goto error;
|
|
}
|
|
- retval = regulator_enable(usb33d);
|
|
+ retval = regulator_enable(hsotg->usb33d);
|
|
if (retval) {
|
|
dev_err(hsotg->dev,
|
|
"can't enable voltage level detector supply\n");
|
|
@@ -498,6 +502,15 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
dwc2_writel(hsotg, ggpio, GGPIO);
|
|
}
|
|
|
|
+ if (hsotg->params.force_b_session_valid) {
|
|
+ u32 gotgctl;
|
|
+
|
|
+ gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
|
+ gotgctl |= GOTGCTL_BVALOVAL; /* B-peripheral session value */
|
|
+ gotgctl |= GOTGCTL_BVALOEN; /* B-peripheral override enable */
|
|
+ dwc2_writel(hsotg, gotgctl, GOTGCTL);
|
|
+ }
|
|
+
|
|
if (hsotg->params.activate_stm_fs_transceiver) {
|
|
u32 ggpio;
|
|
|
|
@@ -516,7 +529,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
|
|
retval = dwc2_gadget_init(hsotg);
|
|
if (retval)
|
|
- goto error;
|
|
+ goto error_init;
|
|
hsotg->gadget_enabled = 1;
|
|
}
|
|
|
|
@@ -525,7 +538,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
if (retval) {
|
|
if (hsotg->gadget_enabled)
|
|
dwc2_hsotg_remove(hsotg);
|
|
- goto error;
|
|
+ goto error_init;
|
|
}
|
|
hsotg->hcd_enabled = 1;
|
|
}
|
|
@@ -541,6 +554,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|
|
|
return 0;
|
|
|
|
+error_init:
|
|
+ if (hsotg->params.activate_stm_id_vb_detection &&
|
|
+ !hsotg->params.force_b_session_valid)
|
|
+ regulator_disable(hsotg->usb33d);
|
|
error:
|
|
dwc2_lowlevel_hw_disable(hsotg);
|
|
return retval;
|
|
@@ -554,6 +571,18 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
|
|
if (dwc2_is_device_mode(dwc2))
|
|
dwc2_hsotg_suspend(dwc2);
|
|
|
|
+ if (dwc2->params.activate_stm_id_vb_detection &&
|
|
+ !dwc2->params.force_b_session_valid) {
|
|
+ u32 ggpio;
|
|
+
|
|
+ ggpio = dwc2_readl(dwc2, GGPIO);
|
|
+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
|
|
+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
|
|
+ dwc2_writel(dwc2, ggpio, GGPIO);
|
|
+
|
|
+ regulator_disable(dwc2->usb33d);
|
|
+ }
|
|
+
|
|
if (dwc2->ll_hw_enabled)
|
|
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
|
|
|
@@ -571,6 +600,35 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|
return ret;
|
|
}
|
|
|
|
+ /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
|
|
+ dwc2_force_dr_mode(dwc2);
|
|
+
|
|
+ if (dwc2->params.activate_stm_id_vb_detection &&
|
|
+ !dwc2->params.force_b_session_valid) {
|
|
+ u32 ggpio;
|
|
+
|
|
+ ret = regulator_enable(dwc2->usb33d);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ggpio = dwc2_readl(dwc2, GGPIO);
|
|
+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
|
|
+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
|
|
+ dwc2_writel(dwc2, ggpio, GGPIO);
|
|
+
|
|
+ /* ID/VBUS detection startup time */
|
|
+ usleep_range(5000, 7000);
|
|
+ }
|
|
+
|
|
+ if (dwc2->params.force_b_session_valid) {
|
|
+ u32 gotgctl;
|
|
+
|
|
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
|
|
+ gotgctl |= GOTGCTL_BVALOVAL; /* B-peripheral session value */
|
|
+ gotgctl |= GOTGCTL_BVALOEN; /* B-peripheral override enable */
|
|
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
|
|
+ }
|
|
+
|
|
if (dwc2_is_device_mode(dwc2))
|
|
ret = dwc2_hsotg_resume(dwc2);
|
|
|
|
--
|
|
2.7.4
|
|
|