usb: chipidea: udc: add suspend/resume support for device controller
authorXu Yang <xu.yang_2@nxp.com>
Thu, 13 Oct 2022 15:14:38 +0000 (23:14 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 23 Oct 2022 12:34:53 +0000 (14:34 +0200)
The controller's power may be powered off during system suspend. This
will add suspend/resume support when the controller suffers power lost.

Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Link: https://lore.kernel.org/r/20221013151442.3262951-5-xu.yang_2@nxp.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/chipidea/udc.c

index 8c3e3a635ac2deedba05f83e383d059ecca2c995..54c09245ad055dc8a66c8e6a83d6686b37d2ab54 100644 (file)
@@ -2181,6 +2181,34 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
                                     ci->platdata->pins_default);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static void udc_suspend(struct ci_hdrc *ci)
+{
+       /*
+        * Set OP_ENDPTLISTADDR to be non-zero for
+        * checking if controller resume from power lost
+        * in non-host mode.
+        */
+       if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0)
+               hw_write(ci, OP_ENDPTLISTADDR, ~0, ~0);
+}
+
+static void udc_resume(struct ci_hdrc *ci, bool power_lost)
+{
+       if (power_lost) {
+               if (ci->is_otg)
+                       hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
+                                       OTGSC_BSVIS | OTGSC_BSVIE);
+               if (ci->vbus_active)
+                       usb_gadget_vbus_disconnect(&ci->gadget);
+       }
+
+       /* Restore value 0 if it was set for power lost check */
+       if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0xFFFFFFFF)
+               hw_write(ci, OP_ENDPTLISTADDR, ~0, 0);
+}
+#endif
+
 /**
  * ci_hdrc_gadget_init - initialize device related bits
  * @ci: the controller
@@ -2201,6 +2229,10 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
 
        rdrv->start     = udc_id_switch_for_device;
        rdrv->stop      = udc_id_switch_for_host;
+#ifdef CONFIG_PM_SLEEP
+       rdrv->suspend   = udc_suspend;
+       rdrv->resume    = udc_resume;
+#endif
        rdrv->irq       = udc_irq;
        rdrv->name      = "gadget";