Skip to content

Commit 42fed57

Browse files
alcoopervinodkoul
authored andcommitted
phy: usb: Leave some clocks running during suspend
The PHY client driver does a phy_exit() call on suspend or rmmod and the PHY driver needs to know the difference because some clocks need to be kept running for suspend but can be shutdown on unbind/rmmod (or if there are no PHY clients at all). The fix is to use a PM notifier so the driver can tell if a PHY client is calling exit() because of a system suspend or a driver unbind/rmmod. Signed-off-by: Al Cooper <[email protected]> Acked-by: Florian Fainelli <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent e783362 commit 42fed57

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

drivers/phy/broadcom/phy-brcm-usb.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/soc/brcmstb/brcmstb.h>
1919
#include <dt-bindings/phy/phy.h>
2020
#include <linux/mfd/syscon.h>
21+
#include <linux/suspend.h>
2122

2223
#include "phy-brcm-usb-init.h"
2324

@@ -70,12 +71,35 @@ struct brcm_usb_phy_data {
7071
int init_count;
7172
int wake_irq;
7273
struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX];
74+
struct notifier_block pm_notifier;
75+
bool pm_active;
7376
};
7477

7578
static s8 *node_reg_names[BRCM_REGS_MAX] = {
7679
"crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
7780
};
7881

82+
static int brcm_pm_notifier(struct notifier_block *notifier,
83+
unsigned long pm_event,
84+
void *unused)
85+
{
86+
struct brcm_usb_phy_data *priv =
87+
container_of(notifier, struct brcm_usb_phy_data, pm_notifier);
88+
89+
switch (pm_event) {
90+
case PM_HIBERNATION_PREPARE:
91+
case PM_SUSPEND_PREPARE:
92+
priv->pm_active = true;
93+
break;
94+
case PM_POST_RESTORE:
95+
case PM_POST_HIBERNATION:
96+
case PM_POST_SUSPEND:
97+
priv->pm_active = false;
98+
break;
99+
}
100+
return NOTIFY_DONE;
101+
}
102+
79103
static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
80104
{
81105
struct phy *gphy = dev_id;
@@ -91,6 +115,9 @@ static int brcm_usb_phy_init(struct phy *gphy)
91115
struct brcm_usb_phy_data *priv =
92116
container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
93117

118+
if (priv->pm_active)
119+
return 0;
120+
94121
/*
95122
* Use a lock to make sure a second caller waits until
96123
* the base phy is inited before using it.
@@ -120,6 +147,9 @@ static int brcm_usb_phy_exit(struct phy *gphy)
120147
struct brcm_usb_phy_data *priv =
121148
container_of(phy, struct brcm_usb_phy_data, phys[phy->id]);
122149

150+
if (priv->pm_active)
151+
return 0;
152+
123153
dev_dbg(&gphy->dev, "EXIT\n");
124154
if (phy->id == BRCM_USB_PHY_2_0)
125155
brcm_usb_uninit_eohci(&priv->ini);
@@ -488,6 +518,9 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
488518
if (err)
489519
return err;
490520

521+
priv->pm_notifier.notifier_call = brcm_pm_notifier;
522+
register_pm_notifier(&priv->pm_notifier);
523+
491524
mutex_init(&priv->mutex);
492525

493526
/* make sure invert settings are correct */
@@ -528,7 +561,10 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
528561

529562
static int brcm_usb_phy_remove(struct platform_device *pdev)
530563
{
564+
struct brcm_usb_phy_data *priv = dev_get_drvdata(&pdev->dev);
565+
531566
sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
567+
unregister_pm_notifier(&priv->pm_notifier);
532568

533569
return 0;
534570
}
@@ -539,6 +575,7 @@ static int brcm_usb_phy_suspend(struct device *dev)
539575
struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
540576

541577
if (priv->init_count) {
578+
dev_dbg(dev, "SUSPEND\n");
542579
priv->ini.wake_enabled = device_may_wakeup(dev);
543580
if (priv->phys[BRCM_USB_PHY_3_0].inited)
544581
brcm_usb_uninit_xhci(&priv->ini);
@@ -578,6 +615,7 @@ static int brcm_usb_phy_resume(struct device *dev)
578615
* Uninitialize anything that wasn't previously initialized.
579616
*/
580617
if (priv->init_count) {
618+
dev_dbg(dev, "RESUME\n");
581619
if (priv->wake_irq >= 0)
582620
disable_irq_wake(priv->wake_irq);
583621
brcm_usb_init_common(&priv->ini);

0 commit comments

Comments
 (0)