aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/rockchip/clk-mmc-phase.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index fe7d9ed1d436..dc4c227732bd 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -25,6 +25,8 @@ struct rockchip_mmc_clock {
25 void __iomem *reg; 25 void __iomem *reg;
26 int id; 26 int id;
27 int shift; 27 int shift;
28 int cached_phase;
29 struct notifier_block clk_rate_change_nb;
28}; 30};
29 31
30#define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw) 32#define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw)
@@ -162,6 +164,29 @@ static const struct clk_ops rockchip_mmc_clk_ops = {
162 .set_phase = rockchip_mmc_set_phase, 164 .set_phase = rockchip_mmc_set_phase,
163}; 165};
164 166
167#define to_rockchip_mmc_clock(x) \
168 container_of(x, struct rockchip_mmc_clock, clk_rate_change_nb)
169static int rockchip_mmc_clk_rate_notify(struct notifier_block *nb,
170 unsigned long event, void *data)
171{
172 struct rockchip_mmc_clock *mmc_clock = to_rockchip_mmc_clock(nb);
173
174 /*
175 * rockchip_mmc_clk is mostly used by mmc controllers to sample
176 * the intput data, which expects the fixed phase after the tuning
177 * process. However if the clock rate is changed, the phase is stale
178 * and may break the data sampling. So here we try to restore the phase
179 * for that case.
180 */
181 if (event == PRE_RATE_CHANGE)
182 mmc_clock->cached_phase =
183 rockchip_mmc_get_phase(&mmc_clock->hw);
184 else if (event == POST_RATE_CHANGE)
185 rockchip_mmc_set_phase(&mmc_clock->hw, mmc_clock->cached_phase);
186
187 return NOTIFY_DONE;
188}
189
165struct clk *rockchip_clk_register_mmc(const char *name, 190struct clk *rockchip_clk_register_mmc(const char *name,
166 const char *const *parent_names, u8 num_parents, 191 const char *const *parent_names, u8 num_parents,
167 void __iomem *reg, int shift) 192 void __iomem *reg, int shift)
@@ -169,6 +194,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
169 struct clk_init_data init; 194 struct clk_init_data init;
170 struct rockchip_mmc_clock *mmc_clock; 195 struct rockchip_mmc_clock *mmc_clock;
171 struct clk *clk; 196 struct clk *clk;
197 int ret;
172 198
173 mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL); 199 mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL);
174 if (!mmc_clock) 200 if (!mmc_clock)
@@ -186,7 +212,18 @@ struct clk *rockchip_clk_register_mmc(const char *name,
186 212
187 clk = clk_register(NULL, &mmc_clock->hw); 213 clk = clk_register(NULL, &mmc_clock->hw);
188 if (IS_ERR(clk)) 214 if (IS_ERR(clk))
189 kfree(mmc_clock); 215 goto err_register;
190 216
217 mmc_clock->clk_rate_change_nb.notifier_call =
218 &rockchip_mmc_clk_rate_notify;
219 ret = clk_notifier_register(clk, &mmc_clock->clk_rate_change_nb);
220 if (ret)
221 goto err_notifier;
222
223 return clk;
224err_notifier:
225 clk_unregister(clk);
226err_register:
227 kfree(mmc_clock);
191 return clk; 228 return clk;
192} 229}