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

clk: ux500: Support is_prepared callback for clk-prcmu

To be able to gate unused prcmu clocks from the clk_disable_unused sequence,
clk-prcmu now implements the is_prepared callback.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Ulf Hansson and committed by
Mike Turquette
2850985f 3cc8247f

+78 -52
+78 -52
drivers/clk/ux500/clk-prcmu.c
··· 20 20 struct clk_prcmu { 21 21 struct clk_hw hw; 22 22 u8 cg_sel; 23 + int is_prepared; 23 24 int is_enabled; 25 + int opp_requested; 24 26 }; 25 27 26 28 /* PRCMU clock operations. */ 27 29 28 30 static int clk_prcmu_prepare(struct clk_hw *hw) 29 31 { 32 + int ret; 30 33 struct clk_prcmu *clk = to_clk_prcmu(hw); 31 - return prcmu_request_clock(clk->cg_sel, true); 34 + 35 + ret = prcmu_request_clock(clk->cg_sel, true); 36 + if (!ret) 37 + clk->is_prepared = 1; 38 + 39 + return ret;; 32 40 } 33 41 34 42 static void clk_prcmu_unprepare(struct clk_hw *hw) ··· 45 37 if (prcmu_request_clock(clk->cg_sel, false)) 46 38 pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 47 39 hw->init->name); 40 + else 41 + clk->is_prepared = 0; 42 + } 43 + 44 + static int clk_prcmu_is_prepared(struct clk_hw *hw) 45 + { 46 + struct clk_prcmu *clk = to_clk_prcmu(hw); 47 + return clk->is_prepared; 48 48 } 49 49 50 50 static int clk_prcmu_enable(struct clk_hw *hw) ··· 95 79 return prcmu_set_clock_rate(clk->cg_sel, rate); 96 80 } 97 81 98 - static int request_ape_opp100(bool enable) 99 - { 100 - static int reqs; 101 - int err = 0; 102 - 103 - if (enable) { 104 - if (!reqs) 105 - err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, 106 - "clock", 100); 107 - if (!err) 108 - reqs++; 109 - } else { 110 - reqs--; 111 - if (!reqs) 112 - prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, 113 - "clock"); 114 - } 115 - return err; 116 - } 117 - 118 82 static int clk_prcmu_opp_prepare(struct clk_hw *hw) 119 83 { 120 84 int err; 121 85 struct clk_prcmu *clk = to_clk_prcmu(hw); 122 86 123 - err = request_ape_opp100(true); 124 - if (err) { 125 - pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n", 126 - __func__, hw->init->name); 127 - return err; 87 + if (!clk->opp_requested) { 88 + err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, 89 + (char *)__clk_get_name(hw->clk), 90 + 100); 91 + if (err) { 92 + pr_err("clk_prcmu: %s fail req APE OPP for %s.\n", 93 + __func__, hw->init->name); 94 + return err; 95 + } 96 + clk->opp_requested = 1; 128 97 } 129 98 130 99 err = prcmu_request_clock(clk->cg_sel, true); 131 - if (err) 132 - request_ape_opp100(false); 100 + if (err) { 101 + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, 102 + (char *)__clk_get_name(hw->clk)); 103 + clk->opp_requested = 0; 104 + return err; 105 + } 133 106 134 - return err; 107 + clk->is_prepared = 1; 108 + return 0; 135 109 } 136 110 137 111 static void clk_prcmu_opp_unprepare(struct clk_hw *hw) 138 112 { 139 113 struct clk_prcmu *clk = to_clk_prcmu(hw); 140 114 141 - if (prcmu_request_clock(clk->cg_sel, false)) 142 - goto out_error; 143 - if (request_ape_opp100(false)) 144 - goto out_error; 145 - return; 115 + if (prcmu_request_clock(clk->cg_sel, false)) { 116 + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 117 + hw->init->name); 118 + return; 119 + } 146 120 147 - out_error: 148 - pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 149 - hw->init->name); 121 + if (clk->opp_requested) { 122 + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, 123 + (char *)__clk_get_name(hw->clk)); 124 + clk->opp_requested = 0; 125 + } 126 + 127 + clk->is_prepared = 0; 150 128 } 151 129 152 130 static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) ··· 148 138 int err; 149 139 struct clk_prcmu *clk = to_clk_prcmu(hw); 150 140 151 - err = prcmu_request_ape_opp_100_voltage(true); 152 - if (err) { 153 - pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n", 154 - __func__, hw->init->name); 155 - return err; 141 + if (!clk->opp_requested) { 142 + err = prcmu_request_ape_opp_100_voltage(true); 143 + if (err) { 144 + pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n", 145 + __func__, hw->init->name); 146 + return err; 147 + } 148 + clk->opp_requested = 1; 156 149 } 157 150 158 151 err = prcmu_request_clock(clk->cg_sel, true); 159 - if (err) 152 + if (err) { 160 153 prcmu_request_ape_opp_100_voltage(false); 154 + clk->opp_requested = 0; 155 + return err; 156 + } 161 157 162 - return err; 158 + clk->is_prepared = 1; 159 + return 0; 163 160 } 164 161 165 162 static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) 166 163 { 167 164 struct clk_prcmu *clk = to_clk_prcmu(hw); 168 165 169 - if (prcmu_request_clock(clk->cg_sel, false)) 170 - goto out_error; 171 - if (prcmu_request_ape_opp_100_voltage(false)) 172 - goto out_error; 173 - return; 166 + if (prcmu_request_clock(clk->cg_sel, false)) { 167 + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 168 + hw->init->name); 169 + return; 170 + } 174 171 175 - out_error: 176 - pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, 177 - hw->init->name); 172 + if (clk->opp_requested) { 173 + prcmu_request_ape_opp_100_voltage(false); 174 + clk->opp_requested = 0; 175 + } 176 + 177 + clk->is_prepared = 0; 178 178 } 179 179 180 180 static struct clk_ops clk_prcmu_scalable_ops = { 181 181 .prepare = clk_prcmu_prepare, 182 182 .unprepare = clk_prcmu_unprepare, 183 + .is_prepared = clk_prcmu_is_prepared, 183 184 .enable = clk_prcmu_enable, 184 185 .disable = clk_prcmu_disable, 185 186 .is_enabled = clk_prcmu_is_enabled, ··· 202 181 static struct clk_ops clk_prcmu_gate_ops = { 203 182 .prepare = clk_prcmu_prepare, 204 183 .unprepare = clk_prcmu_unprepare, 184 + .is_prepared = clk_prcmu_is_prepared, 205 185 .enable = clk_prcmu_enable, 206 186 .disable = clk_prcmu_disable, 207 187 .is_enabled = clk_prcmu_is_enabled, ··· 224 202 static struct clk_ops clk_prcmu_opp_gate_ops = { 225 203 .prepare = clk_prcmu_opp_prepare, 226 204 .unprepare = clk_prcmu_opp_unprepare, 205 + .is_prepared = clk_prcmu_is_prepared, 227 206 .enable = clk_prcmu_enable, 228 207 .disable = clk_prcmu_disable, 229 208 .is_enabled = clk_prcmu_is_enabled, ··· 234 211 static struct clk_ops clk_prcmu_opp_volt_scalable_ops = { 235 212 .prepare = clk_prcmu_opp_volt_prepare, 236 213 .unprepare = clk_prcmu_opp_volt_unprepare, 214 + .is_prepared = clk_prcmu_is_prepared, 237 215 .enable = clk_prcmu_enable, 238 216 .disable = clk_prcmu_disable, 239 217 .is_enabled = clk_prcmu_is_enabled, ··· 266 242 } 267 243 268 244 clk->cg_sel = cg_sel; 245 + clk->is_prepared = 1; 269 246 clk->is_enabled = 1; 247 + clk->opp_requested = 0; 270 248 /* "rate" can be used for changing the initial frequency */ 271 249 if (rate) 272 250 prcmu_set_clock_rate(cg_sel, rate);