summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXu Yang <xu.yang_2@nxp.com>2022-10-13 23:14:38 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-10-23 14:34:53 +0200
commit235ffc17d0146d806f6ad8c094c24ff4878f2edb (patch)
treee73e54f56fb526ff9e3d5ff133a72ff903372e42
parent2f64d6a6cdfbd992e8a8c481ebf79bfa9a71325b (diff)
downloadlinux-235ffc17d0146d806f6ad8c094c24ff4878f2edb.tar.bz2
usb: chipidea: udc: add suspend/resume support for device controller
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>
-rw-r--r--drivers/usb/chipidea/udc.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 8c3e3a635ac2..54c09245ad05 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -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";