summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/qcom/common.c3
-rw-r--r--drivers/clk/qcom/gdsc.c35
-rw-r--r--drivers/clk/qcom/gdsc.h11
3 files changed, 46 insertions, 3 deletions
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index dc51a63c9625..150692879e92 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -125,7 +125,8 @@ int qcom_cc_really_probe(struct platform_device *pdev,
goto err_reset;
if (desc->gdscs && desc->num_gdscs) {
- ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, regmap);
+ ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs,
+ &reset->rcdev, regmap);
if (ret)
goto err_pd;
}
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index e6bbb7608b57..da9fad8b642b 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/pm_domain.h>
#include <linux/regmap.h>
+#include <linux/reset-controller.h>
#include <linux/slab.h>
#include "gdsc.h"
@@ -84,6 +85,24 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
return -ETIMEDOUT;
}
+static inline int gdsc_deassert_reset(struct gdsc *sc)
+{
+ int i;
+
+ for (i = 0; i < sc->reset_count; i++)
+ sc->rcdev->ops->deassert(sc->rcdev, sc->resets[i]);
+ return 0;
+}
+
+static inline int gdsc_assert_reset(struct gdsc *sc)
+{
+ int i;
+
+ for (i = 0; i < sc->reset_count; i++)
+ sc->rcdev->ops->assert(sc->rcdev, sc->resets[i]);
+ return 0;
+}
+
static inline void gdsc_force_mem_on(struct gdsc *sc)
{
int i;
@@ -107,6 +126,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
struct gdsc *sc = domain_to_gdsc(domain);
int ret;
+ if (sc->pwrsts == PWRSTS_ON)
+ return gdsc_deassert_reset(sc);
+
ret = gdsc_toggle_logic(sc, true);
if (ret)
return ret;
@@ -130,6 +152,9 @@ static int gdsc_disable(struct generic_pm_domain *domain)
{
struct gdsc *sc = domain_to_gdsc(domain);
+ if (sc->pwrsts == PWRSTS_ON)
+ return gdsc_assert_reset(sc);
+
if (sc->pwrsts & PWRSTS_OFF)
gdsc_clear_mem_on(sc);
@@ -153,6 +178,13 @@ static int gdsc_init(struct gdsc *sc)
if (ret)
return ret;
+ /* Force gdsc ON if only ON state is supported */
+ if (sc->pwrsts == PWRSTS_ON) {
+ ret = gdsc_toggle_logic(sc, true);
+ if (ret)
+ return ret;
+ }
+
on = gdsc_is_enabled(sc);
if (on < 0)
return on;
@@ -170,7 +202,7 @@ static int gdsc_init(struct gdsc *sc)
}
int gdsc_register(struct device *dev, struct gdsc **scs, size_t num,
- struct regmap *regmap)
+ struct reset_controller_dev *rcdev, struct regmap *regmap)
{
int i, ret;
struct genpd_onecell_data *data;
@@ -189,6 +221,7 @@ int gdsc_register(struct device *dev, struct gdsc **scs, size_t num,
if (!scs[i])
continue;
scs[i]->regmap = regmap;
+ scs[i]->rcdev = rcdev;
ret = gdsc_init(scs[i]);
if (ret)
return ret;
diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h
index 0ff251a5523f..5ded26884f08 100644
--- a/drivers/clk/qcom/gdsc.h
+++ b/drivers/clk/qcom/gdsc.h
@@ -18,6 +18,7 @@
#include <linux/pm_domain.h>
struct regmap;
+struct reset_controller_dev;
/* Powerdomain allowable state bitfields */
#define PWRSTS_OFF BIT(0)
@@ -34,6 +35,9 @@ struct regmap;
* @cxcs: offsets of branch registers to toggle mem/periph bits in
* @cxc_count: number of @cxcs
* @pwrsts: Possible powerdomain power states
+ * @resets: ids of resets associated with this gdsc
+ * @reset_count: number of @resets
+ * @rcdev: reset controller
*/
struct gdsc {
struct generic_pm_domain pd;
@@ -42,13 +46,18 @@ struct gdsc {
unsigned int *cxcs;
unsigned int cxc_count;
const u8 pwrsts;
+ struct reset_controller_dev *rcdev;
+ unsigned int *resets;
+ unsigned int reset_count;
};
#ifdef CONFIG_QCOM_GDSC
-int gdsc_register(struct device *, struct gdsc **, size_t n, struct regmap *);
+int gdsc_register(struct device *, struct gdsc **, size_t n,
+ struct reset_controller_dev *, struct regmap *);
void gdsc_unregister(struct device *);
#else
static inline int gdsc_register(struct device *d, struct gdsc **g, size_t n,
+ struct reset_controller_dev *rcdev,
struct regmap *r)
{
return -ENOSYS;