summaryrefslogtreecommitdiffstats
path: root/drivers/clk/qcom/gdsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/qcom/gdsc.c')
-rw-r--r--drivers/clk/qcom/gdsc.c98
1 files changed, 74 insertions, 24 deletions
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index fa5fe4c2a2ee..7deabf8400cf 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -46,7 +46,7 @@
#define RETAIN_MEM BIT(14)
#define RETAIN_PERIPH BIT(13)
-#define STATUS_POLL_TIMEOUT_US 1500
+#define STATUS_POLL_TIMEOUT_US 2000
#define TIMEOUT_US 500
#define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
@@ -292,6 +292,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
*/
udelay(1);
+ if (sc->flags & RETAIN_FF_ENABLE)
+ gdsc_retain_ff_on(sc);
+
/* Turn on HW trigger mode if supported */
if (sc->flags & HW_CTRL) {
ret = gdsc_hwctrl(sc, true);
@@ -308,9 +311,6 @@ static int gdsc_enable(struct generic_pm_domain *domain)
udelay(1);
}
- if (sc->flags & RETAIN_FF_ENABLE)
- gdsc_retain_ff_on(sc);
-
return 0;
}
@@ -457,13 +457,6 @@ static int gdsc_init(struct gdsc *sc)
goto err_disable_supply;
}
- /* Turn on HW trigger mode if supported */
- if (sc->flags & HW_CTRL) {
- ret = gdsc_hwctrl(sc, true);
- if (ret < 0)
- goto err_disable_supply;
- }
-
/*
* Make sure the retain bit is set if the GDSC is already on,
* otherwise we end up turning off the GDSC and destroying all
@@ -471,6 +464,14 @@ static int gdsc_init(struct gdsc *sc)
*/
if (sc->flags & RETAIN_FF_ENABLE)
gdsc_retain_ff_on(sc);
+
+ /* Turn on HW trigger mode if supported */
+ if (sc->flags & HW_CTRL) {
+ ret = gdsc_hwctrl(sc, true);
+ if (ret < 0)
+ goto err_disable_supply;
+ }
+
} else if (sc->flags & ALWAYS_ON) {
/* If ALWAYS_ON GDSCs are not ON, turn them ON */
gdsc_enable(&sc->pd);
@@ -506,6 +507,55 @@ err_disable_supply:
return ret;
}
+static int gdsc_add_subdomain_list(struct dev_pm_domain_list *pd_list,
+ struct generic_pm_domain *subdomain)
+{
+ int i, ret;
+
+ for (i = 0; i < pd_list->num_pds; i++) {
+ struct device *dev = pd_list->pd_devs[i];
+ struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
+
+ ret = pm_genpd_add_subdomain(genpd, subdomain);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void gdsc_remove_subdomain_list(struct dev_pm_domain_list *pd_list,
+ struct generic_pm_domain *subdomain)
+{
+ int i;
+
+ for (i = 0; i < pd_list->num_pds; i++) {
+ struct device *dev = pd_list->pd_devs[i];
+ struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
+
+ pm_genpd_remove_subdomain(genpd, subdomain);
+ }
+}
+
+static void gdsc_pm_subdomain_remove(struct gdsc_desc *desc, size_t num)
+{
+ struct device *dev = desc->dev;
+ struct gdsc **scs = desc->scs;
+ int i;
+
+ /* Remove subdomains */
+ for (i = num - 1; i >= 0; i--) {
+ if (!scs[i])
+ continue;
+ if (scs[i]->parent)
+ pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd);
+ else if (!IS_ERR_OR_NULL(dev->pm_domain))
+ pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
+ else if (desc->pd_list)
+ gdsc_remove_subdomain_list(desc->pd_list, &scs[i]->pd);
+ }
+}
+
int gdsc_register(struct gdsc_desc *desc,
struct reset_controller_dev *rcdev, struct regmap *regmap)
{
@@ -555,30 +605,30 @@ int gdsc_register(struct gdsc_desc *desc,
if (!scs[i])
continue;
if (scs[i]->parent)
- pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd);
+ ret = pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd);
else if (!IS_ERR_OR_NULL(dev->pm_domain))
- pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
+ ret = pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
+ else if (desc->pd_list)
+ ret = gdsc_add_subdomain_list(desc->pd_list, &scs[i]->pd);
+
+ if (ret)
+ goto err_pm_subdomain_remove;
}
return of_genpd_add_provider_onecell(dev->of_node, data);
+
+err_pm_subdomain_remove:
+ gdsc_pm_subdomain_remove(desc, i);
+
+ return ret;
}
void gdsc_unregister(struct gdsc_desc *desc)
{
- int i;
struct device *dev = desc->dev;
- struct gdsc **scs = desc->scs;
size_t num = desc->num;
- /* Remove subdomains */
- for (i = 0; i < num; i++) {
- if (!scs[i])
- continue;
- if (scs[i]->parent)
- pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd);
- else if (!IS_ERR_OR_NULL(dev->pm_domain))
- pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
- }
+ gdsc_pm_subdomain_remove(desc, num);
of_genpd_del_provider(dev->of_node);
}