aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/dwc2/core.h8
-rw-r--r--drivers/usb/dwc2/core_intr.c12
-rw-r--r--drivers/usb/dwc2/hcd.c18
-rw-r--r--drivers/usb/dwc2/platform.c9
4 files changed, 44 insertions, 3 deletions
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 30bab8463c96..764c78ebee28 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -859,6 +859,8 @@ struct dwc2_hregs_backup {
859 * @gadget_enabled: Peripheral mode sub-driver initialization indicator. 859 * @gadget_enabled: Peripheral mode sub-driver initialization indicator.
860 * @ll_hw_enabled: Status of low-level hardware resources. 860 * @ll_hw_enabled: Status of low-level hardware resources.
861 * @hibernated: True if core is hibernated 861 * @hibernated: True if core is hibernated
862 * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
863 * remote wakeup.
862 * @frame_number: Frame number read from the core. For both device 864 * @frame_number: Frame number read from the core. For both device
863 * and host modes. The value ranges are from 0 865 * and host modes. The value ranges are from 0
864 * to HFNUM_MAX_FRNUM. 866 * to HFNUM_MAX_FRNUM.
@@ -972,6 +974,7 @@ struct dwc2_hregs_backup {
972 * @status_buf_dma: DMA address for status_buf 974 * @status_buf_dma: DMA address for status_buf
973 * @start_work: Delayed work for handling host A-cable connection 975 * @start_work: Delayed work for handling host A-cable connection
974 * @reset_work: Delayed work for handling a port reset 976 * @reset_work: Delayed work for handling a port reset
977 * @phy_reset_work: Work structure for doing a PHY reset
975 * @otg_port: OTG port number 978 * @otg_port: OTG port number
976 * @frame_list: Frame list 979 * @frame_list: Frame list
977 * @frame_list_dma: Frame list DMA address 980 * @frame_list_dma: Frame list DMA address
@@ -1045,6 +1048,7 @@ struct dwc2_hsotg {
1045 unsigned int gadget_enabled:1; 1048 unsigned int gadget_enabled:1;
1046 unsigned int ll_hw_enabled:1; 1049 unsigned int ll_hw_enabled:1;
1047 unsigned int hibernated:1; 1050 unsigned int hibernated:1;
1051 unsigned int reset_phy_on_wake:1;
1048 u16 frame_number; 1052 u16 frame_number;
1049 1053
1050 struct phy *phy; 1054 struct phy *phy;
@@ -1147,6 +1151,7 @@ struct dwc2_hsotg {
1147 1151
1148 struct delayed_work start_work; 1152 struct delayed_work start_work;
1149 struct delayed_work reset_work; 1153 struct delayed_work reset_work;
1154 struct work_struct phy_reset_work;
1150 u8 otg_port; 1155 u8 otg_port;
1151 u32 *frame_list; 1156 u32 *frame_list;
1152 dma_addr_t frame_list_dma; 1157 dma_addr_t frame_list_dma;
@@ -1431,6 +1436,8 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
1431int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); 1436int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
1432int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, 1437int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
1433 int rem_wakeup, int reset); 1438 int rem_wakeup, int reset);
1439static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
1440{ schedule_work(&hsotg->phy_reset_work); }
1434#else 1441#else
1435static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg) 1442static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
1436{ return 0; } 1443{ return 0; }
@@ -1454,6 +1461,7 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
1454static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, 1461static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg,
1455 int rem_wakeup, int reset) 1462 int rem_wakeup, int reset)
1456{ return 0; } 1463{ return 0; }
1464static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
1457 1465
1458#endif 1466#endif
1459 1467
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 19ae2595f1c3..6af6add3d4c0 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -435,6 +435,18 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
435 /* Restart the Phy Clock */ 435 /* Restart the Phy Clock */
436 pcgcctl &= ~PCGCTL_STOPPCLK; 436 pcgcctl &= ~PCGCTL_STOPPCLK;
437 dwc2_writel(hsotg, pcgcctl, PCGCTL); 437 dwc2_writel(hsotg, pcgcctl, PCGCTL);
438
439 /*
440 * If we've got this quirk then the PHY is stuck upon
441 * wakeup. Assert reset. This will propagate out and
442 * eventually we'll re-enumerate the device. Not great
443 * but the best we can do. We can't call phy_reset()
444 * at interrupt time but there's no hurry, so we'll
445 * schedule it for later.
446 */
447 if (hsotg->reset_phy_on_wake)
448 dwc2_host_schedule_phy_reset(hsotg);
449
438 mod_timer(&hsotg->wkp_timer, 450 mod_timer(&hsotg->wkp_timer,
439 jiffies + msecs_to_jiffies(71)); 451 jiffies + msecs_to_jiffies(71));
440 } else { 452 } else {
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 8667ddf3ca74..978232a9e4a8 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4376,6 +4376,17 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
4376 spin_unlock_irqrestore(&hsotg->lock, flags); 4376 spin_unlock_irqrestore(&hsotg->lock, flags);
4377} 4377}
4378 4378
4379static void dwc2_hcd_phy_reset_func(struct work_struct *work)
4380{
4381 struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
4382 phy_reset_work);
4383 int ret;
4384
4385 ret = phy_reset(hsotg->phy);
4386 if (ret)
4387 dev_warn(hsotg->dev, "PHY reset failed\n");
4388}
4389
4379/* 4390/*
4380 * ========================================================================= 4391 * =========================================================================
4381 * Linux HC Driver Functions 4392 * Linux HC Driver Functions
@@ -5152,6 +5163,8 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
5152 destroy_workqueue(hsotg->wq_otg); 5163 destroy_workqueue(hsotg->wq_otg);
5153 } 5164 }
5154 5165
5166 cancel_work_sync(&hsotg->phy_reset_work);
5167
5155 del_timer(&hsotg->wkp_timer); 5168 del_timer(&hsotg->wkp_timer);
5156} 5169}
5157 5170
@@ -5293,11 +5306,10 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
5293 hsotg->hc_ptr_array[i] = channel; 5306 hsotg->hc_ptr_array[i] = channel;
5294 } 5307 }
5295 5308
5296 /* Initialize hsotg start work */ 5309 /* Initialize work */
5297 INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func); 5310 INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
5298
5299 /* Initialize port reset work */
5300 INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func); 5311 INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
5312 INIT_WORK(&hsotg->phy_reset_work, dwc2_hcd_phy_reset_func);
5301 5313
5302 /* 5314 /*
5303 * Allocate space for storing data on status transactions. Normally no 5315 * Allocate space for storing data on status transactions. Normally no
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 9aa9682a5cd2..c01fa8ffc0c8 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -481,6 +481,15 @@ static int dwc2_driver_probe(struct platform_device *dev)
481 hsotg->gadget_enabled = 1; 481 hsotg->gadget_enabled = 1;
482 } 482 }
483 483
484 hsotg->reset_phy_on_wake =
485 of_property_read_bool(dev->dev.of_node,
486 "snps,reset-phy-on-wake");
487 if (hsotg->reset_phy_on_wake && !hsotg->phy) {
488 dev_warn(hsotg->dev,
489 "Quirk reset-phy-on-wake only supports generic PHYs\n");
490 hsotg->reset_phy_on_wake = false;
491 }
492
484 if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { 493 if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
485 retval = dwc2_hcd_init(hsotg); 494 retval = dwc2_hcd_init(hsotg);
486 if (retval) { 495 if (retval) {