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]); |