1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/slab.h>
17#include <linux/clk.h>
18#include <linux/clk-provider.h>
19#include <linux/io.h>
20#include <linux/kernel.h>
21#include "clk.h"
22
23struct rockchip_mmc_clock {
24 struct clk_hw hw;
25 void __iomem *reg;
26 int id;
27 int shift;
28 int cached_phase;
29 struct notifier_block clk_rate_change_nb;
30};
31
32#define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw)
33
34#define RK3288_MMC_CLKGEN_DIV 2
35
36static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
37 unsigned long parent_rate)
38{
39 return parent_rate / RK3288_MMC_CLKGEN_DIV;
40}
41
42#define ROCKCHIP_MMC_DELAY_SEL BIT(10)
43#define ROCKCHIP_MMC_DEGREE_MASK 0x3
44#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
45#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
46
47#define PSECS_PER_SEC 1000000000000LL
48
49
50
51
52
53#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
54
55static int rockchip_mmc_get_phase(struct clk_hw *hw)
56{
57 struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
58 unsigned long rate = clk_get_rate(hw->clk);
59 u32 raw_value;
60 u16 degrees;
61 u32 delay_num = 0;
62
63
64 if (!rate) {
65 pr_err("%s: invalid clk rate\n", __func__);
66 return -EINVAL;
67 }
68
69 raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift);
70
71 degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
72
73 if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
74
75 unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
76 36 * (rate / 1000000);
77
78 delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
79 delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
80 degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
81 }
82
83 return degrees % 360;
84}
85
86static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
87{
88 struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw);
89 unsigned long rate = clk_get_rate(hw->clk);
90 u8 nineties, remainder;
91 u8 delay_num;
92 u32 raw_value;
93 u32 delay;
94
95
96
97
98
99
100
101
102
103
104
105
106
107 if (!rate) {
108 pr_err("%s: invalid clk rate\n", __func__);
109 return -EINVAL;
110 }
111
112 nineties = degrees / 90;
113 remainder = (degrees % 90);
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 delay = 10000000;
139 delay *= remainder;
140 delay = DIV_ROUND_CLOSEST(delay,
141 (rate / 1000) * 36 *
142 (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
143
144 delay_num = (u8) min_t(u32, delay, 255);
145
146 raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
147 raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
148 raw_value |= nineties;
149 writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift),
150 mmc_clock->reg);
151
152 pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n",
153 clk_hw_get_name(hw), degrees, delay_num,
154 mmc_clock->reg, raw_value>>(mmc_clock->shift),
155 rockchip_mmc_get_phase(hw)
156 );
157
158 return 0;
159}
160
161static const struct clk_ops rockchip_mmc_clk_ops = {
162 .recalc_rate = rockchip_mmc_recalc,
163 .get_phase = rockchip_mmc_get_phase,
164 .set_phase = rockchip_mmc_set_phase,
165};
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 struct clk_notifier_data *ndata = data;
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 if (ndata->old_rate <= ndata->new_rate)
190 return NOTIFY_DONE;
191
192 if (event == PRE_RATE_CHANGE)
193 mmc_clock->cached_phase =
194 rockchip_mmc_get_phase(&mmc_clock->hw);
195 else if (mmc_clock->cached_phase != -EINVAL &&
196 event == POST_RATE_CHANGE)
197 rockchip_mmc_set_phase(&mmc_clock->hw, mmc_clock->cached_phase);
198
199 return NOTIFY_DONE;
200}
201
202struct clk *rockchip_clk_register_mmc(const char *name,
203 const char *const *parent_names, u8 num_parents,
204 void __iomem *reg, int shift)
205{
206 struct clk_init_data init;
207 struct rockchip_mmc_clock *mmc_clock;
208 struct clk *clk;
209 int ret;
210
211 mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL);
212 if (!mmc_clock)
213 return ERR_PTR(-ENOMEM);
214
215 init.name = name;
216 init.flags = 0;
217 init.num_parents = num_parents;
218 init.parent_names = parent_names;
219 init.ops = &rockchip_mmc_clk_ops;
220
221 mmc_clock->hw.init = &init;
222 mmc_clock->reg = reg;
223 mmc_clock->shift = shift;
224
225 clk = clk_register(NULL, &mmc_clock->hw);
226 if (IS_ERR(clk)) {
227 ret = PTR_ERR(clk);
228 goto err_register;
229 }
230
231 mmc_clock->clk_rate_change_nb.notifier_call =
232 &rockchip_mmc_clk_rate_notify;
233 ret = clk_notifier_register(clk, &mmc_clock->clk_rate_change_nb);
234 if (ret)
235 goto err_notifier;
236
237 return clk;
238err_notifier:
239 clk_unregister(clk);
240err_register:
241 kfree(mmc_clock);
242 return ERR_PTR(ret);
243}
244