diff options
| -rw-r--r-- | drivers/clk/qcom/clk-krait.c | 2 | ||||
| -rw-r--r-- | drivers/clk/qcom/clk-krait.h | 3 | ||||
| -rw-r--r-- | drivers/clk/qcom/krait-cc.c | 56 |
3 files changed, 61 insertions, 0 deletions
diff --git a/drivers/clk/qcom/clk-krait.c b/drivers/clk/qcom/clk-krait.c index 7ede744c6a14..59f1af415b58 100644 --- a/drivers/clk/qcom/clk-krait.c +++ b/drivers/clk/qcom/clk-krait.c | |||
| @@ -50,6 +50,8 @@ static int krait_mux_set_parent(struct clk_hw *hw, u8 index) | |||
| 50 | if (__clk_is_enabled(hw->clk)) | 50 | if (__clk_is_enabled(hw->clk)) |
| 51 | __krait_mux_set_sel(mux, sel); | 51 | __krait_mux_set_sel(mux, sel); |
| 52 | 52 | ||
| 53 | mux->reparent = true; | ||
| 54 | |||
| 53 | return 0; | 55 | return 0; |
| 54 | } | 56 | } |
| 55 | 57 | ||
diff --git a/drivers/clk/qcom/clk-krait.h b/drivers/clk/qcom/clk-krait.h index 441ba1e18b81..9120bd2f5297 100644 --- a/drivers/clk/qcom/clk-krait.h +++ b/drivers/clk/qcom/clk-krait.h | |||
| @@ -12,6 +12,9 @@ struct krait_mux_clk { | |||
| 12 | u32 shift; | 12 | u32 shift; |
| 13 | u32 en_mask; | 13 | u32 en_mask; |
| 14 | bool lpl; | 14 | bool lpl; |
| 15 | u8 safe_sel; | ||
| 16 | u8 old_index; | ||
| 17 | bool reparent; | ||
| 15 | 18 | ||
| 16 | struct clk_hw hw; | 19 | struct clk_hw hw; |
| 17 | struct notifier_block clk_nb; | 20 | struct notifier_block clk_nb; |
diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c index 7c9dfb032065..4d4b657d33c3 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c | |||
| @@ -26,6 +26,49 @@ static unsigned int pri_mux_map[] = { | |||
| 26 | 0, | 26 | 0, |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | /* | ||
| 30 | * Notifier function for switching the muxes to safe parent | ||
| 31 | * while the hfpll is getting reprogrammed. | ||
| 32 | */ | ||
| 33 | static int krait_notifier_cb(struct notifier_block *nb, | ||
| 34 | unsigned long event, | ||
| 35 | void *data) | ||
| 36 | { | ||
| 37 | int ret = 0; | ||
| 38 | struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk, | ||
| 39 | clk_nb); | ||
| 40 | /* Switch to safe parent */ | ||
| 41 | if (event == PRE_RATE_CHANGE) { | ||
| 42 | mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw); | ||
| 43 | ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel); | ||
| 44 | mux->reparent = false; | ||
| 45 | /* | ||
| 46 | * By the time POST_RATE_CHANGE notifier is called, | ||
| 47 | * clk framework itself would have changed the parent for the new rate. | ||
| 48 | * Only otherwise, put back to the old parent. | ||
| 49 | */ | ||
| 50 | } else if (event == POST_RATE_CHANGE) { | ||
| 51 | if (!mux->reparent) | ||
| 52 | ret = krait_mux_clk_ops.set_parent(&mux->hw, | ||
| 53 | mux->old_index); | ||
| 54 | } | ||
| 55 | |||
| 56 | return notifier_from_errno(ret); | ||
| 57 | } | ||
| 58 | |||
| 59 | static int krait_notifier_register(struct device *dev, struct clk *clk, | ||
| 60 | struct krait_mux_clk *mux) | ||
| 61 | { | ||
| 62 | int ret = 0; | ||
| 63 | |||
| 64 | mux->clk_nb.notifier_call = krait_notifier_cb; | ||
| 65 | ret = clk_notifier_register(clk, &mux->clk_nb); | ||
| 66 | if (ret) | ||
| 67 | dev_err(dev, "failed to register clock notifier: %d\n", ret); | ||
| 68 | |||
| 69 | return ret; | ||
| 70 | } | ||
| 71 | |||
| 29 | static int | 72 | static int |
| 30 | krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) | 73 | krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) |
| 31 | { | 74 | { |
| @@ -70,6 +113,7 @@ static int | |||
| 70 | krait_add_sec_mux(struct device *dev, int id, const char *s, | 113 | krait_add_sec_mux(struct device *dev, int id, const char *s, |
| 71 | unsigned int offset, bool unique_aux) | 114 | unsigned int offset, bool unique_aux) |
| 72 | { | 115 | { |
| 116 | int ret; | ||
| 73 | struct krait_mux_clk *mux; | 117 | struct krait_mux_clk *mux; |
| 74 | static const char *sec_mux_list[] = { | 118 | static const char *sec_mux_list[] = { |
| 75 | "acpu_aux", | 119 | "acpu_aux", |
| @@ -93,6 +137,7 @@ krait_add_sec_mux(struct device *dev, int id, const char *s, | |||
| 93 | mux->shift = 2; | 137 | mux->shift = 2; |
| 94 | mux->parent_map = sec_mux_map; | 138 | mux->parent_map = sec_mux_map; |
| 95 | mux->hw.init = &init; | 139 | mux->hw.init = &init; |
| 140 | mux->safe_sel = 0; | ||
| 96 | 141 | ||
| 97 | init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); | 142 | init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); |
| 98 | if (!init.name) | 143 | if (!init.name) |
| @@ -108,6 +153,11 @@ krait_add_sec_mux(struct device *dev, int id, const char *s, | |||
| 108 | 153 | ||
| 109 | clk = devm_clk_register(dev, &mux->hw); | 154 | clk = devm_clk_register(dev, &mux->hw); |
| 110 | 155 | ||
| 156 | ret = krait_notifier_register(dev, clk, mux); | ||
| 157 | if (ret) | ||
| 158 | goto unique_aux; | ||
| 159 | |||
| 160 | unique_aux: | ||
| 111 | if (unique_aux) | 161 | if (unique_aux) |
| 112 | kfree(sec_mux_list[0]); | 162 | kfree(sec_mux_list[0]); |
| 113 | err_aux: | 163 | err_aux: |
| @@ -119,6 +169,7 @@ static struct clk * | |||
| 119 | krait_add_pri_mux(struct device *dev, int id, const char *s, | 169 | krait_add_pri_mux(struct device *dev, int id, const char *s, |
| 120 | unsigned int offset) | 170 | unsigned int offset) |
| 121 | { | 171 | { |
| 172 | int ret; | ||
| 122 | struct krait_mux_clk *mux; | 173 | struct krait_mux_clk *mux; |
| 123 | const char *p_names[3]; | 174 | const char *p_names[3]; |
| 124 | struct clk_init_data init = { | 175 | struct clk_init_data init = { |
| @@ -139,6 +190,7 @@ krait_add_pri_mux(struct device *dev, int id, const char *s, | |||
| 139 | mux->lpl = id >= 0; | 190 | mux->lpl = id >= 0; |
| 140 | mux->parent_map = pri_mux_map; | 191 | mux->parent_map = pri_mux_map; |
| 141 | mux->hw.init = &init; | 192 | mux->hw.init = &init; |
| 193 | mux->safe_sel = 2; | ||
| 142 | 194 | ||
| 143 | init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s); | 195 | init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s); |
| 144 | if (!init.name) | 196 | if (!init.name) |
| @@ -164,6 +216,10 @@ krait_add_pri_mux(struct device *dev, int id, const char *s, | |||
| 164 | 216 | ||
| 165 | clk = devm_clk_register(dev, &mux->hw); | 217 | clk = devm_clk_register(dev, &mux->hw); |
| 166 | 218 | ||
| 219 | ret = krait_notifier_register(dev, clk, mux); | ||
| 220 | if (ret) | ||
| 221 | goto err_p3; | ||
| 222 | err_p3: | ||
| 167 | kfree(p_names[2]); | 223 | kfree(p_names[2]); |
| 168 | err_p2: | 224 | err_p2: |
| 169 | kfree(p_names[1]); | 225 | kfree(p_names[1]); |
