diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c index 6925c6865089c..df7f8cff9bd9d 100644 --- a/drivers/clk/qcom/gcc-glymur.c +++ b/drivers/clk/qcom/gcc-glymur.c @@ -7784,6 +7784,7 @@ static struct gdsc gcc_usb20_prim_gdsc = { .clk_dis_wait_val = 0xf, .pd = { .name = "gcc_usb20_prim_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7796,6 +7797,7 @@ static struct gdsc gcc_usb30_mp_gdsc = { .clk_dis_wait_val = 0xf, .pd = { .name = "gcc_usb30_mp_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7808,6 +7810,7 @@ static struct gdsc gcc_usb30_prim_gdsc = { .clk_dis_wait_val = 0xf, .pd = { .name = "gcc_usb30_prim_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7820,6 +7823,7 @@ static struct gdsc gcc_usb30_sec_gdsc = { .clk_dis_wait_val = 0xf, .pd = { .name = "gcc_usb30_sec_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7832,6 +7836,7 @@ static struct gdsc gcc_usb30_tert_gdsc = { .clk_dis_wait_val = 0xf, .pd = { .name = "gcc_usb30_tert_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7844,6 +7849,7 @@ static struct gdsc gcc_usb3_mp_ss0_phy_gdsc = { .clk_dis_wait_val = 0x2, .pd = { .name = "gcc_usb3_mp_ss0_phy_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7856,6 +7862,7 @@ static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = { .clk_dis_wait_val = 0x2, .pd = { .name = "gcc_usb3_mp_ss1_phy_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7904,6 +7911,7 @@ static struct gdsc gcc_usb_0_phy_gdsc = { .clk_dis_wait_val = 0x2, .pd = { .name = "gcc_usb_0_phy_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7916,6 +7924,7 @@ static struct gdsc gcc_usb_1_phy_gdsc = { .clk_dis_wait_val = 0x2, .pd = { .name = "gcc_usb_1_phy_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, @@ -7928,6 +7937,7 @@ static struct gdsc gcc_usb_2_phy_gdsc = { .clk_dis_wait_val = 0x2, .pd = { .name = "gcc_usb_2_phy_gdsc", + .power_off = gdsc_synced_poweroff_disable, }, .pwrsts = PWRSTS_OFF_ON, .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index f419a28f616b6..2f067d1eb9f19 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -730,3 +730,32 @@ int gdsc_gx_disable(struct generic_pm_domain *domain) return 0; } EXPORT_SYMBOL_GPL(gdsc_gx_disable); + +/* + * USB and PCIE GDSCs require GDSC to be kept ON even during system system + * for USB host mode and PCIE non-D3 cold usecases. The below callback can + * be used for such GDSCs where the consumer drivers can set GenPD's + * synced_poweroff flag using dev_pm_genpd_synced_poweroff() before suspend + * to disable the GDSC and can avoid setting the flag to keep the GDSC ON + * during suspend. + */ +int gdsc_synced_poweroff_disable(struct generic_pm_domain *domain) +{ + struct gdsc *sc = domain_to_gdsc(domain); + + /* + * For GDSCs with VOTABLE flag(e.g. PCIE), status must not be polled + * during disable. However, gdsc_disable() polls for status when + * synced_poweroff is set. Use gdsc_toggle_logic() with wait = false + * to skip status polling for VOTABLE GDSCs during power-off. + */ + if (domain->synced_poweroff) + return gdsc_toggle_logic(sc, GDSC_OFF, false); + + /* Remove parent-supply placed in enable */ + if (sc->rsupply) + return regulator_disable(sc->rsupply); + + return 0; +} +EXPORT_SYMBOL_GPL(gdsc_synced_poweroff_disable); diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 1acb5c97ccd96..d62f4b63172f8 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -94,7 +94,7 @@ int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *, void gdsc_unregister(struct gdsc_desc *desc); int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain); int gdsc_gx_disable(struct generic_pm_domain *domain); -#define gdsc_synced_poweroff_disable gdsc_gx_disable +int gdsc_synced_poweroff_disable(struct generic_pm_domain *domain); #else static inline int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *rcdev, @@ -104,5 +104,6 @@ static inline int gdsc_register(struct gdsc_desc *desc, } static inline void gdsc_unregister(struct gdsc_desc *desc) {}; +static int gdsc_synced_poweroff_disable(struct generic_pm_domain *domain) {}; #endif /* CONFIG_QCOM_GDSC */ #endif /* __QCOM_GDSC_H__ */