aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/qcom/clk-krait.c2
-rw-r--r--drivers/clk/qcom/clk-krait.h3
-rw-r--r--drivers/clk/qcom/krait-cc.c56
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 */
33static 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
59static 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
29static int 72static int
30krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) 73krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
31{ 74{
@@ -70,6 +113,7 @@ static int
70krait_add_sec_mux(struct device *dev, int id, const char *s, 113krait_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
160unique_aux:
111 if (unique_aux) 161 if (unique_aux)
112 kfree(sec_mux_list[0]); 162 kfree(sec_mux_list[0]);
113err_aux: 163err_aux:
@@ -119,6 +169,7 @@ static struct clk *
119krait_add_pri_mux(struct device *dev, int id, const char *s, 169krait_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;
222err_p3:
167 kfree(p_names[2]); 223 kfree(p_names[2]);
168err_p2: 224err_p2:
169 kfree(p_names[1]); 225 kfree(p_names[1]);