Skip to content

Commit a40a003

Browse files
Heiko StübnerFelipe Balbi
authored andcommitted
usb: dwc2: add shutdown callback to platform variant
In specific conditions (involving usb hubs) dwc2 devices can create a lot of interrupts, even to the point of overwhelming devices running at low frequencies. Some devices need to do special clock handling at shutdown-time which may bring the system clock below the threshold of being able to handle the dwc2 interrupts. Disabling dwc2-irqs in a shutdown callbacks prevents reboots/poweroffs from getting stuck in such cases. The hsotg struct already contains an unused irq element, so we can just use it to store the irq number for the shutdown callback. Reviewed-by: Douglas Anderson <dianders@chromium.org> Acked-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Heiko Stuebner <heiko.stuebner@collabora.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
1 parent ea4a8cb commit a40a003

File tree

1 file changed

+27
-8
lines changed

1 file changed

+27
-8
lines changed

drivers/usb/dwc2/platform.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,25 @@ static int dwc2_driver_remove(struct platform_device *dev)
405405
return 0;
406406
}
407407

408+
/**
409+
* dwc2_driver_shutdown() - Called on device shutdown
410+
*
411+
* @dev: Platform device
412+
*
413+
* In specific conditions (involving usb hubs) dwc2 devices can create a
414+
* lot of interrupts, even to the point of overwhelming devices running
415+
* at low frequencies. Some devices need to do special clock handling
416+
* at shutdown-time which may bring the system clock below the threshold
417+
* of being able to handle the dwc2 interrupts. Disabling dwc2-irqs
418+
* prevents reboots/poweroffs from getting stuck in such cases.
419+
*/
420+
static void dwc2_driver_shutdown(struct platform_device *dev)
421+
{
422+
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
423+
424+
disable_irq(hsotg->irq);
425+
}
426+
408427
static const struct of_device_id dwc2_of_match_table[] = {
409428
{ .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
410429
{ .compatible = "hisilicon,hi6220-usb", .data = &params_hi6220 },
@@ -435,7 +454,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
435454
struct dwc2_hsotg *hsotg;
436455
struct resource *res;
437456
int retval;
438-
int irq;
439457

440458
match = of_match_device(dwc2_of_match_table, &dev->dev);
441459
if (match && match->data) {
@@ -490,15 +508,15 @@ static int dwc2_driver_probe(struct platform_device *dev)
490508

491509
dwc2_set_all_params(hsotg->core_params, -1);
492510

493-
irq = platform_get_irq(dev, 0);
494-
if (irq < 0) {
511+
hsotg->irq = platform_get_irq(dev, 0);
512+
if (hsotg->irq < 0) {
495513
dev_err(&dev->dev, "missing IRQ resource\n");
496-
return irq;
514+
return hsotg->irq;
497515
}
498516

499517
dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
500-
irq);
501-
retval = devm_request_irq(hsotg->dev, irq,
518+
hsotg->irq);
519+
retval = devm_request_irq(hsotg->dev, hsotg->irq,
502520
dwc2_handle_common_intr, IRQF_SHARED,
503521
dev_name(hsotg->dev), hsotg);
504522
if (retval)
@@ -523,14 +541,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
523541
dwc2_force_dr_mode(hsotg);
524542

525543
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
526-
retval = dwc2_gadget_init(hsotg, irq);
544+
retval = dwc2_gadget_init(hsotg, hsotg->irq);
527545
if (retval)
528546
goto error;
529547
hsotg->gadget_enabled = 1;
530548
}
531549

532550
if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
533-
retval = dwc2_hcd_init(hsotg, irq);
551+
retval = dwc2_hcd_init(hsotg, hsotg->irq);
534552
if (retval) {
535553
if (hsotg->gadget_enabled)
536554
dwc2_hsotg_remove(hsotg);
@@ -597,6 +615,7 @@ static struct platform_driver dwc2_platform_driver = {
597615
},
598616
.probe = dwc2_driver_probe,
599617
.remove = dwc2_driver_remove,
618+
.shutdown = dwc2_driver_shutdown,
600619
};
601620

602621
module_platform_driver(dwc2_platform_driver);

0 commit comments

Comments
 (0)