build/patch/kernel/rockchip-next/assert-phy-reset-when-waking-up-in-rk3288-platform.patch
2019-01-11 02:29:02 -05:00

68 lines
2.2 KiB
Diff

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index cc9c93af..3ff41d87 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -1021,6 +1021,7 @@ struct dwc2_hsotg {
u16 frame_number;
struct phy *phy;
+ struct work_struct phy_rst_work;
struct usb_phy *uphy;
struct dwc2_hsotg_plat *plat;
struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 19ae2595..f1270bf1 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -396,6 +396,7 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
int ret;
+ struct device_node *np = hsotg->dev->of_node;
/* Clear interrupt */
dwc2_writel(hsotg, GINTSTS_WKUPINT, GINTSTS);
@@ -435,6 +436,16 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Restart the Phy Clock */
pcgcctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(hsotg, pcgcctl, PCGCTL);
+
+ /*
+ * It is a quirk in Rockchip RK3288, causing by
+ * a hardware bug. This will propagate out and
+ * eventually we'll re-enumerate the device.
+ * Not great but the best we can do.
+ */
+ if (of_device_is_compatible(np, "rockchip,rk3288-usb"))
+ schedule_work(&hsotg->phy_rst_work);
+
mod_timer(&hsotg->wkp_timer,
jiffies + msecs_to_jiffies(71));
} else {
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 57764289..748763bd 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -208,6 +208,14 @@ int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
return ret;
}
+/* Only used to reset usb phy at interrupter runtime */
+static void dwc2_reset_phy_work(struct work_struct *data)
+{
+ struct dwc2_hsotg *hsotg = container_of(data, struct dwc2_hsotg,
+ phy_rst_work);
+ phy_reset(hsotg->phy);
+}
+
static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
{
int i, ret;
@@ -252,6 +260,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
return ret;
}
}
+ INIT_WORK(&hsotg->phy_rst_work, dwc2_reset_phy_work);
if (!hsotg->phy) {
hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);