From: minda.chen Date: Tue, 17 Oct 2023 06:29:59 +0000 (+0900) Subject: usb: cdns3: add hibernation pm notifier to set roothub wakeup X-Git-Tag: accepted/tizen/unified/riscv/20231130.214005~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d5a3fbda7243a6e179a753fe9e9a941f904a28fc;p=platform%2Fkernel%2Flinux-starfive.git usb: cdns3: add hibernation pm notifier to set roothub wakeup In hibernation resume case. usb devices maybe not emulated, roothub is suspended, In this case, usb devices will be resume fail. Set roothub active while hibernation resume. Signed-off-by: minda.chen [hoegeun.kwon: cherry-pick the commit d86ba4820f59 from https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_6.1.y_devel] Signed-off-by: Hoegeun Kwon Change-Id: Idd244d8d3e50fd8e84cb72ff5fcdb50ff4399788 --- diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c index 55ae4ac..f43da41 100644 --- a/drivers/usb/cdns3/cdns3-starfive.c +++ b/drivers/usb/cdns3/cdns3-starfive.c @@ -176,6 +176,20 @@ static const unsigned int supported_cable[] = { }; #endif +static struct cdns3_platform_data cdns_starfive_pdata = { +#ifdef CONFIG_PM_SLEEP + .quirks = CDNS3_REGISTER_PM_NOTIFIER, +#endif +}; + +static const struct of_dev_auxdata cdns_starfive_auxdata[] = { + { + .compatible = "cdns,usb3", + .platform_data = &cdns_starfive_pdata, + }, + {}, +}; + static int cdns_starfive_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -239,7 +253,7 @@ static int cdns_starfive_probe(struct platform_device *pdev) if (ret) return ret; - ret = of_platform_populate(node, NULL, NULL, dev); + ret = of_platform_populate(node, NULL, cdns_starfive_auxdata, dev); if (ret) return dev_err_probe(dev, ret, "Failed to create children\n"); diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h index 2d332a7..f5ad30f 100644 --- a/drivers/usb/cdns3/core.h +++ b/drivers/usb/cdns3/core.h @@ -44,6 +44,7 @@ struct cdns3_platform_data { bool suspend, bool wakeup); unsigned long quirks; #define CDNS3_DEFAULT_PM_RUNTIME_ALLOW BIT(0) +#define CDNS3_REGISTER_PM_NOTIFIER BIT(1) }; /** diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index 6164fc4..ac1276f 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -24,7 +24,7 @@ #define CFG_RXDET_P3_EN BIT(15) #define LPM_2_STB_SWITCH_EN BIT(25) -static void xhci_cdns3_plat_start(struct usb_hcd *hcd) +static void xhci_cdns3_plat_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); u32 value; @@ -45,9 +45,18 @@ static void xhci_cdns3_plat_start(struct usb_hcd *hcd) } } +static void xhci_cdns3_plat_start(struct usb_hcd *hcd) +{ + xhci_cdns3_plat_setup(hcd); +#ifdef CONFIG_PM_SLEEP + if (cdns3_hiber_data.pm_setup) + cdns3_hiber_data.pm_setup(hcd); +#endif +} + static int xhci_cdns3_resume_quirk(struct usb_hcd *hcd) { - xhci_cdns3_plat_start(hcd); + xhci_cdns3_plat_setup(hcd); return 0; } @@ -57,6 +66,67 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = { .resume_quirk = xhci_cdns3_resume_quirk, }; +#ifdef CONFIG_PM_SLEEP +struct cdns_hiber_data { + struct usb_hcd *hcd; + struct usb_hcd *shared_hcd; + struct notifier_block pm_notifier; + int (*pm_setup)(struct usb_hcd *hcd); + int (*pm_remove)(struct cdns *cdns); +}; +static struct cdns_hiber_data cdns3_hiber_data; + +static int cdns_hiber_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct usb_hcd *hcd = cdns3_hiber_data.hcd; + struct usb_hcd *shared_hcd = cdns3_hiber_data.shared_hcd; + + switch (action) { + case PM_RESTORE_PREPARE: + if (hcd->state == HC_STATE_SUSPENDED) { + usb_hcd_resume_root_hub(hcd); + usb_disable_autosuspend(hcd->self.root_hub); + } + if (shared_hcd->state == HC_STATE_SUSPENDED) { + usb_hcd_resume_root_hub(shared_hcd); + usb_disable_autosuspend(shared_hcd->self.root_hub); + } + break; + case PM_POST_RESTORE: + usb_enable_autosuspend(hcd->self.root_hub); + usb_enable_autosuspend(shared_hcd->self.root_hub); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static int cdns_register_pm_notifier(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + cdns3_hiber_data.hcd = xhci->main_hcd; + cdns3_hiber_data.shared_hcd = xhci->shared_hcd; + cdns3_hiber_data.pm_notifier.notifier_call = cdns_hiber_notifier; + return register_pm_notifier(&cdns3_hiber_data.pm_notifier); +} + +static int cdns_unregister_pm_notifier(struct cdns *cdns) +{ + int ret; + + ret = unregister_pm_notifier(&cdns3_hiber_data.pm_notifier); + + cdns3_hiber_data.hcd = NULL; + cdns3_hiber_data.shared_hcd = NULL; + + return ret; +} +#endif + static int __cdns_host_init(struct cdns *cdns) { struct platform_device *xhci; @@ -91,6 +161,12 @@ static int __cdns_host_init(struct cdns *cdns) if (cdns->pdata && (cdns->pdata->quirks & CDNS3_DEFAULT_PM_RUNTIME_ALLOW)) cdns->xhci_plat_data->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; +#ifdef CONFIG_PM_SLEEP + if (cdns->pdata && (cdns->pdata->quirks & CDNS3_REGISTER_PM_NOTIFIER)) { + cdns3_hiber_data.pm_setup = cdns_register_pm_notifier; + cdns3_hiber_data.pm_remove = cdns_unregister_pm_notifier; + } +#endif ret = platform_device_add_data(xhci, cdns->xhci_plat_data, sizeof(struct xhci_plat_priv)); if (ret) @@ -118,6 +194,14 @@ err1: static void cdns_host_exit(struct cdns *cdns) { +#ifdef CONFIG_PM_SLEEP + if (cdns3_hiber_data.pm_remove) { + cdns3_hiber_data.pm_remove(cdns); + cdns3_hiber_data.pm_remove = NULL; + cdns3_hiber_data.pm_setup = NULL; + } +#endif + kfree(cdns->xhci_plat_data); platform_device_unregister(cdns->host_dev); cdns->host_dev = NULL;