Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: qcom: gdsc: Add support for ON only state

Certain devices can have GDSCs' which support ON as the only state.
They can't be power collapsed to either hit RET or OFF.
The clients drivers for these GDSCs' however would expect the state
of the core to be reset following a GDSC disable and re-enable.
To do this assert/deassert reset lines every time the client
driver would request the GDSC to be powered on/off instead.

Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Rajendra Nayak and committed by
Stephen Boyd
3c53f5e2 014e193c

+46 -3
+2 -1
drivers/clk/qcom/common.c
··· 125 125 goto err_reset; 126 126 127 127 if (desc->gdscs && desc->num_gdscs) { 128 - ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, regmap); 128 + ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, 129 + &reset->rcdev, regmap); 129 130 if (ret) 130 131 goto err_pd; 131 132 }
+34 -1
drivers/clk/qcom/gdsc.c
··· 18 18 #include <linux/kernel.h> 19 19 #include <linux/pm_domain.h> 20 20 #include <linux/regmap.h> 21 + #include <linux/reset-controller.h> 21 22 #include <linux/slab.h> 22 23 #include "gdsc.h" 23 24 ··· 85 84 return -ETIMEDOUT; 86 85 } 87 86 87 + static inline int gdsc_deassert_reset(struct gdsc *sc) 88 + { 89 + int i; 90 + 91 + for (i = 0; i < sc->reset_count; i++) 92 + sc->rcdev->ops->deassert(sc->rcdev, sc->resets[i]); 93 + return 0; 94 + } 95 + 96 + static inline int gdsc_assert_reset(struct gdsc *sc) 97 + { 98 + int i; 99 + 100 + for (i = 0; i < sc->reset_count; i++) 101 + sc->rcdev->ops->assert(sc->rcdev, sc->resets[i]); 102 + return 0; 103 + } 104 + 88 105 static inline void gdsc_force_mem_on(struct gdsc *sc) 89 106 { 90 107 int i; ··· 125 106 { 126 107 struct gdsc *sc = domain_to_gdsc(domain); 127 108 int ret; 109 + 110 + if (sc->pwrsts == PWRSTS_ON) 111 + return gdsc_deassert_reset(sc); 128 112 129 113 ret = gdsc_toggle_logic(sc, true); 130 114 if (ret) ··· 152 130 { 153 131 struct gdsc *sc = domain_to_gdsc(domain); 154 132 133 + if (sc->pwrsts == PWRSTS_ON) 134 + return gdsc_assert_reset(sc); 135 + 155 136 if (sc->pwrsts & PWRSTS_OFF) 156 137 gdsc_clear_mem_on(sc); 157 138 ··· 178 153 if (ret) 179 154 return ret; 180 155 156 + /* Force gdsc ON if only ON state is supported */ 157 + if (sc->pwrsts == PWRSTS_ON) { 158 + ret = gdsc_toggle_logic(sc, true); 159 + if (ret) 160 + return ret; 161 + } 162 + 181 163 on = gdsc_is_enabled(sc); 182 164 if (on < 0) 183 165 return on; ··· 202 170 } 203 171 204 172 int gdsc_register(struct device *dev, struct gdsc **scs, size_t num, 205 - struct regmap *regmap) 173 + struct reset_controller_dev *rcdev, struct regmap *regmap) 206 174 { 207 175 int i, ret; 208 176 struct genpd_onecell_data *data; ··· 221 189 if (!scs[i]) 222 190 continue; 223 191 scs[i]->regmap = regmap; 192 + scs[i]->rcdev = rcdev; 224 193 ret = gdsc_init(scs[i]); 225 194 if (ret) 226 195 return ret;
+10 -1
drivers/clk/qcom/gdsc.h
··· 18 18 #include <linux/pm_domain.h> 19 19 20 20 struct regmap; 21 + struct reset_controller_dev; 21 22 22 23 /* Powerdomain allowable state bitfields */ 23 24 #define PWRSTS_OFF BIT(0) ··· 35 34 * @cxcs: offsets of branch registers to toggle mem/periph bits in 36 35 * @cxc_count: number of @cxcs 37 36 * @pwrsts: Possible powerdomain power states 37 + * @resets: ids of resets associated with this gdsc 38 + * @reset_count: number of @resets 39 + * @rcdev: reset controller 38 40 */ 39 41 struct gdsc { 40 42 struct generic_pm_domain pd; ··· 46 42 unsigned int *cxcs; 47 43 unsigned int cxc_count; 48 44 const u8 pwrsts; 45 + struct reset_controller_dev *rcdev; 46 + unsigned int *resets; 47 + unsigned int reset_count; 49 48 }; 50 49 51 50 #ifdef CONFIG_QCOM_GDSC 52 - int gdsc_register(struct device *, struct gdsc **, size_t n, struct regmap *); 51 + int gdsc_register(struct device *, struct gdsc **, size_t n, 52 + struct reset_controller_dev *, struct regmap *); 53 53 void gdsc_unregister(struct device *); 54 54 #else 55 55 static inline int gdsc_register(struct device *d, struct gdsc **g, size_t n, 56 + struct reset_controller_dev *rcdev, 56 57 struct regmap *r) 57 58 { 58 59 return -ENOSYS;